<?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: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-3179964835593137794</id><updated>2011-12-30T21:31:24.520+04:00</updated><category term='linux'/><category term='arm'/><category term='QT'/><category term='мысли'/><category term='бесшумный компьютер'/><category term='usb'/><category term='gentoo'/><category term='toolchain'/><category term='C'/><category term='дети'/><category term='boost'/><category term='exherbo'/><category term='assembler'/><category term='memory'/><category term='wtf'/><category term='kde'/><category term='отладка'/><category term='планирование работ'/><category term='test'/><category term='clang'/><category term='ia32'/><category term='рефакторинг'/><category term='VCS'/><category term='agile'/><category term='git'/><category term='python'/><category term='mdf'/><category term='работа'/><category term='ошибки'/><category term='windows'/><category term='gcc'/><category term='tdd'/><category term='идеи'/><category term='mercurial'/><category term='хорошая практика'/><category term='c++'/><category term='usability'/><category term='crypto'/><category term='hardware'/><category term='google'/><category term='subversion'/><title type='text'>Распутывая нити</title><subtitle type='html'>Много загадочного и непонятного скрывает в себе мир вообще и мир программирования в частности.&lt;br&gt; 
Не запутаться бы.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default?start-index=101&amp;max-results=100'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>134</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-2264637177524735750</id><published>2011-10-27T15:22:00.001+04:00</published><updated>2011-10-27T15:22:48.591+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tdd'/><title type='text'>Что-то мне в последнее время не нравится make...</title><content type='html'>Что-то мне начал надоедать make. А так хочется быть гибким, хочется применять всякие новостные методики, но  make мешается. &lt;br /&gt;&lt;br /&gt;В принципе конечно все проблемы разрешаются, но что-то мне не хочется их решать. Да пусть этих Makefile вообще не будет. В каждом каталоге лежат, чтоб им пусто было. Лучшая система сборки та, которой нету.&lt;br /&gt;&lt;br /&gt;Да, я, как всегда, занимаюсь велосипедостроением, но давайте обо всем по порядку.&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Очень хочется применять TDD. Так, чтобы про настоящему, с максимальным покрытием кода. Состояния полного просветления я еще не достиг, и иногда начинаю просто писать код. Но вскоре понимаю, что действую неправильно. Если, ради того, чтобы сошелся тест надо написать еще один классик, то для нового класса тоже нужны тесты. Причем до того, как я начну его реализовывать. Хобби проект очень хорошее место для того, чтобы отточить навыки в TDD и освоить на практике новый стандарт c++.&lt;br /&gt;&lt;br /&gt;Ради тестирования структура проекта выстраивается так, чтобы функция main была бы отдельно и не мешалась, а остальной код можно было бы использовать как с упомянутой выше main, так и в рамках тестового модуля. Классики TDD об этом почему-то не пишут. Может быть потому, что они все работают на java. Но в c ++ иначе никак не получится.&lt;br /&gt;&lt;br /&gt;Итак, весь рабочий код, без main, удобно держать в отдельной папке. При компиляции  эта папка сворачивается в один объектный модуль. Здесь я конечно не говорю про большие проекты из десятков библиотек, там иерархия сборки немного более сложная. Мы будем говорить о проектах, где некоторый набор исходных текстов собирается в один или несколько исполняемых модулей. Исходные тексты могут быть разложены по подкаталогам, это по моему правильно, и не меняет сильно дела. И в итоге получается, что логика сборки весьма проста и прямолинейна.&lt;br /&gt;&lt;br /&gt;Кроме того, это помогает ускорить процесс сборки. Собирать цель из сотен объектных модулей по моему долго. Гораздо оптимальнее поделить модули на группы, каждую группу сворачивать в бандл, а потом просто слинковать несколько получившихся бандлов. Такая система используется, например, в ядре linux. А для TDD есть прямой резон в том, чтобы при сборке минимизировать количество компилируемых/линкуемых файлов. Поскольку в TDD изменения сильно локализованы и незначительны по размеру, а сборки — достаточно часты.&lt;br /&gt;&lt;br /&gt;Короче, нужна максимально быстрая сборка. И make с этим более-менее справляется, хотя к его скорости и есть серьёзные претензии у сообщества.&lt;br /&gt;&lt;br /&gt;Кроме того нужна минимальная пересборка. И с этим make справляется, если прикрутить к нему файлы с зависимостями. &lt;br /&gt;&lt;br /&gt;Но если, в полном соответствии с лучшими практиками, как то рефакторинг, мы начнем переименовывать include файлы, то у нас съезжают зависимости, и мы получаем ошибку сборки. И это происходит не смотря на то, что другие файлы в списках зависимостей претерпели изменения и на самом деле сборка цела. Чтобы преодолеть это, надо обновлять файл зависимости. Честно говоря, не могу придумать, как сделать это выборочно, а полная очистка вызывает полную пересборку, чего мы хотели бы избежать.&lt;br /&gt;&lt;br /&gt;И тут я подумал, что вообще не хочу беспокоится о зависимостях. Даже более того, я готов терпеть чуть более долгий процесс сборки, ради того, чтобы сборка при любых изменениях собиралась корректно и, конечно, в минимальном объеме. &lt;br /&gt;&lt;br /&gt;И тогда я написал скрипт, который умеет превращать каталог в один объектный модуль. Конечно, с учетом всех модификаций и изменений. Этот, очень простой скрипт на питоне можно найти &lt;a href="http://code.google.com/p/paranoid/source/browse/script/build.py"&gt;здесь&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;Его использование дает несколько больших плюсов:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Мне больше не нужны Makefile в подкаталогах. От корневого Makefile отказываться, конечно, не стоит. Но на его плечи ложиться сравнительно небольшая нагрузка, как то свести все воедино, и подчистить за собой.&lt;/li&gt;&lt;li&gt;Зависимости я определяю на лету, думаю что препроцессор отрабатывает сравнительно быстро, и мне нет смысла с этим заморачиваться пока у меня проект не перерос какие-то разумные размеры.&lt;/li&gt;&lt;li&gt;Мне больше нет необходимости наблюдать вывод сборки. Я могу сделать дружественные сообщения, вплоть до прогресса. Это можно было сделать и в Makefile, но там это не так гибко.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Сам про себе скрипт, конечно не универсален, и имеет минусы:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Все исходные тексты, для полноты картины даже main.cpp, необходимо раскладывать по отдельным папочкам. Ведь не для того все это затевалось, чтобы потом некоторые файлы собирать чем-то еще?&lt;/li&gt;&lt;li&gt;Пока он никак не многопоточен. Это большой минус и его можно решить по разному. Можно, например, запускать несколько каталогов паралельно - самое простое. Или можно встроить в скрипт пул компиляторов, но тогда это сильно утяжелит его, думаю в этом нет особой необходимости.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Сейчас он  решает мою конкретную задачу, и этого довольно. Если идея кому-то покажется интересной, я всегда открыт для общения.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-2264637177524735750?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/2264637177524735750/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=2264637177524735750' title='Комментарии: 22'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/2264637177524735750'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/2264637177524735750'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2011/10/make.html' title='Что-то мне в последнее время не нравится make...'/><author><name>Андрей Валяев</name><uri>https://profiles.google.com/105555804149403561366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-f5qQ0O2SMCo/AAAAAAAAAAI/AAAAAAAAAAA/ZQ5xusHVJVU/s512-c/photo.jpg'/></author><thr:total>22</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-2376482167088658222</id><published>2011-09-07T22:58:00.000+04:00</published><updated>2011-09-07T23:00:24.951+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='мысли'/><category scheme='http://www.blogger.com/atom/ns#' term='хорошая практика'/><title type='text'>Если не strcmp...</title><content type='html'>Опять встретилась проблема в коде. Не то, чтобы очень уж страшная проблема, некоторые даже думают что тем самым они наоборот вносят ясность в код. Но я, как обычно, против.&lt;br /&gt;&lt;br /&gt;Давайте посмотрим на следующий код, который я для примера выдрал из ядра linux:&lt;br /&gt;&lt;pre&gt;if (!strncmp(name, p, k) &amp;amp;&amp;amp; p[k] == '=') {&lt;br /&gt; 	p += k + 1;&lt;br /&gt;	...&lt;/pre&gt;&lt;a name='more'&gt;&lt;/a&gt;Вроде бы ничего особенного... Что же мне может не нравится в таком замечательном коде?&lt;br /&gt;&lt;br /&gt;Глядя на этот код, лично я, никак не могу понять каким боком там стоит логическое отрицание? Проблема возникает, когда я пытаюсь этот код прочитать...&lt;br /&gt;&lt;br /&gt;Если не strcmp... тогда кто?&lt;br /&gt;Если strcmp ложно... а в чем собственно заключается истина?&lt;br /&gt;&lt;br /&gt;Проблема в том, что результат функции не логический. Функция возвращает конкретную разницу, число. В спецификации написано открытым текстом, функция возвращает меньше, больше и равно нулю. Почему бы не написать просто: Если результат вызова strcmp равен нулю то...&lt;br /&gt;&lt;pre&gt;if (strcmp(...) == 0) {&lt;br /&gt;	...&lt;/pre&gt;Это не проблема работоспособности кода, это проблема понятности кода. Конечно все программисты знают что делает функция strcmp  и что она возвращает. Но давайте представим на секунду, что мы видим совершенно незнакомую функцию: &lt;code&gt;if (!foobar(...))&lt;/code&gt; Как вы думаете, что проверяет это условие? Кто нибудь может сходу ответить? &lt;br /&gt;&lt;br /&gt;Да, согласен, по окружающему контексту можно судить - насколько 'не фубар' это хорошо... Кроме того, функция могла бы иметь более понятное название. Чтобы понять смысл выражения нужно будет для начала изучить прототип foobar. При непонятном имени придется изучить еще и исходник...&lt;br /&gt;&lt;br /&gt;Но, и самое главное, если правильно ее использовать в условии, можно сразу, не задумываясь ответить на вопрос - что же она возвращает. &lt;code&gt;foobar(...) == '\0'&lt;/code&gt; - Эта функция возвращает char и вероятно наткнулась на символ окончания строки. &lt;code&gt;foobar(...) == nullptr&lt;/code&gt; А эта возвращает нулевой указатель (Мы все знаем, что NULL в C++ - это плохо, а 0 очень похож на int :) ), Если же мы видим сравнение с нулем - это значит что нас интересует именно ноль сам по себе. Как число, как константа.&lt;br /&gt;&lt;br /&gt;Конечно, никому в здравом уме не придет в голову писать &lt;code&gt;if (foobar(...) == false)&lt;/code&gt;... Именно для этого случая существует логическое отрицание. И только в случае логического значения можно не писать явное сравнение.&lt;br /&gt;&lt;br /&gt;По моему в давно пора перестать рассматривать ноль, как false, а не ноль, как true... Это было в прошлом веке.&lt;br /&gt;&lt;br /&gt;Очень часто встречается, например, со стандартными библиотеками си:&lt;br /&gt;&lt;pre&gt;int fd = open(...);&lt;br /&gt;if (fd &amp;gt;= 0)&lt;/pre&gt;Ну какой ноль??? В мане серым по черному написано, что в случае ошибки функция возвращает -1, почему бы не написать условие явно? &lt;br /&gt;&lt;pre&gt;if (fd == -1) {&lt;br /&gt;	error;&lt;/pre&gt;Хотя, может быть это и не самый удачный пример (много этих стандартов в мире юникс, может быть где-то и не -1?).&lt;br /&gt;&lt;br /&gt;Код должен читаться, буквально по английски. Если получается чушь, значит стоит подумать о том, насколько явно вы доносите свои намерения в коде.&lt;br /&gt;&lt;br /&gt;А применяя вместо хитрых трюков типизированные константы, типа '\0', nullptr мы даем читателю подсказки к пониманию кода. С понятными именами у него не должно возникнуть необходимости к тому, чтобы полезть искать прототип, или хуже того - изучать реализацию.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-2376482167088658222?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/2376482167088658222/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=2376482167088658222' title='Комментарии: 5'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/2376482167088658222'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/2376482167088658222'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2011/09/strcmp.html' title='Если не strcmp...'/><author><name>Андрей Валяев</name><uri>https://profiles.google.com/105555804149403561366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-f5qQ0O2SMCo/AAAAAAAAAAI/AAAAAAAAAAA/ZQ5xusHVJVU/s512-c/photo.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-7823212546353871103</id><published>2011-08-30T14:04:00.004+04:00</published><updated>2011-08-30T14:33:08.013+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><title type='text'>Давным давно, в одном редко вызываемом модуле...</title><content type='html'>Нет, все действия происходят в настоящее время. Наткнулся на интересный кусок кода:&lt;br /&gt;&lt;pre&gt;	boost::format value("%s:%s");&lt;br /&gt;	value % head;&lt;br /&gt;&lt;br /&gt;	BOOST_FOREACH(value_type &amp;item, container) {&lt;br /&gt;		if (item.valid()) {&lt;br /&gt;			value % item.value();&lt;br /&gt;		}&lt;br /&gt;	}&lt;br /&gt;&lt;br /&gt;	return 0;&lt;br /&gt;}&lt;/pre&gt;Все совпадения с реальным кодом следует считать совпадениями, конечно я его немного поменял. :)&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Наткнулся потому, что из за него повалились вдруг тесты - мало аргументов для boost::format.&lt;br /&gt;&lt;br /&gt;Долго думал, пока наконец не понял, что этот код совершенно никому не нужен. value, объявленная в начале фрагмента благополучно уничтожается в конце оного. &lt;br /&gt;&lt;br /&gt;Полез в историю, и выяснил, что в мае 2006 году объявление value находилось в другом месте, в начале модуля. И действительно использовалось в другом месте. &lt;br /&gt;&lt;br /&gt;Через два месяца, в июле 2006, код, который использовал это значение был переписан. значение осталось без использования.&lt;br /&gt;&lt;br /&gt;Через месяц определение value было перенесено в начало вышеуказанного фрагмента. В этот момент уже можно было оценить всю бесполезность кода, но почему-то этого не произошло, даже более того...&lt;br /&gt;&lt;br /&gt;В новейшей истории, в этом месяце, код был переписан с использованием BOOST_FOREACH. &lt;br /&gt;&lt;br /&gt;Пока наконец сегодня не сломались тесты, и этот код не был выброшен на свалку истории.&lt;br /&gt;&lt;br /&gt;Забавно, что почти 6 лет совершенно бесполезный код продолжал работать, работать и работать. :) В реальности он немного более наворочанный, возможно это его и спасало все это время.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-7823212546353871103?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/7823212546353871103/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=7823212546353871103' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/7823212546353871103'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/7823212546353871103'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2011/08/blog-post_30.html' title='Давным давно, в одном редко вызываемом модуле...'/><author><name>Андрей Валяев</name><uri>https://profiles.google.com/105555804149403561366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-f5qQ0O2SMCo/AAAAAAAAAAI/AAAAAAAAAAA/ZQ5xusHVJVU/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-4977745509175796650</id><published>2011-08-16T18:33:00.003+04:00</published><updated>2011-08-16T18:57:50.324+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='хорошая практика'/><title type='text'>Семь раз отмерь...</title><content type='html'>Интересно, откуда пошла поговорка? Но речь не об этом.&lt;br /&gt;&lt;br /&gt;Если жить в соответствии с дао, я имею ввиду TDD и рефакторинг, то методы надо делать меньше. Как сказал Роберт Мартин - 'нет, методы надо делать еще меньше'. И классы в соответствии с SRP надо делать меньше.&lt;br /&gt;&lt;br /&gt;Я никогда не встречал проектов, которые бы разрабатывались в полном соответствии с этой концепцией, но чувствую проблемы. Проблемы заключаются в том, что количество таких объектов может уйти далеко за рамки 7+-2, которые человек в состоянии эффективно анализировать.&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Разрастание количества классов может привести к плохо обозримой кодовой базе, в следствии чего увеличится дублирование кода. Что же делать?&lt;br /&gt;&lt;br /&gt;Очень просто - необходимо распространять принцип 7+-2 дальше. не более 7+-2 классов в модуле, не более 7+-2 модулей в компоненте, не более 7+-2 компонентов в приложении. Это даст хорошую локализацию функционала, но опять таки может привести к дублированию, потому что усложняется расшаривание общего кода. Что же делать?&lt;br /&gt;&lt;br /&gt;Общий код (тоже 7+-2 :) ) нужно выносить в библиотеки... &lt;br /&gt;&lt;br /&gt;И осталось только все это аккуратно и гармонично расположить по каталогам проекта. В древовидном виде, конечно.&lt;br /&gt;&lt;br /&gt;Собственно к цифре 7+-2 надо относится прагматично. Не стоит на каждый чих вести отсчет. Достаточно подсчитывать определяющие поведение классы, методы или что похуже. Утилитарные однострочники не достойны считаться полноценными классами.&lt;br /&gt;&lt;br /&gt;Очень кстати удобно сделано в linux kernel - каждый подкаталог в нем сворачивается в объектный бандл, один объектный файл, который объединяет в себе все скомпилированное содержимое каталога.&lt;br /&gt;&lt;br /&gt;А сколько классов/файлов в одном каталоге живет у вас?&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-4977745509175796650?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/4977745509175796650/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=4977745509175796650' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/4977745509175796650'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/4977745509175796650'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2011/08/blog-post_16.html' title='Семь раз отмерь...'/><author><name>Андрей Валяев</name><uri>https://profiles.google.com/105555804149403561366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-f5qQ0O2SMCo/AAAAAAAAAAI/AAAAAAAAAAA/ZQ5xusHVJVU/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-2806282659559929694</id><published>2011-08-05T11:08:00.004+04:00</published><updated>2011-08-05T12:00:34.567+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='wtf'/><title type='text'>Использование исключений</title><content type='html'>Я очень люблю исключения. Но в последнее время я начал понимать тех, кто в своих стандартах кодирования запрещает исключения. Просто поразительно насколько часто, даже грамотные люди не могут оценить исключительность ситуации..&lt;br /&gt;&lt;br /&gt;Исключения надо применять исключительно в исключительных ситуациях. Тогда, когда ты не можешь даже предугадать как обработать ту или иную ситуацию. И даже тогда надо десять раз подумать - а нет ли способа проще. может быть просто вернуть пустое значение, которое удовлетворит вышестоящие уровни? Это будет реально проще, чем бросать исключения.&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Теперь давайте я приведу несколько примеров, которые меня бесят. Все совпадения с реальным кодом - реальны, имена только изменены, и код немного подчищен...&lt;br /&gt;&lt;pre&gt;type Client::receive()&lt;br /&gt;{&lt;br /&gt; struct special_case { };&lt;br /&gt; type data;&lt;br /&gt;&lt;br /&gt; try {&lt;br /&gt;  if (...) {&lt;br /&gt;   throw runtime_error("...");&lt;br /&gt;  }&lt;br /&gt;  ... skipped many throws ...&lt;br /&gt;  if (...) {&lt;br /&gt;   throw special_case();&lt;br /&gt;  }&lt;br /&gt; } catch (exception &amp;) {&lt;br /&gt;  data = type();&lt;br /&gt; } catch (special_case &amp;) {&lt;br /&gt;  throw runtime_error("...");&lt;br /&gt; }&lt;br /&gt; return data;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;В данном случае мы видим реализацию переходов на базе исключений. Я не вижу в этих ситуациях ничего исключительного, и более того. В этой функции мы прекрасно представляем, что собираемся с этим сделать.&lt;br /&gt;&lt;br /&gt;Очень костыльно выглядит особый случай, который вполне легко решается одним throw, когда мы убираем все "goto"...&lt;br /&gt;&lt;pre&gt;string Informer::get()&lt;br /&gt;{&lt;br /&gt; int sock = socket(AF_UNIX, SOCK_STREAM, 0);&lt;br /&gt; if (sock &amp;lt; 0) { &lt;br /&gt;  throw runtime_error("...");&lt;br /&gt; }&lt;br /&gt; ... skip more code with throws ...&lt;/pre&gt;&lt;br /&gt;Конечно, мы же на C++ пишем, зачем мы будем связываться с кодами ошибок и тд... &lt;br /&gt;С кодами ошибок связываться нет необходимости, проблема не в этом. Проблема в том, что функция приватная. В публичной функции мы видим следующее:&lt;br /&gt;&lt;pre&gt;try {&lt;br /&gt; string r = get(components[i].comp);&lt;br /&gt; ... do something ...&lt;br /&gt;} catch (const runtime_error &amp;e) {&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;То есть в рамках класса мы опять таки прекрасно знаем, что будем делать в том случае, если возникнет исключение. Так давайте уберем исключение и сразу сделаем то, что хотим? Например вернем пустую строку.&lt;br /&gt;&lt;br /&gt;Следующий пример больше не по генерации, а по перехвату исключений. Так уж сложилось, что наш интерфейс базы данных бросает исключения, если выборка пуста. С этим ничего не поделаешь, приходится мириться, хотя много кода, похожего на этот:&lt;br /&gt;&lt;pre&gt;try {&lt;br /&gt; scoped_ptr&amp;lt;Set&gt; cursor(db-&gt;all_records());&lt;br /&gt; ... do something ...&lt;br /&gt;} catch (EmptySet &amp;) {&lt;br /&gt; // ничего не надо делать&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Костыльно конечно, но что делать..&lt;br /&gt;И тут я увидел это:&lt;br /&gt;&lt;pre&gt;void convert_records(shared_ptr&amp;lt;RecordSet&gt; &amp;in, list&lt;Record&gt; &amp;records) {&lt;br /&gt; do {&lt;br /&gt;  try {&lt;br /&gt;   shared_ptr&amp;lt;RecordSet&gt; cur_rec((*in)-&gt;get_records());&lt;br /&gt;   convert_records(cur_rec, records);&lt;br /&gt;  } catch (EmptySet) {&lt;br /&gt;   Record rec;&lt;br /&gt;   convert_record(**in, rec);&lt;br /&gt;   records.push_back(rec);&lt;br /&gt;  }&lt;br /&gt; } while (!in-&gt;next()); &lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Смысл в том, что там добавилась древовидность записей, одна запись получила возможность ссылаться на другие. И записи отныне делятся на листовые и групповые.&lt;br /&gt;&lt;br /&gt;Я сперва не мог сообразить, почему две одинаковые функции используют совершенно разные параметры, буква s в конце имени функции очень плохо видна.. а за такую перегрузку - вообще бы убил.&lt;br /&gt;&lt;br /&gt;Пришлось трясти автора, и тогда я узнал всю страшную правду. Эта функция вызывается для корневых элементов, и каждый элемент пытается проходить вглубь. Для негрупповых элементов происходит исключение, где, в ветке catch, и происходит натуральная работа - наполнение списка записей...&lt;br /&gt;&lt;br /&gt;Условие нельзя было поставить? чтобы одним легким движением вообще отказаться от исключений в этом месте? Исключительность ошибок - я еще могу оправдать. Но здесь через catch проходит основная логика программы, основная ветвь выполнения.&lt;br /&gt;&lt;br /&gt;Вот после этого я и подумал - наверное в Google все таки не дураки сидят, что запретили исключения?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-2806282659559929694?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/2806282659559929694/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=2806282659559929694' title='Комментарии: 8'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/2806282659559929694'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/2806282659559929694'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2011/08/blog-post.html' title='Использование исключений'/><author><name>Андрей Валяев</name><uri>https://profiles.google.com/105555804149403561366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-f5qQ0O2SMCo/AAAAAAAAAAI/AAAAAAAAAAA/ZQ5xusHVJVU/s512-c/photo.jpg'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-5496512304428656141</id><published>2011-05-31T10:28:00.003+04:00</published><updated>2011-05-31T11:28:13.603+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><title type='text'>fastdb query</title><content type='html'>Существует такая библиотека, &lt;a href="http://www.garret.ru/fastdb.html"&gt;fastdb&lt;/a&gt;. Это объектная in-memory база данных. Мы используем ее в своем проекте, чтобы хранить конфигурацию сервера. Администратор вносит изменения в конфигурацию, при этом программа управления - весьма тонкий клиент, не обладающей собственной логикой. Вся логика находится на сервере, который должен проверить, что то, что сделал администратор не противоречит функционированию системы в целом.&lt;br /&gt;&lt;br /&gt;Для проверки в основном использовались dbQuery. Мне всегда казалось это неудобным, поскольку в Query не так то просто подсунуть программные константы. Кроме того мучили сомнения относительно эффективности данного подхода, которые и сподвигли меня на измерение производительности.&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Запросов достаточно много, на каждый случай - свой. Причем каждый запрос характеризует невозможную ситуацию, если какой нибудь объект удовлетворяет критериям запроса - это фейл. Основной вопрос - насколько dbQuery быстрее циклического перебора полной выборки. Особенно учитывая, что в одном цикле можно проверить несколько кейсов. Но давайте по порядку.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Надо сказать что я не сильно заморачивался и тестирование получилось достаточно поверхностное.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Для измерения была создана тестовая база с миллионом достататочно простых структурок.&lt;br /&gt;&lt;pre&gt;struct dbItem {&lt;br /&gt; db_nat4 id;&lt;br /&gt; db_nat4 type;&lt;br /&gt; const char *name;&lt;br /&gt; TYPE_DESCRIPTOR((KEY(id, AUTOINCREMENT|INDEXED), FIELD(type), FIELD(name)));&lt;br /&gt;};&lt;/pre&gt;Строковой параметр ввел специально, чтобы поднапрячь движок. Все поля, кроме id, который AUTOINCREMENT, заполнил случайным образом. Общий размер базы данных составил гигабайт. Нетипично большая база, но думаю, она более показательна для наших измерений.&lt;br /&gt;&lt;br /&gt;Вообще dbQuery достаточно тяжелый объект, поскольку он должен интерпретировать запрос, который в него передается. Внутри он хранит оптимизированное представление. Если запрос сам по себе достаточно неизменен, имеет смысл использовать ключевое слово static. Но на выборке в миллион элементов эффект от статичности dbQuery совершенно нивелируется.&lt;br /&gt;&lt;br /&gt;На моей выборке один select выполняется примерно 130мс. Но только в том случае, если в запросе используется неиндексированное поле. Если же поле используется индексированное, то время выборки сокращается до 500нс! Такая же скорость наблюдается при использовании selectByKey. Для сравнения я провел аналогичные замеры для map - он справился с поиском за 100нс.&lt;br /&gt;&lt;br /&gt;Индексированные поля показывают выдающиеся результаты, но к сожалению наши выборки строятся на разных полях. Все же поля не станешь делать индексированными! И не стоит забывать о цели нашего тестирования. Нам ведь хотелось сравнить запросы с простым перебором. &lt;br /&gt;&lt;br /&gt;А простой перебор без запросов справился с этим делом за 80мс. Что на ~30% быстрее, чем аналогичный query. При этом, если мы будем в простой перебор добавлять дополнительные условия, это не будет нам стоить практически ничего. В то время как каждый новый dbQuery стоит 130мс...&lt;br /&gt;&lt;br /&gt;Для сравнения - поиск по такой же выборке, загруженной в list, занимает 9мс. Загруженной в vector - 2мс...&lt;br /&gt;&lt;br /&gt;Резюмируя можно сказать, что dbQuery позволят вам получить значительный выигрыш, если вы грамотно используете в запросах индексированные поля. В противном случае простой перебор окажется быстрее. Но с другой стороны dbQuery кому-то могут показаться более наглядными, если скорость не критична.&lt;br /&gt;&lt;br /&gt;Кроме того интересовал вопрос - стоит ли кешировать значения из БД в памяти? Если доступ к элементам БД осуществляется через индексированное поле - кешировать однозначно не нужно, по моему это только усложняет код, и все из за жалких 400 наносекунд. :)&lt;br /&gt;&lt;br /&gt;Теперь можно убрать нафиг эти dbQuery, и мы получим возможность абстрагироваться от БД в плане проверок.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-5496512304428656141?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/5496512304428656141/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=5496512304428656141' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/5496512304428656141'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/5496512304428656141'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2011/05/fastdb-query.html' title='fastdb query'/><author><name>Андрей Валяев</name><uri>https://profiles.google.com/105555804149403561366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-f5qQ0O2SMCo/AAAAAAAAAAI/AAAAAAAAAAA/ZQ5xusHVJVU/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-2569180008502898182</id><published>2011-04-27T16:32:00.003+04:00</published><updated>2011-04-27T17:00:03.287+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><title type='text'>Эволюционный Agile</title><content type='html'>Когда внедряют SCRUM, часто применяют все классические практики сразу. Так было и у нас. Мы практиковали непонятно что, потом приехали ребята из &lt;a href="http://scrumtrek.ru/"&gt;ScrumTrek&lt;/a&gt;, научили нас жить по новому.&lt;br /&gt;&lt;br /&gt;Сейчас прошло больше года. Наш процесс уже нельзя назвать скрамом. Мы не рисуем Burndown, мы не оцениваем время. Мы нашли что-то свое. Новые люди говорят, что у нас не очень плохо получается.&lt;br /&gt;&lt;br /&gt;Мы от SCRUM пришли к удобному для себя формату и это является генеральной линией гибкости. Все так делают. И возникла мысль - а почему ту же гибкость мы не используем при внедрении Agile?&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Конечно для начала необходима личная заинтересованность - вовлеченность. Все должны хотеть жить лучше и понимать что это возможно.&lt;br /&gt;&lt;br /&gt;Начинать необходимо с какой нибудь одной практики. Думаю что хорошим вариантом будет ретроспектива. Начинаем собираться всей командой к примеру раз в неделю и дружно думать о том - что мы можем улучшить в нашем процессе.&lt;br /&gt;&lt;br /&gt;Под улучшением можно подразумевать внедрение какой нибудь новой практики, либо какие-то организационные меры. Если речь идет о практиках - мы не заморачиваемся на SCRUM. Мы просто выбираем тот вариант, который нас устраивает.&lt;br /&gt;&lt;br /&gt;Например - нужны ли нам итерации? Итерация предполагает приращение продукта, то есть очередной выпуск. Или нам удобнее демонстрировать фичи по готовности? Бывает разная специфика. Бывает что один эпик длится два месяца, а оставшиеся фичи мы быстро подбираем за пару недель. Бывает даже так, что пока делается какая-то длительная работа - нечего показывать.&lt;br /&gt;&lt;br /&gt;Так же под вопросом таскборд. Некоторые команды обходятся без него. В принципе можно и на уровне багтрекинга (даже самого отсталого) построить гибкую систему.&lt;br /&gt;&lt;br /&gt;Нужны ли стендап митинги? спорный вопрос. Зависит от интенсивности разработки. Их можно проводить например пару раз в неделю.&lt;br /&gt;&lt;br /&gt;И мы не пытаемся построить новый мир сразу (внедрение SCRUM), чтобы разрушать его потом, а сразу ищем для себя лучший путь.&lt;br /&gt;&lt;br /&gt;Смущает во всем этом только то, что если команда и так гибкая и понимает куда следует двигаться дальше - то вряд ли им придется начинать с нуля. :) Хотя под руководством это наверное возможно и для непосвящённой команды.&lt;br /&gt;&lt;br /&gt;У нас сейчас прижилась схема с месячными итерациями и недельными спринтами. Демонстрация у нас проводится в конце итерации, то есть раз в месяц. Фокусфакторами мы тоже не страдаем.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-2569180008502898182?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/2569180008502898182/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=2569180008502898182' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/2569180008502898182'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/2569180008502898182'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2011/04/agile.html' title='Эволюционный Agile'/><author><name>Андрей Валяев</name><uri>https://profiles.google.com/105555804149403561366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-f5qQ0O2SMCo/AAAAAAAAAAI/AAAAAAAAAAA/ZQ5xusHVJVU/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-2584189194935821185</id><published>2011-04-12T17:11:00.002+04:00</published><updated>2011-04-12T17:35:43.018+04:00</updated><title type='text'>mbuf overrun</title><content type='html'>Наткнулся на интересную проблему... &lt;br /&gt;&lt;br /&gt;Не буду винить команду FreeBSD, как я люблю, ибо в стандартной комплектации FreeBSD-6 вообще не поддерживает данный адаптер. Нам, для поддержки необходимого оборудования пришлось взять самый последний драйвер от Intel. Драйвер изначально ориентирован на FreeBSD-7, но нам удалось прикрутить его к шестерке. Оригинальные драйвера от Intel используются во FreeBSD практически без изменений. Только фря старая, и драйвер седьмой версии в нее не втащить. До сего дня использовался 6.9.12&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Но это все была присказка, приоткрывающая завесу тайны. Началось все с того, что на новой платформе версия продукта начала падать...&lt;br /&gt;&lt;br /&gt;Наших менеджеров хлебом не корми, дай что нибудь продать. А продукт у нас аппаратно-программный. И для продаж последней версии закупили новую платформу. Очень новую... для FreeBSD 6.3 просто невозможно новую... Но драйвер em из семерки мы втащили в ядро раньше. Надо сказать семерка, в своих ранних проявлениях, не сильно отличается от шестерки.&lt;br /&gt;&lt;br /&gt;Все имеющиеся платформы оттестировали вдоль и поперек, но на новой продукт почему-то стал падать при прохождении трафика. И мало того, Из за него начали падать соседние шлюзы, которые раньше прекрасно работали.&lt;br /&gt;&lt;br /&gt;Почти неделя прошла в медитациях.&lt;br /&gt;&lt;br /&gt;Сперва, как обычно, грешил на невыясненные глюки в коде, даже работающее решение предоставил, где ничего не падает и почти полное счастье. Но истинная причина оставалась неизвестной.&lt;br /&gt;&lt;br /&gt;Потом выяснилось, что в пакете, пока он находится в очереди на шифрование, не просто портится длина, а весь пакет чудесным образом заменяется на другой. А FreeBSD ведет себя хитро, чтобы работать с пакетом в заголовке пакета длину меняют на host order. Представляете себе удивление ip_fragment, когда он пытался фрагментировать пакет у которого длинна оказалась в некорректном (сетевом) порядке байт.&lt;br /&gt;&lt;br /&gt;Причина падения ясна - а вот причина чудесной подмены пакетов - нет. Собственно лечить FreeBSD - не входило в мои планы. В таких случаях я обычно начинаю читать svn.freebsd.org... Но сейчас это не помогло. В шестерке драйвер значительно старее нашего, а в семерке - уже значительно новее. &lt;br /&gt;&lt;br /&gt;Нашелся новый драйвер от Intel (6.9.21), который решил проблему окончательно, подмены пакетов прекратились.&lt;br /&gt;&lt;br /&gt;Не знаю какая мораль из всего этого. Обновление драйверов спасает нас почти при любых проблемах с новым железом. Но с каждым новым железом сделать это все труднее, FreeBSD-6 уже не развивается. Как мы дальше будем ее поддерживать? - не знаю...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-2584189194935821185?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/2584189194935821185/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=2584189194935821185' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/2584189194935821185'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/2584189194935821185'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2011/04/mbuf-overrun.html' title='mbuf overrun'/><author><name>Андрей Валяев</name><uri>https://profiles.google.com/105555804149403561366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-f5qQ0O2SMCo/AAAAAAAAAAI/AAAAAAAAAAA/ZQ5xusHVJVU/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-4553607838859049064</id><published>2011-04-05T00:28:00.005+04:00</published><updated>2011-04-05T01:03:15.775+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='мысли'/><category scheme='http://www.blogger.com/atom/ns#' term='VCS'/><title type='text'>Понять ветвления</title><content type='html'>Централизованные системы контроля приучили нас к единому репозиторию. Ветвления осуществляются между каталогами, или депотами, как их не назови. Ну CVS мы за систему контроля (поддерживающую ветвления) вообще не считаем. Во всех остальных, насколько я знаю - деревья.&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Вообще любой подход имеет как плюсы, так и минусы. svn хорошо, пока не захочешь посмотреть историю по ветке... В которой обычно можно наблюдать только последствия мерджей (MFC, MFC, MFC, MFC) - реальная природа изменений похоронена в транке.&lt;br /&gt;&lt;br /&gt;Децентрализованные системы сливают весь чейнджсет, и мы можем видеть историю, не зависимо от того, в какой ветке находимся, это плюс. &lt;br /&gt;&lt;br /&gt;Но я, почему-то, думал что одной центральной базы хватит всем. Нет! Природа децентрализованных систем такова, что каждая ветка, до слияния, живет в своей базе. Коммиты, попавшие в базу никуда не исчезают. И если вдруг есть вероятность, что данная ветка может не понадобиться, ее нельзя пушить в центральную базу, она там не нужна. Можно хранить ее на сервере, но только в отдельной базе.&lt;br /&gt;&lt;br /&gt;Так же, традиционный воркфлов, вероятно, подразумевает многочисленные локальные клонирования. Вытянул у Пети, посмотрел, вытянул у Васи, посмотрел - в любом случае нужна отдельная база, куда втягиваются неподтвержденные изменения.&lt;br /&gt;&lt;br /&gt;Есть возможности публиковать только часть изменений - git публикует текущую ветку, mercurial'у можно указать что публиковать (со всеми парентами). При этом mercurial выталкивает на сервер все родительские коммиты. Сделал локальное слияние - все уйдет на сервер.&lt;br /&gt;&lt;br /&gt;Создать временный бранч - тоже не получается. Mercurial будет грязно ругаться, если ты не предполагаешь публиковать его на сервере. Получается, что именованные бранчи локально не работают. Для этих целей базу надо клонировать.&lt;br /&gt;&lt;br /&gt;Думал, что можно выбрать в качестве альтернативы для текущей, централизованной системы? Mercurial вероятно наиболее подходящий кандидат. Во первых в базе Меркуриала есть номера ревизий. Пускай в каждой клонированной базе и свои, главное, что на сервере они неизменны. Я могу применять их в сборках и при этом сборки однозначно будут идентифицироваться с соответствующим коммитом. Этим свойством обладают почти все централизованные, и отсутствие этого служит препятствием к переходу. git или bazar не обладают такой упорядоченностью и компактностью (одна цифра) версий.&lt;br /&gt;&lt;br /&gt;В остальном системы, по моему, идентичны. В bazar вообще нет локальных ветвлений, но как написано выше, они и в mercurial не особо помогают.&lt;br /&gt;&lt;br /&gt;Надо сказать, что у меня не большой опыт работы с DVCS. Чтобы полноценно это осознать - нужно поработать в распределенной команде. Я только учусь. Возможно я и до сих пор в чем-то ошибаюсь.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-4553607838859049064?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/4553607838859049064/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=4553607838859049064' title='Комментарии: 10'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/4553607838859049064'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/4553607838859049064'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2011/04/blog-post.html' title='Понять ветвления'/><author><name>Андрей Валяев</name><uri>https://profiles.google.com/105555804149403561366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-f5qQ0O2SMCo/AAAAAAAAAAI/AAAAAAAAAAA/ZQ5xusHVJVU/s512-c/photo.jpg'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-3692421080486875021</id><published>2011-03-25T21:08:00.002+03:00</published><updated>2011-03-25T22:12:41.264+03:00</updated><title type='text'>Own build system</title><content type='html'>Наш проект издавна был прикручен к BSD build system. Это набор скриптов, которые располагаются в /usr/share/mk и BSD make с ними. Что-то я от них устал. Они совершенно не подходят для гибкой разработки.&lt;br /&gt;&lt;br /&gt;Например, если попытаться практиковать TDD - для качественной сборки необходимо будет всегда делать make depend, иначе изменения в инклюдах не будут отслеживаться. И один раз сделать make depend - совершенно недостаточно. Всегда надо забивать себе голову мыслями о том, не изменил ли я в коде что-то, что могло повлиять на зависимости... &lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;С другой стороны избыточный синтаксис мейкфайлов. Не достаточно указать библиотеку в LDADD, мне необходимо добавить ее в DPADD, чтобы изменение этой библиотеки так же корректно приводило к пересборке. Явное дублирование.&lt;br /&gt;&lt;br /&gt;Следование соглашениям BSD вынуждает все файлы инсталлировать. Нам нет необходимости их инсталлировать, потому что из них еще надлежит собрать архивы и образы для инсталляции.&lt;br /&gt;&lt;br /&gt;И самое неудобное, что при смене какой-нибудь опции компилятора все надо сперва очистить make clean, make cleandir два раза, а то все не сотрет, make obj не забыть а то objdir не заюзает, собрать все. Не забыть потом сделать make depend, если есть планы пересобирать далее, который без собранных компонентов предварительно не проработает. Вроде ничего не забыл... Это же жесть...&lt;br /&gt;&lt;br /&gt;Всякие наворочанные системы сборки тащить в проект особо не хочется, лучше всего обходиться стандартными FreeBSD-шными средствами.&lt;br /&gt;&lt;br /&gt;Пораскинув мозгами пришел к выводу, что многие из вышеуказанных проблем можно легко обойти выбросив нафиг BSD build system и написав свои собственные мейкфайлы.&lt;br /&gt;&lt;br /&gt;Для начала нужно явно указывать временный каталог и каталог с результатами сборки. Это позволит переключаться между несколькими альтернативными сборками, которые могут различаться используемыми компиляторами или опциями. Кроме того позволит не замусоривать промежуточными файлами дерево исходных текстов, которое кроме того доступно на моей сборочной машине по NFS. С другой стороны желающие могут временный каталог разместить рядом - нет никаких проблем.&lt;br /&gt;&lt;br /&gt;Шаг номер два я подсмотрел в &lt;a href="http://martine.github.com/ninja/manual.html"&gt;ninja&lt;/a&gt;. Зависимости там вычисляются паралельно со сборкой файла (для каждого объектного модуля свои). Это достаточно легко делается через -MMD -MF depfile. И действительно, если объектного модуля нету, то и зависимости никому не нужны. А после первой компиляции зависимости появляются и заставляют файл пересобираться автоматически самообновляясь.&lt;br /&gt;&lt;br /&gt;С третей задачей я серьезно застрял. Два дня думал. Очень хотелось, чтобы при смене компилятора или опций все что необходимо пересобиралось само, без дурацких make clean. Основная идея в том, что версия компилятора и флаги сгружаются в файл, который сравнивается с таким же файлом, сохраненным для каждого объектного модуля. Проблема в том, что файл образец создается безусловно и все модульный флаги считаются out-of-date. В результате остановился на следующей схеме: файл образец для каждого компонента свой. И когда мы его формируем - сперва создаем временную копию. Если временная версия не соответствует образцу (через diff), то она заменяет образец и все модульные флаги оутдатятся, утягивая за собой и объектные модули.&lt;br /&gt;&lt;br /&gt;Лишнее все из компонентных мейкфайлов выкинул. В каждом компоненте указывается только цель (TARGET), список исходников (SOURCES) и включается специальный инклюд верхнего уровня. Который по TARGET легко определяет как ее собирать - как библиотеку или как бинарник. BSD использовала для этого разные переменные и разные mk инклюды. Для бинарников предусмотрено указание линкуемых библиотек. И в любом случае можно прописать индивидуальные опции компиляции/линкования, если в этом есть нужда.&lt;br /&gt;&lt;br /&gt;Отдельно подумал о юниттестах. При написании тестов лучше избегать всяких рутинных операций, и я решил что даже Makefile в тестах будет лишним. Просто каталог с набором файлов, файлы начинающиеся со слова test обнаруживаются автоматически, линкуются в тестраннер и запускаются. Если нужно отключить тест - его можно просто переименовать. Помоему будет очень удобно. Можно будет специально поработать над скоростью компиляции, чтобы работа в стиле TDD проходила быстрее.&lt;br /&gt;&lt;br /&gt;Порадовало ядро FreeBSD. Раньше оно чихало на OBJDIR и собиралось в недрах sys/i386/compile/CONFIG. Но оказалось что эту папку легко можно переназначить в TEMPDIR. Концепция чистых исходников сохраняется. Кроме того я подумал, что одно из трех собираемых ядер явно лишнее. Релизное ядро вполне подходит и для инсталлятора и нам незачем тратить время на сборку инсталляционного.&lt;br /&gt;&lt;br /&gt;И судя по всему сборка будет проходить значительно быстрее. Работа пока еще не закончена. Наверное на следующей неделе смогу собрать весь проект - поглядим.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-3692421080486875021?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/3692421080486875021/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=3692421080486875021' title='Комментарии: 9'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/3692421080486875021'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/3692421080486875021'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2011/03/own-build-system.html' title='Own build system'/><author><name>Андрей Валяев</name><uri>https://profiles.google.com/105555804149403561366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-f5qQ0O2SMCo/AAAAAAAAAAI/AAAAAAAAAAA/ZQ5xusHVJVU/s512-c/photo.jpg'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-9133142652960566876</id><published>2011-02-25T09:42:00.003+03:00</published><updated>2011-02-25T10:38:35.368+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='boost'/><title type='text'>boost::serialization hell</title><content type='html'>&lt;div style="text-align: left;"&gt;Никогда не используйте boost::serialize! Никогда...&lt;/div&gt;&lt;br /&gt;Ну нельзя так работать, ну честное слово! Или может быть у них какие колебания в проекте, нехорошие? Не знаю...&lt;br /&gt;&lt;br /&gt;Мы используем сериализацию...&lt;br /&gt;&lt;div style="text-align: right;"&gt;&lt;i&gt;"Мыши плакали, кололись, но продолжали есть кактус!.."&lt;/i&gt;&lt;/div&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Самая большая проблема boost::serialize - это отсутствие совместимости на понижение. Мы &lt;span style="font-weight:bold;"&gt;не можем&lt;/span&gt; сформировать архив старой версии. И если вы вдруг задумаете строить клиент-серверную архитектуру на основе boost::serialization - одумайтесь.&lt;br /&gt;&lt;br /&gt;Мы сидели на boost-1.35.0 достаточно долго, потом поняли, что продолжаться так больше не может и создали отдельный вариант boost::serialization, для старых версий. Для новых клиентов архивируем по новому, для старых по старому. Но новая версия попадет в ту же ловушку, как только выйдет. Нам придется иметь три, или четыре версии сериализации для совместимости.&lt;br /&gt;&lt;br /&gt;Вообще с совместимостью в boost::serialization плохо. Обновились до 1.45.0 - система не работает. Стали выяснять почему - что-то разъехалось с темплейтами. Сериализация пользовательских структур обрабатывается некорректно.&lt;br /&gt;&lt;br /&gt;Но тут, неожиданно вышла версия 1.46. В общем списке изменений которой вообще не написано что что-то менялось в данной либе. Но в списке изменений самой либы написано - что версии 1.42,1.43,1.44 содержали ошибку, и отныне считаются некошерными. Вплоть до того что архивы указанных версий не прочитаются на текущей. Это же жесть! Тестировать то не пробовал его никто?&lt;br /&gt;&lt;br /&gt;У нас пока все заработало. Но что делать дальше - не понятно. Надо бы уходит от этой сериализации в сторону какого нибудь google protocol. Но не все так просто. Для начала нужно в достаточной степени развязать все в исходных текстах, чтобы новые версии не зависели от старых. Пока там все очень сильно перемешано.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-9133142652960566876?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/9133142652960566876/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=9133142652960566876' title='Комментарии: 17'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/9133142652960566876'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/9133142652960566876'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2011/02/boostserialization-hell.html' title='boost::serialization hell'/><author><name>Андрей Валяев</name><uri>https://profiles.google.com/105555804149403561366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-f5qQ0O2SMCo/AAAAAAAAAAI/AAAAAAAAAAA/ZQ5xusHVJVU/s512-c/photo.jpg'/></author><thr:total>17</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-4722857449822615308</id><published>2011-02-10T00:13:00.003+03:00</published><updated>2011-02-10T00:44:12.808+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='usability'/><title type='text'>Относительность и поиск</title><content type='html'>Иногда появляются мысли, достаточно далекие от программирования. Что с этим поделать?&lt;br /&gt;&lt;br /&gt;Последнее время я стал совершенно невыносим. Я стал задавать очень много вопросов. Мне очень многое непонятно. Мне непонятно например зачем мы собираемся тащить в проект возможности, которые совершенно никому не нужны, не только нашим пользователям, но даже в рекламных проспектах от этого не холодно не горячо. Но нам зачем-то надо... Зачем???&lt;br /&gt;&lt;br /&gt;В жизни у меня возникает масса всяческих вопросов. Может быть дети на меня так влияют?&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Вот например недавно, заказывая в озоне книги, подумал... Почему бы озону и другим интернет магазинам не размещать на фотографиях что-то, что позволило бы реально оценить размер того, что ты покупаешь?&lt;br /&gt;&lt;br /&gt;Да, озон конечно пишет размеры. Но кто смотрит на эти цифры? Кому они о чем-то говорят? Чтобы оценить размеры по цифрам надо взять линейку соответствующего размера и отмерять... Почему бы не разместить что-то, размер которого известен всем?&lt;br /&gt;&lt;br /&gt;Нет, я пока не придумал что это могло бы быть... спичечный коробок слишком мал для того, что продает озон. Можно например контуром обозначать лист А4. Он с одной стороны не будет загораживать обложку книжки, с другой стороны почти все знают его размер. А то покупаешь книгу... а она вдруг оказывается размером А3, йолки, Куда ее пихать то?&lt;br /&gt;&lt;br /&gt;В другой раз поймал себя на том, что пытался в консоли набрать Ctrl-F, хотелось что-то найти, а не скроллить ее в поисках нужного текста. В yakuake дело было, не работает. Хотя не понятно почему? Вроде бы есть портянка текста, почему бы не сделать по ней поиск?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-4722857449822615308?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/4722857449822615308/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=4722857449822615308' title='Комментарии: 6'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/4722857449822615308'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/4722857449822615308'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2011/02/blog-post.html' title='Относительность и поиск'/><author><name>Андрей Валяев</name><uri>https://profiles.google.com/105555804149403561366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-f5qQ0O2SMCo/AAAAAAAAAAI/AAAAAAAAAAA/ZQ5xusHVJVU/s512-c/photo.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-4763539605465557985</id><published>2011-02-08T10:51:00.003+03:00</published><updated>2011-02-08T11:34:41.212+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='хорошая практика'/><category scheme='http://www.blogger.com/atom/ns#' term='VCS'/><title type='text'>Триггеры perforce</title><content type='html'>Наша разработка ведется очень демократично. Мы пишем под FreeBSD (исторически и лицензионно сложилось), используем кодировку koi8-r (тоже исторически сложилось, FreeBSD не очень то дружит с UTF-8 и по сей день).&lt;br /&gt;&lt;br /&gt;Но в то же время мы не навязываем разработчикам никаких условий... Каждый работает так, как ему комфортнее. Жить под FreeBSD - я не пожелаю и врагу (ну вы уже знаете, как я ее не люблю :) ). Наши разработчики пользуются своими любимыми редакторами, сидят в своих любимых системах с разными локалями и интерпретациями концов строк.&lt;br /&gt;&lt;br /&gt;На этой почве достаточно хорошо вырастаюст всякие проблемы с кодировками, которые по неосторожности могут легко попасть в репозиторий. Начитавшись прогрессивной литературы с этого аспекта я и решил начать некоторую автоматизацию контроля исходных текстов.&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;В perforce используются типы файлов, с помощью которых можно задавать отчасти кодировку, расстановку тегов и формат файлов. Тип unicode, в частности, позволяет каждому клиенту предоставлять текст в той кодировке, которую тот использует. Что крайне неудобно, если хочется везде иметь koi8-r. &lt;br /&gt;&lt;br /&gt;Поэтому список типов файлов волевым решением был жестко ограничен следующими типами: binary, text, symlink. Для воплощения этого в perforce используются триггеры.&lt;br /&gt;&lt;pre&gt;#!/bin/sh&lt;br /&gt;REV=$1&lt;br /&gt;lsfiles()&lt;br /&gt;{&lt;br /&gt;        p4 files //depot/...@=$1 | grep -v '(binary' | \&lt;br /&gt;            grep -v '(text' | grep -v '(symlink' | \&lt;br /&gt;            grep -v 'delete change'&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;if [ `lsfiles $REV | wc -l` != 0 ]; then&lt;br /&gt;        echo "Using forbidden filetypes"&lt;br /&gt;        lsfiles $REV&lt;br /&gt;        exit 1&lt;br /&gt;fi&lt;/pre&gt;Надо сказать что действия с репозиторием в триггере ограничены.  Например доступ к ревизии осуществляется исключительно по номеру @=&lt;номер ревизии&gt;, ибо это pending changelist.&lt;br /&gt;&lt;br /&gt;Указанный выше фильтр допускает применение модификаторов, как-то text+k, text+ko, text+kox, но и тут собака порылась... В мануале написано:&lt;br /&gt;&lt;pre&gt;The following type aliases exist for backwards compatibility:&lt;br /&gt;xtext       text                 +x&lt;/pre&gt;То есть ты, зараза такая должна отображать их по новому!!! а ты, зараза такая, вместо этого, при указании text+x радостно пишешь - xtext... Пришлось добавить дополнительный grep на этот случай. &lt;br /&gt;&lt;pre&gt;grep -v 'text)'&lt;/pre&gt;Теперь осталось включить триггер..&lt;br /&gt;&lt;pre&gt;$ p4 triggers&lt;br /&gt;Triggers:&lt;br /&gt;        forbidden change-content //depot/... "prohibited-file-types %change%"&lt;/pre&gt;После чего ни один коммит содержащий unicode, UTF16 или еще какую непонятную фигню не пройдет. &lt;br /&gt;&lt;br /&gt;В этом триггере возможно использование change-submit, для указанной ревизии список файлов должен быть уже на сервере. Но я как-то в процессе экспериментов остановился на change-content, пусть пока так стоит.&lt;br /&gt;&lt;br /&gt;Правда это не спасает нас от того, что в тексте файла буквы могут быть любые. Для этого нужна еще одна проверка на тело файлов. В частности UTF-8 часто проскакивает. Надо только придумать как лучше всего проверить файл на предмет некорректной кодировки.&lt;br /&gt;&lt;br /&gt;Наверное подойдет что-то типа того:&lt;br /&gt;&lt;pre&gt;iconv -f utf-8 -t koi8-r &amp;&amp; die&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-4763539605465557985?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/4763539605465557985/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=4763539605465557985' title='Комментарии: 11'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/4763539605465557985'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/4763539605465557985'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2011/02/perforce.html' title='Триггеры perforce'/><author><name>Андрей Валяев</name><uri>https://profiles.google.com/105555804149403561366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-f5qQ0O2SMCo/AAAAAAAAAAI/AAAAAAAAAAA/ZQ5xusHVJVU/s512-c/photo.jpg'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-1613266772090205097</id><published>2011-01-14T14:23:00.008+03:00</published><updated>2011-01-14T17:54:24.056+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='отладка'/><title type='text'>ISO9660 FILESYSTEM</title><content type='html'>Мне не нравится FreeBSD. эта антипатия старая и взаимная. Я ее даже не хочу ставить в тэги.&lt;br /&gt;&lt;br /&gt;Началось все это давно (2001 кажется год), когда она отказалась читать с fd0 блок по размеру некратный 512 байт. Да вы слышали что нибудь про абстракцию вообще???&lt;br /&gt;&lt;br /&gt;Я тогда некоторое время возился с ней, патч имени меня можно найти во FreeBSD. Но это было давно. Сейчас я опять работаю с ней, и она не перестает меня радовать.&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Наше приложение должно читать с CD информацию. Мы обеспечили поддержку этого формата, и неожиданностей в принципе не ожидали. Правда экспериментировали мы на дисках, записанных собственноручно.&lt;br /&gt;&lt;br /&gt;И вот сюрприз, пришел правильный диск - не работает. Стали выяснять почему, и выяснилось...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Стандарт ISO подразумевает, что все имена файлов хранятся в верхнем регистре. Но операционные системы, дабы не шокировать пользователей, приводят все имена к нижнему регистру. Говоря про системы я имею ввиду Unix.&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;Мы наивно предполагали что диски будут писать люди грамотные и продвинутые, и если написано имя файла должно быть большими буквами - значит надо использовать расширения, в которых большие буквы отличаются от маленьких. Собственно так мы и делали и работали с именами файлов исключительно в верхнем регистре.&lt;br /&gt;&lt;br /&gt;После монтирования диска все имена файлов почему-то в нижнем регистре. Мы быстро сообразили, что это вероятно из за отсутствия расширений ISO. Только вот оставалось не совсем понятным, почему приложение, хоть и не полностью, все таки работает.&lt;br /&gt;&lt;br /&gt;Оказалось, что FreeBSD, Тудыть ее в CVS, позволяет пользователям работать с файлами в верхнем регистре.&lt;br /&gt;&lt;pre&gt;# ls&lt;br /&gt;foo.txt&lt;br /&gt;# ls FOO.TXT&lt;br /&gt;FOO.TXT&lt;br /&gt;# WTF?!?&lt;/pre&gt;Вот блин, какие заботливые, позаботились о глупых пользователях, не оставили нас...&lt;br /&gt;&lt;pre&gt;# ls *.TXT&lt;br /&gt;&lt;пусто&gt;&lt;br /&gt;# WTF!?! WTF?!?&lt;/pre&gt;На этом мы собственно и обожглись. Открытие файлов работает без проблем. А вот glob("*.TXT") выдает пустой результат. &lt;br /&gt;&lt;br /&gt;Ну кто так строит???&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-1613266772090205097?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/1613266772090205097/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=1613266772090205097' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/1613266772090205097'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/1613266772090205097'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2011/01/iso9660-filesystem.html' title='ISO9660 FILESYSTEM'/><author><name>Андрей Валяев</name><uri>https://profiles.google.com/105555804149403561366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-f5qQ0O2SMCo/AAAAAAAAAAI/AAAAAAAAAAA/ZQ5xusHVJVU/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-7593089781862698852</id><published>2011-01-13T23:49:00.008+03:00</published><updated>2011-01-17T01:16:46.031+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gcc'/><category scheme='http://www.blogger.com/atom/ns#' term='clang'/><title type='text'>Назначенные инициализаторы</title><content type='html'>Есть такая замечательная штука, как &lt;a href="http://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html"&gt;Designated Initializers&lt;/a&gt;. Эта возможность описана в стандарте ISO C99.&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;pre&gt;const char *msg[] = {&lt;br /&gt; [0] = "No message",&lt;br /&gt; [1] = "Message 1",&lt;br /&gt; [2] = "Message 2",&lt;br /&gt; ...&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;const struct foo f = {&lt;br /&gt; .field1 = 10,&lt;br /&gt; .field2 = 20,&lt;br /&gt; ...&lt;br /&gt;};&lt;/pre&gt;Всегда сожалел о том, что такой возможности нету в C++. Ведь бывают и просто структуры, не все же конструкторы городить. А такая возможность здорово помогает обезопаситься от ошибок при инициализации. Инициализация в традиционном стиле далеко не так наглядна и превращается в сущий ад, если структура содержит больше трех элементов.&lt;br /&gt;&lt;pre&gt;const struct foo f = { 10, 20, ... };&lt;/pre&gt;И вот значит совершенно случайно скопировал кусок кода из .c в .cpp... &lt;br /&gt;&lt;pre&gt;const struct KernelModifyCustomIoBindParam bind_params = {&lt;br /&gt; .first = first_port,&lt;br /&gt; .last = last_port,&lt;br /&gt; .access = RESOURCE_ACCESS_READ | RESOURCE_ACCESS_WRITE,&lt;br /&gt;};&lt;/pre&gt;Скомпилировал без ошибок. И только потом сообразил, что это никак не должно было скомпилироваться. Что-то здесь не чисто.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Надо сказать, что я, с некоторых пор, для своего баловства использую clang. Clang рулит и я с интересом слежу за его развитием.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;И вот значит такая оказия... Компилится при полном уровне варнингом, хоть ты тресни. Переключился на gcc:&lt;br /&gt;&lt;pre&gt;Compile for localhost test/Custom.cpp...&lt;br /&gt;Custom.cpp: In member function ‘void suiteCustom::testBindPortToCustom::test_method()’:&lt;br /&gt;Custom.cpp:29: ошибка: expected primary-expression before ‘.’ token&lt;br /&gt;Custom.cpp:30: ошибка: expected primary-expression before ‘.’ token&lt;br /&gt;Custom.cpp:31: ошибка: expected primary-expression before ‘.’ token&lt;br /&gt;make[1]: *** [/home/dron/MDF.Temp/test_Custom.o] Ошибка 1&lt;br /&gt;make: *** [test] Ошибка 2&lt;/pre&gt;Как и следовало ожидать - результат положительный, то бишь не компилится.&lt;br /&gt;&lt;br /&gt;Что это? несоответствие стандартам в clang? или просто они тоже считают эту фичу клевой и допустили ее использование в c++? Надо пообщаться с разработчиками.&lt;br /&gt;&lt;br /&gt;PS: Если ваша программа компилируется без ошибок, обратитесь к разработчику компилятора, он исправит ошибки в нем.. :D&lt;br /&gt;&lt;br /&gt;PPS: fixed in r123582 :) В этот раз правда моего имени не написали, так что я теперь аноним.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-7593089781862698852?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/7593089781862698852/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=7593089781862698852' title='Комментарии: 3'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/7593089781862698852'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/7593089781862698852'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2011/01/blog-post.html' title='Назначенные инициализаторы'/><author><name>Андрей Валяев</name><uri>https://profiles.google.com/105555804149403561366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-f5qQ0O2SMCo/AAAAAAAAAAI/AAAAAAAAAAA/ZQ5xusHVJVU/s512-c/photo.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-1291403117282715259</id><published>2010-12-22T16:20:00.005+03:00</published><updated>2010-12-27T11:43:29.805+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='отладка'/><title type='text'>Не вся информация одинаково полезна</title><content type='html'>Очень часто для отладки приходится использовать всяческие отладочные сообщения. Но мне совершенно непонятно, почему эти отладочные сообщения попадают в репозиторий!!!&lt;br /&gt;&lt;br /&gt;И еще я что-то засомневался в полезности ассертов. Они конечно не оставляют незамеченными проблемы, но очень часто мало что дают для их разрешения, кроме оставленной после себя коры...&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Я очень люблю отладочные сообщения. Они говорят мне значительно больше чем ковыряние в отладчике. Я вообще не люблю отладчики.&lt;br /&gt;&lt;br /&gt;Причем наш код уже содержит достаточно много всякого мусора, который давно надо убить. Зачем убить, спросите вы, ведь отладочные сообщения полезны?!? Надо. Опыт подсказывает, что чужие сообщения не несут информации. Очень редко получается так, что посмотрел на чужие сообщения, и понял в чем проблема. Чаще приходится дописывать новые.&lt;br /&gt;&lt;br /&gt;Так зачем спрашивается хранить старые, если их в каждом конкретном случае все равно приходится менять??? Эти отладочные сообщения заполонили весь код, у нас их столько, что за ними содержательных не видно!!!&lt;br /&gt;&lt;br /&gt;Короче, отладочным сообщениям не место в продакшн коде. Но с другой стороны в нем могли бы быть понятные информационные сообщения. Как отличить белый шум от полезной информации? Кому полезной? Насколько полезной?&lt;br /&gt;&lt;br /&gt;Теперь о другом, про ассерты. Ассерты конечно очень хороший инструмент, но нужно уметь различать совершенно фатальную ситуацию и просто некоторые несоответствие некоторым ожиданиям. Особенно это плохо, в библиотеках.&lt;br /&gt;&lt;br /&gt;Какого черта вот она в fastDB падает:&lt;br /&gt;&lt;pre&gt;assert(currId != 0);&lt;/pre&gt;Может это и правильно с ее точки зрения, но не несет мне необходимой информации. Может быть исключение в данном случае было бы предпочтительнее? В исключение можно запихнуть значительно больше информации, которая позволит тому, кто пользуется данными методами понять, что же он делает не так.&lt;br /&gt;&lt;br /&gt;Хотя может быть я что-то понимаю неправильно. shared_ptr тоже не позволяет себе бросать исключения из operator-&gt;, и тоже обходится ассертами. В релизной версии ассертов нету, и приложение просто крешится.&lt;br /&gt;&lt;br /&gt;Тему про наглядность ассертов я уже &lt;a href="http://mdf-i.blogspot.com/2008/09/blog-post_07.html"&gt;поднимал как-то&lt;/a&gt;, с тех пор собственно ничего не изменилось. Ассерты не доносят информацию. Сообщение о том, что 'currId != 0', могло бы что-то полезное сообщить, если я работаю на соседнем уровне, то есть вызываю эту функцию непосредственно. Но теряет всякий смысл, когда я использую все это через три уровня косвенности. &lt;br /&gt;&lt;br /&gt;Да, можно определить что она улетела в БД и зарылась где-то там... Зачем зарылась - а кто его знает. Если бы это было бы исключением - его мог бы обработать какой-то из промежуточных уровней и сказать что у него пошло не так. Сказать что-то большее, нежели currId == 0. Чтобы докопаться до причины, в случае ассерта необходимо понять как работают все промежуточные уровни.&lt;br /&gt;&lt;br /&gt;Я вообще не люблю, когда на пользователя вываливается все. Компьютер должен работать, он должен работать над тем, как концентрированно донести до пользователя суть его проблем. Не без помощи программистов конечно.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-1291403117282715259?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/1291403117282715259/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=1291403117282715259' title='Комментарии: 9'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/1291403117282715259'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/1291403117282715259'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2010/12/blog-post_22.html' title='Не вся информация одинаково полезна'/><author><name>Андрей Валяев</name><uri>https://profiles.google.com/105555804149403561366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-f5qQ0O2SMCo/AAAAAAAAAAI/AAAAAAAAAAA/ZQ5xusHVJVU/s512-c/photo.jpg'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-1491185060525207543</id><published>2010-12-16T10:14:00.004+03:00</published><updated>2010-12-16T12:41:04.515+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='отладка'/><category scheme='http://www.blogger.com/atom/ns#' term='ошибки'/><title type='text'>Изгоняющий демонов</title><content type='html'>С некоторых пор я решил больше писать, что-то совсем забываю про блог. Чтобы не расслабляться - каждую неделю обещал себе выдавать по посту. Пока получается не очень плохо. Когда тебя подстегивают сроки - ты заранее начинаешь собирать идеи для новых постов.&lt;br /&gt;&lt;br /&gt;Одна из таких идей у меня касалась ошибок. Не простых, а трудно воспроизводимых. У нас вообще складывается ситуация на данный момент, что очень часто мы ничего не можем сказать, глядя на багу. Хорошо, если воспроизвел на стенде и причина ясна. Часто бывает что она проявляется не всегда, а только при полной луне... &lt;br /&gt;&lt;br /&gt;Тема показалась мне не достаточной для полноценного поста. Но сама судьба подбросила одну из таких ошибок, с которой я проковырялся три дня и в конце концов одолел. Есть, что рассказать...&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Вообще сам факт наличия таких ошибок, как то трудновоспроизводимых или просто непонятных, характеризует общее состояние проекта. Да, есть над чем работать...&lt;br /&gt;&lt;br /&gt;Итак, ситуация следующая: приложение стартует замечательно, но при повышении нагрузки падает, в коре какая-то белиберда.&lt;br /&gt;&lt;br /&gt;Поскольку приложение у нас серверное, места на сервере мало - с отладчиками там крайне не удобно, их там нету. Поэтому мы локализуем место с помощью отладочного вывода.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Прошел день...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Удалось выяснить, что падает она при попытке вызова виртуальной функции. Где-то портится память? Память вряд ли может портится в самой виртуальной таблице, скорее всего поехал указатель на виртуальную таблицу. Обложили это все ассертами - не клюет...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;В тщетных попытках понять смысл проблемы прошел еще один день...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;И вот ведь зараза, вообще перестала обрабатывать соединения. Ошибка происходит в 100% случаев. Это конечно хорошо, только ясности не добавляет. В порыве отчаяния накрутил сильно отладочных опций, как-то -fstack-check, -fbounds-check (Написано что в си не работает, ну до кучи). После чего удалось выяснить, что вызов виртуальной функции всетаки происходит, отладочное сообщение вывелось, а падение происходит где-то дальше.&lt;br /&gt;&lt;br /&gt;Но долго искать уже не пришлось. В начале функции стоит буфер на 65 килобайт. Раньше уже приходилось сталкиваться с ограничением на размер стека нити. Помню что оно не велико... Очень невелико... Что-то типа нескольких килобайт...&lt;br /&gt;&lt;br /&gt;Определить размер стека по умолчанию - просто.&lt;br /&gt;&lt;pre&gt;#include &amp;lt;stdio.h&gt;&lt;br /&gt;#include &amp;lt;pthread.h&gt;&lt;br /&gt;&lt;br /&gt;int main(int argc, char **argv)&lt;br /&gt;{&lt;br /&gt; pthread_attr_t thread_attr;&lt;br /&gt; pthread_attr_init(&amp;thread_attr);&lt;br /&gt;&lt;br /&gt; size_t stacksize = 0;&lt;br /&gt; pthread_attr_getstacksize(&amp;thread_attr, &amp;stacksize);&lt;br /&gt;&lt;br /&gt; printf("Размер стека по умолчанию: %lu\n", stacksize);&lt;br /&gt;&lt;br /&gt; return 0;&lt;br /&gt;}&lt;/pre&gt;Для Linux (x86-64) он достаточно комфортный - 8 мегабайт... но на FreeBSD (i386) - всего 64 килобайта. Учитывая тот факт, что стек нити располагается в адресном пространстве процесса, выделяясь в куче, выход за его пределы может нарушить работу приложения в самый непонятный момент. И эта проблема может долго оставаться незамеченной. Использование стека в релизной и отладочной версии разное. Расположение блоков памяти в куче тоже может варьироваться, предсказать результат достаточно сложно.&lt;br /&gt;&lt;br /&gt;Я в принципе люблю пользоваться стеком, это ограничивает область видимости и избавляет от возни с динамической памятью. Наверное я все таки правильно сделал, что в MDF создал для каждой нити свой, полностью изолированный стек.&lt;br /&gt;&lt;br /&gt;А что делать с проектом - где-то видел, что в gcc можно инструментовать каждую функцию. Надо туда вставить функцию, контролирующую размер стека. И погонять...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-1491185060525207543?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/1491185060525207543/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=1491185060525207543' title='Комментарии: 11'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/1491185060525207543'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/1491185060525207543'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2010/12/blog-post.html' title='Изгоняющий демонов'/><author><name>Андрей Валяев</name><uri>https://profiles.google.com/105555804149403561366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-f5qQ0O2SMCo/AAAAAAAAAAI/AAAAAAAAAAA/ZQ5xusHVJVU/s512-c/photo.jpg'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-7912112934672027249</id><published>2010-12-08T10:58:00.003+03:00</published><updated>2010-12-08T12:24:13.316+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='exherbo'/><title type='text'>Есть ли жизнь с systemd?</title><content type='html'>Я вообще люблю ощущать какое-то движение вокруг. Мир меняется, программы меняются тоже. Поэтому я пересел на Gentoo. Которая тоже, со временем стала не такая веселая, в связи с чем дома я теперь использую Exherbo. Которая пока еще настолько нестабильная, что не устает меня радовать... каждою иголочкой... &lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Вот и в эти выходные, после очередного обновления, которое сопровождалось установкой нового профиля - система перестала загружаться.&lt;br /&gt;&lt;br /&gt;В таких ситуациях хорошо, если грузится консоль. Можно по быстрому исправить ситуацию. Но в этот раз все оказалось хуже. Система останавливалась из за того, что не могла использовать udev, никакие устройства не появлялись, и система не могла даже рут перемонтировать. Полный финиш.&lt;br /&gt;&lt;br /&gt;А до того я хотел попробовать systemd, и поэтому включил соответствующую опцию перед обновлением. При возникновении проблемы первым делом я попытался отключить опцию, но udev облегчения при этом не почувствовал. Стал выяснять почему.&lt;br /&gt;&lt;br /&gt;И выяснилось, что systemd отныне recommended for exherbo, а устаревший baselayout по умолчанию отключен в новом профиле. Ну что тут поделаешь - надо переходить на systemd.&lt;br /&gt;&lt;br /&gt;Собрал сам systemd, обновил еще раз udev, накатил новое ядро - 2.6.36-rc1 минимум, от которого &lt;a href="http://www.mailstation.de/wordpress/?p=48"&gt;systemd много чего требует&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;После чего я смог загрузить систему в минимально-консольном окружении. Загрузить-то загрузил, но что с ней делать дальше? - Интернета нету, иксов нету, как включать неизвестно. Другой мир... Хорошо, что у меня рядом есть другой компьютер с интернетом.&lt;br /&gt;&lt;br /&gt;Проблемы решаются достаточно просто.&lt;br /&gt;Чтобы появилась сеть, которая у меня конфигурируется статически, необходимо для systemd включить опцию simple-net, после чего он установит network.service и /etc/conf.d/netfork.conf для него.&lt;br /&gt;&lt;br /&gt;Включаются сервисы просто:&lt;br /&gt;&lt;pre&gt;# systemctl enable network.service&lt;br /&gt;# systemctl enable samba.service&lt;br /&gt;# systemctl enable kdm.service&lt;/pre&gt;&lt;br /&gt;Я правда так и не понял, как рестартить сервисы. systemctl restart network.service ни на что не ругается и ничего не делает. Как и start/stop. Может быть недоделанные фичи systemd?&lt;br /&gt;&lt;br /&gt;Но больше меня волнует другое, как подключить к systemd transmission? Это не срочно, а в остальном жизнь более менее налажена. интернет есть, графика есть...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-7912112934672027249?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/7912112934672027249/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=7912112934672027249' title='Комментарии: 3'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/7912112934672027249'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/7912112934672027249'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2010/12/systemd.html' title='Есть ли жизнь с systemd?'/><author><name>Андрей Валяев</name><uri>https://profiles.google.com/105555804149403561366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-f5qQ0O2SMCo/AAAAAAAAAAI/AAAAAAAAAAA/ZQ5xusHVJVU/s512-c/photo.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-1301152477267516962</id><published>2010-12-01T12:39:00.003+03:00</published><updated>2010-12-01T13:10:15.951+03:00</updated><title type='text'>Кодинг стайл - 3 пробела...</title><content type='html'>Не понимаю, откуда в программистском сообществе такая нелюбовь к табуляциям? &lt;br /&gt;&lt;br /&gt;Взять к примеру &lt;a href="http://www.gnu.org/prep/standards/html_node/Formatting.html#Formatting"&gt;GNU coding style&lt;/a&gt;. Вертикальное пространство они никак не экономят, скобки пишут на новых строчках. Зато в горизонтальном плане почему-то экономят.&lt;br /&gt;&lt;br /&gt;Или вот &lt;a href="http://www.python.org/dev/peps/pep-0008/"&gt;Python Style Guide&lt;/a&gt; вообще не рекомендует использовать табы, хотя и не запрещает как некоторые.&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Собственно пытался освоить какую нибудь IDE... &lt;br /&gt;&lt;br /&gt;Наверное я уже слишком давно занимаюсь программированием в просто редакторах, чтобы мне могли понравиться IDE. Баловался в NetBeans с питоном - не выдержал, вернулся в kate.&lt;br /&gt;&lt;br /&gt;Много всяких умных подсказок, но я как-то и без них обхожусь. А вот то, что идентификация в одну сторону, когда нажимаешь Enter, работает хорошо, а в другую сторону, когда нажимаешь Del, вынуждает удалять n'ное количество пробелов, при этом совершенно не допуская табуляций - напрягает меня гораздо больше.&lt;br /&gt;&lt;br /&gt;Может я просто неправильно редактирую? Я могу переучиваться, я уже почти научился переключать русский/английский разными клавишами. :) Но с IDE у меня пока не ладится. Kate от меня ничего не требует, и свои правила не насаждает.&lt;br /&gt;&lt;br /&gt;Вообще я думаю что табуляции гораздо удобнее пробелов. &lt;br /&gt;&lt;br /&gt;Некоторые говорят, что отступы в 8 символов приводят к слишком широкому тексту. Но ведь если глубина отступов превышает 3 - пожалуй у вас слишком большая и глубокая функция. А с другой стороны размер табуляции можно настроить... настройте на 4 или на 2. Хотя, по моему, 8 - вполне выразительно.&lt;br /&gt;&lt;br /&gt;А чтобы не разъезжались выравнивания в конце строк - их просто не надо выравнивать. :) Существуют &lt;a href="http://dklab.ru/chicken/nablas/11.html"&gt;правила правильной расстановки табуляции&lt;/a&gt;, но мне кажется что в хвостах строк вообще лучше ничего не выравнивать - проще модифицировать потом.&lt;br /&gt;&lt;br /&gt;И получается, что автодополнение мне почти что пофиг, могу обойтись и без него. А вот к такие мелочи сильно достают. Просматривал я разные IDE больше в плане рефакторинга. Но как-то скудно там все в этом плане.&lt;br /&gt;&lt;br /&gt;Пробовал смотреть даже emacs. Сильно меня не пинайте, но с одной стороны мне кажется что он мог бы быть и покрасивее, а с другой стороны я еще недостаточно хорошо знаю lisp (практически совсем не знаю), чтобы его использовать...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-1301152477267516962?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/1301152477267516962/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=1301152477267516962' title='Комментарии: 11'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/1301152477267516962'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/1301152477267516962'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2010/12/3.html' title='Кодинг стайл - 3 пробела...'/><author><name>Андрей Валяев</name><uri>https://profiles.google.com/105555804149403561366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-f5qQ0O2SMCo/AAAAAAAAAAI/AAAAAAAAAAA/ZQ5xusHVJVU/s512-c/photo.jpg'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-1148804215161738065</id><published>2010-11-08T12:53:00.004+03:00</published><updated>2010-11-08T13:24:21.165+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><title type='text'>Про гибкое планирование...</title><content type='html'>Хотелось блеснуть интеллектом, процитировав классиков. Но небольшое углубление в тему показало что классиков перевирают... :)&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Вот у Энди Ханта я встречал изречение:&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: right;"&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;Стычка с неприятелем разрушает любые планы&lt;/span&gt;&lt;br /&gt;&lt;a href="http://ru.wikipedia.org/wiki/%D0%9C%D0%BE%D0%BB%D1%8C%D1%82%D0%BA%D0%B5,_%D0%A5%D0%B5%D0%BB%D1%8C%D0%BC%D1%83%D1%82_%D0%9A%D0%B0%D1%80%D0%BB_%D0%91%D0%B5%D1%80%D0%BD%D1%85%D0%B0%D1%80%D0%B4_%D1%84%D0%BE%D0%BD"&gt;Хельмут фон Мольтке&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Его много цитируют, и именно его я тоже хотел процитировать в контексте противостояния Google vs Oracle.&lt;br /&gt;&lt;br /&gt;Еще встречаются варианты:&lt;br /&gt;&lt;div style="text-align: right;"&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;Ни один план не переживает встречи с противником&lt;/span&gt;&lt;/div&gt;&lt;div style="text-align: right;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;span style="font-style:italic;"&gt;&lt;div style="text-align: right;"&gt;Ни один план не переживет столкновения с врагом&lt;/div&gt;&lt;/span&gt;&lt;div style="text-align: right;"&gt;&lt;a href="http://ru.wikipedia.org/wiki/%D0%A0%D0%BE%D0%BC%D0%BC%D0%B5%D0%BB%D1%8C,_%D0%AD%D1%80%D0%B2%D0%B8%D0%BD"&gt;Эрвин Роммель&lt;/a&gt;&lt;/div&gt;&lt;span style="font-style:italic;"&gt;&lt;div style="text-align: right;"&gt;Ни один план не выживает, после контакта с миром.&lt;/div&gt;&lt;/span&gt;&lt;div style="text-align: right;"&gt;&lt;a href="http://ru.wikipedia.org/wiki/%D0%9F%D0%B0%D0%B2%D0%BB%D0%B8%D0%BD%D0%B0,_%D0%A1%D1%82%D0%B8%D0%B2"&gt;Стив Павлина&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: right;"&gt;&lt;br /&gt;&lt;/div&gt;Но учитывая, что Мольтке жил задолго до Роммеля и Павлины можно предположить, что те действительно произносил подобную фразу, вычитав ее.&lt;br /&gt;&lt;br /&gt;Только вот проблема в том, что смысл изречения несколько искажен.&lt;br /&gt;&lt;br /&gt;В &lt;a href="http://militera.lib.ru/science/classic2/15.html"&gt;своих трудах&lt;/a&gt; Мольтке сказал следующее:&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Ни один оперативный план не может, хотя бы с некоторой достоверностью, простираться за пределы первого столкновения с главными силами противника. Только профан может полагать, что ход кампании представляет логическое осуществление заранее очерченной, детально проработанной и до конца удерживаемой первоначальной идеи.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Вполне себе так в духе гибких методологий...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-1148804215161738065?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/1148804215161738065/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=1148804215161738065' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/1148804215161738065'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/1148804215161738065'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2010/11/blog-post.html' title='Про гибкое планирование...'/><author><name>Андрей Валяев</name><uri>https://profiles.google.com/105555804149403561366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-f5qQ0O2SMCo/AAAAAAAAAAI/AAAAAAAAAAA/ZQ5xusHVJVU/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-5673462948177136828</id><published>2010-10-08T23:20:00.002+04:00</published><updated>2010-10-08T23:38:22.756+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><title type='text'>Coding style battle</title><content type='html'>Стандарт кодирования у нас в команде отсутствует.&lt;br /&gt;&lt;br /&gt;Это было бы ничего, если бы не возникало проблем. Но недавно обнаружилось, что один разработчик старательно вычищает то, что добавляют другие. Поскольку этот процесс совершенно неконструктивен - стали разбираться.&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Да, я могу согласиться что использование using namespace в глобальном пространстве имен чем-то чревато. Может вызвать различные неудобства, в плане того, что описываемая переменная начнет конфликтовать с каким-то именем из указанного пространства. Не вижу в этом ничего страшного, не знаю как кто, я достаточно редко на это натыкаюсь.&lt;br /&gt;&lt;br /&gt;С одной стороны даже хорошо, это предостерегает разработчика от привычки присваивать имена, которые уже где-то используются. Повышает однозначность кода.&lt;br /&gt;&lt;br /&gt;Но мне не жалко. Я могу пойти навстречу, и соглашусь отказаться от использования using namespace в глобальном пространстве. Хотя с постоянным указыванием std::, boost:: и других общеупотребительных пространств я все равно буду бороться с помощью локальных using и определений типов.&lt;br /&gt;&lt;br /&gt;Благо на этом сошлись.&lt;br /&gt;&lt;br /&gt;Но есть еще одна вещь на которую я пойтить не могу!&lt;br /&gt;&lt;br /&gt;Совершенно дурацкий стиль - ставить тип на отдельной строке. Его ноги вероятно растут из GNU codin style, но GNU - это все таки по большей части си. &lt;br /&gt;&lt;br /&gt;Мне объяснили, зачем это надо. Это надо, дескать для того, чтобы легко можно было найти реализацию функции, поскольку перед именем функции в определении нет пробельных символов. И дескать это способствует более успешному поиску. Может быть. Но при этом в результатах того самого поиска мы получаем не полную информацию, поскольку там отсутствует возвращаемый тип. &lt;br /&gt;&lt;br /&gt;Вообще я не люблю распространение программы в длину, так типичное для GNU стиля. И каждая строка должна быть самодостаточна. Для функции главным является тип, имя и список аргументов. И это все должно быть вместе.&lt;br /&gt;&lt;br /&gt;Если поиск по названию функции выводит 100 мест где она используется, может быть это и правильно, но мне кажется - что-то не так с архитектурой... надо лечить.&lt;br /&gt;&lt;br /&gt;Почему у меня не возникает проблем с поиском? Наверное не так что-то делаю...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-5673462948177136828?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/5673462948177136828/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=5673462948177136828' title='Комментарии: 14'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/5673462948177136828'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/5673462948177136828'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2010/10/coding-style-battle.html' title='Coding style battle'/><author><name>Андрей Валяев</name><uri>https://profiles.google.com/105555804149403561366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-f5qQ0O2SMCo/AAAAAAAAAAI/AAAAAAAAAAA/ZQ5xusHVJVU/s512-c/photo.jpg'/></author><thr:total>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-8052785993653629908</id><published>2010-09-30T10:34:00.002+04:00</published><updated>2010-09-30T12:56:05.648+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='test'/><title type='text'>Использование юниттестов</title><content type='html'>Всетаки я еще не достиг просветления, и очень часто пишу код без тестов, потому что так быстрее/влом/проще/подствьте свой вариант...&lt;br /&gt;&lt;br /&gt;Тесты должны прорабатывать быстро, но есть одна проблема - время компиляции. И в таком контексте я не на шутку задумался о сценариях сборки тестового раннера.&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Идеальным для обычных приложений мне видится вариант, когда практически весь код приложения располагается в библиотеке. В принципе это не обязательно должна быть библиотека. Более быстрым может оказаться подход, который я наблюдал в linux ядре. Там модули аккумулируются в .o файлы.&lt;br /&gt;&lt;br /&gt;Итак, весь код продукта аккумулируется в один модуль, который легко может быть слинкован как с main функцией продукта (которая по причине нетестированности должна быть минимальна), так и с тестовым раннером.&lt;br /&gt;&lt;br /&gt;Вообще скорость надо померять. Ради скорости может иметь смысл все объектники раннера тоже слинковать, поскольку типичный сценарий TDD затрагивает то тесты, то код продукта. Но чтобы померять скорость - необходимо иметь достаточно объемный проект, разработанный в стиле TDD. У меня такого нету, я только учусь.&lt;br /&gt;&lt;br /&gt;И учусь я вот на чем:&lt;br /&gt;&lt;br /&gt;Одна из моих старых творений - это мое ядро, которое по истечении 10 лет все еще не готово. Но там вообще своя специфика. Там объектные модули продукта теоретически могут быть вообще не совместимы с текущей платформой, так что для тестирования их всеравно надо собрать под HOST.&lt;br /&gt;&lt;br /&gt;Другая случай - это мой рабочий проект. В котором я поступил так: Я включил все исходники продукта в проект для тестирования, и они дважды собираются. Один раз при сборке бинарника продукта, другой раз при сборке тестового раннера. С тестированием там достаточно туго, но некоторые вещи удается потестировать.&lt;br /&gt;&lt;br /&gt;Долго гуглил - но нигде не могу найти информацию о том, как люди разруливают тестирование и сборку в C++ проектах... Если не услышу более умного рецепта - буду изобретать свой велосипед.&lt;br /&gt;&lt;br /&gt;Есть мысли пощупать Google test... каким он окажется в противовес boost?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-8052785993653629908?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/8052785993653629908/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=8052785993653629908' title='Комментарии: 3'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/8052785993653629908'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/8052785993653629908'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2010/09/blog-post_30.html' title='Использование юниттестов'/><author><name>Андрей Валяев</name><uri>https://profiles.google.com/105555804149403561366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-f5qQ0O2SMCo/AAAAAAAAAAI/AAAAAAAAAAA/ZQ5xusHVJVU/s512-c/photo.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-8712022851083459309</id><published>2010-09-17T12:18:00.004+04:00</published><updated>2010-09-30T14:32:34.690+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='google'/><title type='text'>Есть ли в Google суппорт?</title><content type='html'>&lt;div style="text-align: right;"&gt;- Доктор, меня никто не замечает&lt;br /&gt;- Следующий!&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;В связи с изменением структуры организации, в которой я работаю - я уже два месяца, как ведущий программист в компании Код Безопасности в группе компаний Информзащита. &lt;span style="font-style:italic;"&gt;Типа хвалюсь, что теперь я не хухры мухры, а уже ведущий.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Заодно у меня сменился адрес электронной почты. Вместо привычного мне dron@infosec.ru, которым я пользовался 10 лет, у меня появился новый @securitycode.ru&lt;br /&gt;&lt;br /&gt;И решил я значит завести себе новый аккаунт в Google...&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Тем самым, заодно, расчистить список используемых приложений. А то они, по большей части не удаляются из профиля, хотя нафиг не нужны.&lt;br /&gt;&lt;br /&gt;Но не все так просто...&lt;br /&gt;&lt;br /&gt;Первым делом я конечно добавил себя нового в свои старые приложения, которыми пользуюсь. Blogger, Код, Группы, Ридер, Сайты.&lt;br /&gt;&lt;br /&gt;Все настроено, все работает, но почему-то некоторые приложения упорно не хотят попадать в мой список. Блоггер, Сайты в аккаунте есть, Группы, Код и Ридер приходится выискивать через дополнительные кнопки.  Что надо сделать чтобы они попали в аккаунт?&lt;br /&gt;&lt;br /&gt;Пытался описать свою проблему на гугле - у них нет проблем репорта по Аккаунту. :( Причем список продуктов на русском сайте сильно уже списка продуктов на западном. Но и там поддержки по Аккаунту нету. Только FAQ, который почему-то не описывает данную проблему.&lt;br /&gt;&lt;br /&gt;От нечего делать описал проблему - На российском сайте в разделе &lt;a href="http://www.google.com/support/forum/p/groups/thread?tid=53cc136bc321932b&amp;hl=ru"&gt;про Группы&lt;/a&gt;, на западном сайте в разделе &lt;a href="http://www.google.com/support/forum/p/reader/thread?tid=7e5da05c213c6034&amp;hl=en"&gt;про Reader&lt;/a&gt;. Прошло две недели... Реакция - ноль.&lt;br /&gt;&lt;br /&gt;Может быть у меня плохой английский, но я стараюсь... мне можно задавать наводящие вопросы...&lt;br /&gt;&lt;br /&gt;Но это еще не все.&lt;br /&gt;&lt;br /&gt;Google Code - мой аккаунт выглядит как Unverified... Я могу пользоваться репозиториями, но не могу производить какие-либо действия через сайт.. вообще никакие! Даже примитивное Issue создать я не в состоянии... &lt;br /&gt;&lt;br /&gt;Со старого аккаунта создал &lt;a href="http://code.google.com/p/support/issues/detail?id=4381"&gt;Issue&lt;/a&gt; на странице проекта Google Code.  Прошло две недели... Аккаунт по прежнему Unverified, на запрос - ноль реакции...&lt;br /&gt;&lt;br /&gt;Что же это делается? Куда тыркать то надо, чтобы аккаунт заверифицировался? И почему никто не обращает на меня внимания? Я для чего запросы пишу???&lt;br /&gt;&lt;br /&gt;Короче не получив никакой реакции пишу сюда, в надежде что суперкомпьютер Google, проиндексировав мой пост подкинет мне пару полезных советов...&lt;br /&gt;&lt;br /&gt;UPDATE: 29 сентября в Google Code пофиксили мой Unverified... можно жить. :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-8712022851083459309?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/8712022851083459309/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=8712022851083459309' title='Комментарии: 3'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/8712022851083459309'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/8712022851083459309'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2010/09/google.html' title='Есть ли в Google суппорт?'/><author><name>Андрей Валяев</name><uri>https://profiles.google.com/105555804149403561366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-f5qQ0O2SMCo/AAAAAAAAAAI/AAAAAAAAAAA/ZQ5xusHVJVU/s512-c/photo.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-4260585215327396930</id><published>2010-09-06T23:26:00.003+04:00</published><updated>2010-09-07T00:15:40.362+04:00</updated><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='VCS'/><title type='text'>Ветвления в бранче</title><content type='html'>Все-таки это зло.&lt;br /&gt;&lt;br /&gt;Mercurial позволяет двум разработчикам независимо сделать push, что приведет к тому что в бранче на сервере получится ветвление. Но что делать третьему разработчику, который это вытягивает? Заниматься слиянием? Да он вообще не в курсе что там куда.&lt;br /&gt;&lt;br /&gt;Он мог бы выбрать себе, предположим, одну из ветвей... Но в это же самое время хозяин этой ветви может слить ее с другой и третий разработчик опять останется не у дел, где-то в своей отдельной ветке.&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Должна быть в системе контроля версий какая-то однозначность. Мне кажется логичным, что тот, кто первый закоммитил - тот и продолжил бранч. А отставшие должны приложить усилия (сделать rebase) чтобы вернуться в бранч.&lt;br /&gt;&lt;br /&gt;Про git - я тащусь... цитирую: "&lt;i&gt;Чтобы на самом деле разобраться в способе ветвления в Git, мы должны сделать шаг назад и рассмотреть, как Git хранит свои данные&lt;/i&gt;". А как же абстракция, сокрытие реализации и тд?&lt;br /&gt;&lt;br /&gt;Долго курил маны, так и не понял. Если в ветку удаленного репозитория git кто-то пропихнул свои изменения, git откажет мне в push?&lt;br /&gt;&lt;br /&gt;В принципе в git все сделано грамотно, только слишком уж низкоуровнево.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-4260585215327396930?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/4260585215327396930/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=4260585215327396930' title='Комментарии: 4'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/4260585215327396930'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/4260585215327396930'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2010/09/blog-post.html' title='Ветвления в бранче'/><author><name>Андрей Валяев</name><uri>https://profiles.google.com/105555804149403561366</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-f5qQ0O2SMCo/AAAAAAAAAAI/AAAAAAAAAAA/ZQ5xusHVJVU/s512-c/photo.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-6848208744779303535</id><published>2010-08-26T23:26:00.000+04:00</published><updated>2010-08-26T23:26:54.305+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='мысли'/><title type='text'>Допустимая публичность</title><content type='html'>В C++ традиционным считается использование public методов в начале описания. И сразу слайды:&lt;br /&gt;&lt;pre&gt;class foo {&lt;br /&gt;public:&lt;br /&gt;        foo();&lt;br /&gt;        void doSomething();&lt;br /&gt;private:&lt;br /&gt;        ...&lt;br /&gt;};&lt;/pre&gt;И это логично. При чтении кода первое, что мы видим, это доступные нам рычаги для воздействия на класс, его интерфейс. Для тех, кто дочитал до private, становятся известны некоторые подробности реализации. Но речь не о том...&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;В java объявлений, как таковых нету. В нем объявление и реализация существуют неразрывно. И там принято переменные описывать в начале класса.&lt;br /&gt;&lt;br /&gt;В принципе, что в c++, что в java, нет никаких ограничений на порядок следования описаний в классе. Но то, что принято в java - выглядит логично. После описания переменных следуют реализации, которые эти переменные используют.&lt;br /&gt;&lt;br /&gt;В том же C++ никто не отменял предварительные описания классов, отдельных функций и переменных. Именно поэтому код выглядит странно:&lt;br /&gt;&lt;pre&gt;class bad {&lt;br /&gt;public:&lt;br /&gt;        void action() {&lt;br /&gt;                badness = 100;&lt;br /&gt;        }&lt;br /&gt;        ...&lt;/pre&gt;Мы сразу пытаемся найти эту переменную выше по коду. Не пытайтесь найти ее там, это невозможно. Эта переменная находится на несколько сотен строк ниже, перед закрывающей класс скобкой. Мозг протестует, но в c++ это допустимо.&lt;br /&gt;&lt;br /&gt;Я вообще с некоторых пор перестал пользоваться инлайн объявлениями, за исключением темплейтов. &lt;br /&gt;&lt;br /&gt;Некоторые утверждают, - что дескать инлайн объявления инлайнятся, что делает программу быстрее. А вы уверены? Утверждения о скорости работы необходимо подтверждать цифрами. 80% преждевременной оптимизации лишне. Стоило ли ради этого мнимого ускорения жертвовать удобочитаемостью программы? Ведь освобождая интерфейс класса от ненужных подробностей мы облегчаем его понимание и использование.&lt;br /&gt;&lt;br /&gt;Кроме того если возникнет необходимость отладки - лично мне мешаются инлайн функции. Я бы предпочел чтобы каждая функция в исходном тексте оставалась такой же отдельной и в исполняемом модуле. Чтобы по одному содержимому стека проблема прояснялась. Но gcc последнее время стал слишком умным. даже при -O0 -ggdb3 он все равно инлайнит почем зря.&lt;br /&gt;&lt;br /&gt;Кроме того, даже самые маленькие методы, такие как &lt;code&gt;int getX() const { return x; }&lt;/code&gt; со временем могут подрасти. Что приводит к классам на 500 строк описания, но почему то без cpp файла. &lt;br /&gt;&lt;br /&gt;Поэтому я почти всю реализацию описываю отдельно от описания класса. Пусть описание будет чистым. И содержит только то, что невозможно убрать.&lt;br /&gt;&lt;br /&gt;Но если, не смотря на все мои уговоры, вам очень хочется описать реализацию в инклюде - следуйте соглашению java и хотя бы переменные описывайте до того, как они будут использованы в коде. Это логично и читатели кода будут вам за это благодарны.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-6848208744779303535?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/6848208744779303535/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=6848208744779303535' title='Комментарии: 9'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/6848208744779303535'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/6848208744779303535'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2010/08/blog-post_26.html' title='Допустимая публичность'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-4483118621078193948</id><published>2010-08-18T12:42:00.001+04:00</published><updated>2010-08-18T12:43:29.542+04:00</updated><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='VCS'/><title type='text'>Назад, в будущее...</title><content type='html'>Закоммитил не функционирующие изменения. Причем привык сразу делать hg push, чтобы не забыть это сделать позже. И только потом выяснил что все сломалось, надо выкинуть эти изменения и начать сначала. Но меркуриал немного разочаровал. &lt;br /&gt;&lt;br /&gt;hg rollback можно делать только один раз и только до того как ты сделал push, при этом ревизия совершенно исчезает.&lt;br /&gt;&lt;br /&gt;hg backout позволяет сделать откат, при этом добавляя еще одну ревизию.&lt;br /&gt;&lt;br /&gt;Записал в дневнике: &lt;i&gt;Достаточно переместить хед на одну ревизию назад и дальше пойти уже от нее. Тот хед - пусть болтается как тупиковая ветвь. Вполне естественно. Хотя может быть я что-то не понимаю.&lt;/i&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Чуть позже я понял, что я не понимаю. Если ревизия удалена от tip - то меркуриал формирует backout changeset на него. Но при этом получается, что Все ревизии, которые находятся между bad и tip - содерждат ошибку.&lt;br /&gt;&lt;br /&gt;Я не возражаю против того, что репозиторий должен содержать всю историю. Пусть содержит. Только нет необходимости замусоривать основную ветку. Ломающие ревизии должны быть исключены из основной ветки, пусть догнивают в боковых ветвях.&lt;br /&gt;&lt;br /&gt;С последней ревизией все просто, ее стоит просто вывести в отдельную ветвь и забыть.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://blin.exler.ru/articles/scifimovies/bttf01.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://blin.exler.ru/articles/scifimovies/bttf01.jpg" /&gt;&lt;/a&gt;Несколько сложнее ситуация, когда плохая ревизия содержится где-то в недрах истории. Исключая ревизию из истории мы должны все последующие изменения корректно наложить. Если какие-то последующие изменения пересекались с ломающей ревизией - тут возникает пространственно временной парадокс, который необходимо ресолвить. После всего этого у нас получается новая ветка реальности, которая не содержит ломающей ревизии вообще. В то время как сломанная ветка остается догнивать на свалке истории.&lt;br /&gt;&lt;br /&gt;Тем самым можно добиться того, что любая ревизия из основной ветки - заведомо работоспособна.&lt;br /&gt;&lt;br /&gt;PS: Не знаю точно, умеет ли так делать git, не дружу я с ним.&lt;br /&gt;&lt;br /&gt;PPS: Когда нибудь, может быть, я напишу свою систему контроля версий. :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-4483118621078193948?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/4483118621078193948/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=4483118621078193948' title='Комментарии: 9'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/4483118621078193948'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/4483118621078193948'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2010/08/blog-post_18.html' title='Назад, в будущее...'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-550603087943135155</id><published>2010-08-16T15:18:00.000+04:00</published><updated>2010-08-16T15:18:43.646+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='мысли'/><category scheme='http://www.blogger.com/atom/ns#' term='идеи'/><title type='text'>Из песни слова не выкинешь</title><content type='html'>... Но их можно легко забыть.&lt;br /&gt;&lt;br /&gt;Последнее время я очень редко беру в руки гитару. А когда беру - выясняется, что те песни которые пою я, не очень то интересуют ту аудиторию, перед которой я взял гитару в руки. Моя, достаточно толстая, папка с аккордами не содержит ни одной интересной для них песни.&lt;br /&gt;&lt;br /&gt;И вот я подумал, чтобы не лазить каждый раз по интернету в поисках нужной песни, все песни нужно собрать в одну базу данных!&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Естественно пополнять базу данных нужно автоматически, это могла бы быть даже онлайн база данных, но с таким расчетом, чтобы по названию песни пользователь мобильных устройств мог бы получить текст, аккорды, мелодию или даже полную песню. Конечно такое есть. В интернете таких сайтов полно, забитые баннерами и рекламами. И после нахождения нужной песни обнаруживаешь, что аккордов нету...&lt;br /&gt;&lt;br /&gt;Хотя я давно не интересовался данной темой, может быть сейчас мир изменился к лучшему. С другой стороны если я изложу свои мысли на этот счет - мир может стать еще лучше. :)&lt;br /&gt;&lt;br /&gt;А мысли у меня, как обычно, о программировании. Задача встала нетривиальная - необходимо отличить песню от не песни. :)&lt;br /&gt;&lt;br /&gt;Поскольку нас интересуют аккорды - можно с одной стороны сканировать интернет в поисках аккордов. А уже потом анализировать текст на предмет похожести его на песню.&lt;br /&gt;&lt;br /&gt;Что же касается анализа теста, то текст должен быть в первую очередь стихом. &lt;i&gt;Очень спорный момент, ведь этим мы выводим из рассмотрения всяческую попсу, кого нибудь интересуют аккорды попсы?&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Стих можно определить по стихотворному размеру и по рифме.&lt;br /&gt;&lt;br /&gt;Для определения стихотворного размера необходимо поделить текст на слоги и определить ударные и безударные из них. Возможны неточные попадания в размер, здесь мы вероятно имеем плавающую характеристику - более или менее похож на стих по стихотворному размеру.&lt;br /&gt;&lt;br /&gt;С рифмой все не менее сложно. Рифмоваться могут разные части строк, можно рассмотреть наиболее типичные (концы или середины строк). Кроме того проблема в том, что понятие рифмы очень расплывчато. Для рифмы иногда не обязательно даже совпадение концов слов, вернее, оно может совпадать в произношении, но различаться в написании. То есть мы опять имеем весьма нечеткую характеристику.&lt;br /&gt;&lt;br /&gt;Вернемся снова к песням. Иногда у песен есть припевы! Повторяющиеся фрагменты стихотворного текста можно определять как припевы.&lt;br /&gt;&lt;br /&gt;Для полноты картины осталось только определить исполнителя, год, всякие другие метаданные, которые могут использоваться для поиска. Здесь пока мыслей особо нету.&lt;br /&gt;&lt;br /&gt;Это все пока идея, времени у меня пока на нее нету, но может быть, когда нибудь. Если кому-то интересно до такой степени, чтобы заняться этим - пишите. Я буду рад, если такое приложение появится. Естественно это должно быть приложение для мобильных платформ, счастливым обладателем которой я пока не являюсь, но уже хочу.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-550603087943135155?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/550603087943135155/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=550603087943135155' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/550603087943135155'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/550603087943135155'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2010/08/blog-post.html' title='Из песни слова не выкинешь'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-4883527864572022618</id><published>2010-07-28T16:03:00.000+04:00</published><updated>2010-07-28T16:03:49.419+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VCS'/><category scheme='http://www.blogger.com/atom/ns#' term='git'/><category scheme='http://www.blogger.com/atom/ns#' term='subversion'/><title type='text'>Человеческое лицо subversion - 2</title><content type='html'>Git очень плохо дружит с proxy. Его можно заставить работать с прокси, но после этого git-svn все равно валится по сигналам после каждой ревизии.&lt;br /&gt;&lt;br /&gt;В связи с вышесказанным извлечь FreeBSD на работе не получилось, поэтому эксперименты спокойно буду проводить дома.&lt;br /&gt;&lt;br /&gt;Итак, продолжение эксперимента...&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Сам я не пользуюсь git. Одно время пытался использовать его но что-то так и не сдружился с его патчеобразной логикой, и с тех пор как-то не дружу с ним.&lt;br /&gt;&lt;br /&gt;Git, в отличии от предыдущего конкурсанта, прекрасно восстанавливается после clone. Так что начинать можно с простого клонирования.&lt;br /&gt;&lt;pre&gt;git svn clone http://svn.freebsd.org/base --trunk head FreeBSD-git&lt;/pre&gt;После прерывания этот процесс можно продолжить с помощью команды:&lt;br /&gt;&lt;pre&gt;git svn fetch&lt;/pre&gt;В процессе скачивания git, видимо, не обеспечивает работоспособности копии. log посмотреть нельзя.&lt;br /&gt;&lt;br /&gt;Занял этот процесс у меня 5 дней с перерывами, 47 часов чистого времени приблизительно.&lt;br /&gt;Размер базы после &lt;code&gt;git gc&lt;/code&gt; - 550MiB.&lt;br /&gt;&lt;br /&gt;Как и ожидалось - git по скорости всех (собственно mercurial) рвет. Да и по объему немного надрывает...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-4883527864572022618?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/4883527864572022618/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=4883527864572022618' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/4883527864572022618'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/4883527864572022618'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2010/07/subversion-2.html' title='Человеческое лицо subversion - 2'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-7873508928966198723</id><published>2010-07-02T14:15:00.059+04:00</published><updated>2010-07-05T15:15:32.074+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mercurial'/><category scheme='http://www.blogger.com/atom/ns#' term='VCS'/><category scheme='http://www.blogger.com/atom/ns#' term='git'/><category scheme='http://www.blogger.com/atom/ns#' term='subversion'/><title type='text'>Человеческое лицо Subversion</title><content type='html'>Людям, поработавшим с децентрализованными системами контроля версий, нет необходимости перечислять все вкусности - которые они дают. Но, к сожалению, в сети много проектов, которые используют морально устаревшие централизованные системы контроля. Ладно бы еще subversion, но до сих пор нередко использование cvs.&lt;br /&gt;&lt;br /&gt;И вот я, как настоящий джедай, решил затянуть к себе историю развития FreeBSD... Мне важна не сама история, больше всего меня интересует новейшая история, но все DVCS, по моим сведениям, не умеют вытягивать историю частично.&lt;br /&gt;&lt;br /&gt;Тащить стабильные ветки - совершенно неинформативно, Весь чейнджлог содержит только собщения о мердже. Следовательно надо тащить к себе транк, который в репозитории FreeBSD традиционно по cvs'овски называется HEAD.&lt;br /&gt;&lt;br /&gt;Проблема в том что история FreeBSD - богатая, 200 тысяч ревизий. И как выяснилось, не всякая DVCS долетит до середины репозитория FreeBSD. Решил немного сравнить mercurial и git в этом плане.&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;b&gt;Mercurial&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Для Меркуриала я использую рекоммендуемое расширение hgsubversion.&lt;br /&gt;&lt;br /&gt;Самый простой путь - &lt;code&gt;hg clone svn+http://svn.freebsd.org/base/head&lt;/code&gt; очень легко может не сработать. Одна ошибка и Mercurial прерывает свое выполнение, не забыв при этом стереть все скачанное непосильным трудом.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Блин, зачем же я три часа тяну &lt;code&gt;svn+http://svn.freebsd.org/base&lt;/code&gt;?&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Лучше сделать hg init, потом добавить в .hg/hgrc default path:&lt;br /&gt;&lt;pre&gt;[paths]&lt;br /&gt;default = svn+http://svn.freebsd.org/base/head/&lt;/pre&gt;А после чего, спокойно, можно делать hg pull. В случае ошибок дальнейший пуллинг будет продолжаться с последней скачанной ревизии.&lt;br /&gt;&lt;br /&gt;... прошло 5 часов.&lt;br /&gt;Проблема еще в том что этот процесс продолжается ужасно много времени. Пока дошел до 13500/209640. До конца осталось примерно 55 часов... подождем...&lt;br /&gt;&lt;br /&gt;... прошло 30 часов.&lt;br /&gt;90800/209640. До конца осталось примерно столько же.&lt;br /&gt;&lt;br /&gt;... Прошло 55 часов.&lt;br /&gt;148054/209640&lt;br /&gt;&lt;br /&gt;... Прошло 75 часов, опять аборт.&lt;br /&gt;202063/209640&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;pulling from svn+http://svn.freebsd.org/base/head/&lt;br /&gt;[r202063] imp: Cope with the move and if_timer going way.&lt;br /&gt;abort: sys/mips/cavium/dev/rgmii/octeon_fau.c@2ef2ef595899: not found in manifest!&lt;/pre&gt;&lt;br /&gt;Ан нет, вру... необходимо указать опцию --stupid для команды pull. При этом меркуриал, похоже, извлекает весь срез целиком, и потом уже строит дельты. Ведь не зря он пишет после каждой ревизии: &lt;code&gt;Fetching entire revision: branch creation with mods.&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;И вот наконец этот процесс завершился, заняв приблизительно 76 часов чистого времени.&lt;br /&gt;Полученная история FreeBSD насчитывает ~150000 ревизий, за период с 1993 года.&lt;br /&gt;И все это заняло на диске 767 MiB базы данных.&lt;br /&gt;Само дерево насчитывает ~45.5 тысяч файлов и занимает объем 603 MiB.&lt;br /&gt;Какой объем данных был выкачан при этом по сети - я затрудняюсь предположить, наверное несколько гигабайт.&lt;br /&gt;&lt;br /&gt;Главное, что стоит запомнить:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Не используйте команду clone, init/pull значительно надежнее.&lt;/li&gt;&lt;li&gt;Некоторые ревизии вызывают ошибки, которые можно обойти путем указания для pull опции --stupid.&lt;/li&gt;&lt;li&gt;Но не надо скачивать все с указанием опции --stupid, это потребует значительно больше времени и трафика.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;Git&lt;/b&gt;&lt;br /&gt;Должен справиться с этим часов за 50, но с этим экспериментом я пожалуй повременю, через три недели вернусь из отпуска - проверю.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-7873508928966198723?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/7873508928966198723/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=7873508928966198723' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/7873508928966198723'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/7873508928966198723'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2010/07/subversion.html' title='Человеческое лицо Subversion'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-3220517350725343304</id><published>2010-06-25T17:05:00.000+04:00</published><updated>2010-06-25T17:05:18.952+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='мысли'/><title type='text'>Операторные скобки, египетские и не очень</title><content type='html'>У нас в проекте не существует Coding Style. Это конечно плохо, но тут вопрос программистского самосознания о том, что считать правильным, а что никогда не применять, потому что плохо.&lt;br /&gt;&lt;br /&gt;Вот один из свежих конфликтов связан с операторными скобками для функций. &lt;br /&gt;&lt;br /&gt;В коде я предпочитаю использовать &lt;a href="http://m.habrahabr.ru/post/96978/"&gt;египетские скобки&lt;/a&gt;, потому что они экономят размер кода по вертикали. Это ведь не справедливо, что стандартный экран имеет 80 символов в ширину и только 25 строк по высоте. :) 80 символов мне хватает почти всегда.&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Проблема заключается в следующем:&lt;br /&gt;&lt;pre&gt;1: void hello()&lt;br /&gt;{&lt;br /&gt; printf("hello world\n");&lt;br /&gt;}&lt;/pre&gt;Можно так:&lt;br /&gt;&lt;pre&gt;2: void hello() {&lt;br /&gt; printf("hello world\n");&lt;br /&gt;}&lt;/pre&gt;А можно даже так (только c++)&lt;br /&gt;&lt;pre&gt;3: void hello() try {&lt;br /&gt; printf("hello world\n");&lt;br /&gt;} catch(...) {&lt;br /&gt; ...&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Последний вариант конечно экономит один уровень табуляции в каждой строке функции, но помоему является достаточно бесполезной фичей, за исключением конструкторов классов, в которых он позволяет обработать исключения при инициализации. Только там его и следует использовать. Использование исключений - вообще является спорным моментом, в &lt;a href="http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml"&gt;стандарте кодирования Googlе&lt;/a&gt; они, например, вообще запрещены, чего не одобряю. Исключения, по моему мнению, очень мощная вещь. Но, как и любой другой очень мощной вещью, пользоваться ими надо осторожно и умеренно. При осторожном и умеренном использовании не возникает никакой необходимости обрабатывать исключения в каждой функции, и такая проблема - как лишняя табуляция от блока try - стоять вообще не должна.&lt;br /&gt;&lt;br /&gt;Но я отвлекся. Вернемся к вариантам 1 и 2. Я долгое время объяснял свою приверженность варианту 1 тем, что прототип функции - понятие достаточно растяжимое, чтобы захламлять эту строку вещами,  к ней не относящимися. Так же я поступаю например с блоками if, в том случае если условие достаточно сложное и скобка после условия не достаточно видна.&lt;br /&gt;&lt;br /&gt;Но недавно меня осенило очень простое объяснение. Суть в том, что &lt;code&gt;void hello()&lt;/code&gt;  - это прототип, а &lt;code&gt;{ printf("hello world\n"); }&lt;/code&gt; - это тело. Если прототип у нас находится отдельно от тела - мы легко можем скопировать строку и вставить ее во включаемый файл. Нам будет необходимо лишь добавить точку с запятой. Если же мы будем захламлять строку прототипа дополнительными конструкциями типа  'try' и '{', то мы лишимся такой удобной возможности просто скопировать в случае, например, изменения списка параметров.&lt;br /&gt;&lt;br /&gt;Остается еще захламление строки прототипа неймспейсами и именами классов, но тут уж ничего не поделаешь. Надо с этим как-то жить.&lt;br /&gt;&lt;br /&gt;Мой кодинг стайл: обычные скобки для функций, египетские для логики.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-3220517350725343304?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/3220517350725343304/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=3220517350725343304' title='Комментарии: 8'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/3220517350725343304'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/3220517350725343304'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2010/06/blog-post_25.html' title='Операторные скобки, египетские и не очень'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-108025050877414691</id><published>2010-06-23T14:09:00.006+04:00</published><updated>2010-07-02T14:06:23.350+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='test'/><title type='text'>Фитнесс для питона</title><content type='html'>Однажды мы создалии для своего проекта на работе систему автоматизированного тестирования, которая могла бы в тестовых целях заменить нам программу управления. Система получилась тяжелая и плохо переносимая. Она была написана на перле, но в качестве транспортного уровня использовала код из продукта, который нормально собирается, по моему, только на 32-х битной FreeBSD. Транспортная библиотека из продукта с помощью swig была адаптирована для использования с perl. Кроме того на уровне perl по каждой функции существовала обертка...&lt;br /&gt;&lt;br /&gt;Чтобы добавить функцию в эту систему необходимо было расширить транспортный уровень, доработать swig интерфейс, доточить perl враппер, отладиить все это (что порою превращалось в весьма нетривиальную операцию)..&lt;br /&gt;&lt;br /&gt;Я уже знал в то время про &lt;a href="http://fitnesse.org/"&gt;FitNesse&lt;/a&gt;, и мне думалось, что неплохо было бы через wiki интерфейс управлять системой. Но связать все это вместе было достаточно нетривиально. Сам я на FreeBSD не сижу, а тестовое приложение не сидит на моей системе... А на той фре, на которой сидит тестовое приложение нет в помине никакой java, так нужной фитнессу.&lt;br /&gt;&lt;br /&gt;Это все была присказка, переходим к сказке...&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Поскольку собрать настроить и запустить систему тестирования было делом весьма неординарным, не удивительно, что никто ею и не пользовался.&lt;br /&gt;&lt;br /&gt;С подачи Блейза, я тем временем заинтересовался питоном. Кроме того сам он сгенерировал набор классов транспортного уровня на чистом питоне. И я подумал что пора вдохнуть в систему тестирования новую жизнь. Мне понравилось, и я подумал еще и о том, что применение чистого python открывает широчайшие возможности в применении системы, в частности ее можно запустить на Windows. А так же, оценивая широчайшие возможности, я вспомнил про FitNesse, и решил что это  хорошая возможность попробовать этого зверя в действии.&lt;br /&gt;&lt;br /&gt;Установить FitNesse не просто, а очень просто... Скачиваем с сайта java приложение, в свободном каталоге, где фитнесс будет складывать свои файлы, запускаем.&lt;br /&gt;&lt;pre&gt;$ java -jar fitnesse.jar -p 8000&lt;/pre&gt;&lt;i&gt;Порт лучше указать, потому что по умолчанию он захочет использовать порт 80, для использования которого требуются права администратора.&lt;/i&gt;&lt;br /&gt;После этого берем броузер и открываем &lt;a href="http://localhost:8000/"&gt;http://localhost:8000/&lt;/a&gt;. Фитнесс запущен и готов к работе, авторизации по умолчанию он не требует.&lt;br /&gt;&lt;br /&gt;Теперь переходим к питону. Поскольку вся система изначально разрабатывалась для java, она полностью пропитана java-терминологией. В частности путь к модулям традиционно для джавы называется CLASSPATH. Но давайте попорядку.&lt;br /&gt;&lt;br /&gt;FitNesse родился на основе технологии FIT, которая подразумевает хранение сценариев в обычных файлах. Задачей FitNess'а был запуск FIT с указанием конкретных сценариев для выполнения. Но этот механизм был пересмотрен, в результате чего родилась технология SLIM. Отличие от FIT состоит в том, что SLIM сервер взаимодействует с сервером FitNesse через сокет. Как утверждается на сайте это позволяет избежать каких-то лицензионных ограничений, я в лицензиях не силен. Но с другой стороны понятно, что возможности у такого взаимодействия шире. &lt;br /&gt;&lt;br /&gt;Итак мы собираемся использовать SLIM. Для тестирования python модулей нам нужен питоновый SLIM. Который называется &lt;a href="http://pypi.python.org/pypi/waferslim"&gt;waferslim&lt;/a&gt;. Его достаточно распаковать в любое место, при этом просто придется дополнительно указать дополнительный путь к модулям. Но проще установить его в систему, тогда он будет доступен по умолчанию. В своей Gentoo я для этого создал специальный ebuild.&lt;br /&gt;&lt;br /&gt;Теперь переходим к конфигурированию FitNesse. Поскольку я пока не собираюсь смешивать языки - я настраиваю его централизованно. Это делается через &lt;a href="http://localhost:8000/root"&gt;http://localhost:8000/root&lt;/a&gt;. Там необходимо прописать примерно следующее:&lt;br /&gt;&lt;pre&gt;!define TEST_SYSTEM {slim}&lt;br /&gt;!define CLASSPATH_PROPERTY {PYTHONPATH}&lt;br /&gt;!define COMMAND_PATTERN {python2 -m waferslim.server}&lt;/pre&gt;Далее мы погружаемся в изучение wiki синтаксиса и формата SLIM таблиц. Методика тестирования кода через FitNesse подразумевает очень конкретное разделение функций. Проще всего когда каждая функция принимает только один параметр или возвращает его. Хотя через Script таблицу можно использовать достаточно произвольный код, но decision таблицы выглядят попроще.&lt;br /&gt;&lt;br /&gt;Для адаптации своего кода к возможностям FitNesse можно использовать специально заточенные классы фикстур.&lt;br /&gt;&lt;br /&gt;Небольшой пример теста:&lt;br /&gt;&lt;pre&gt;!path /home/dron/prog&lt;br /&gt;&lt;br /&gt;|import|&lt;br /&gt;|fixture|&lt;br /&gt;&lt;br /&gt;!|fixture.Config|&lt;br /&gt;|name|getName?|&lt;br /&gt;|test|test|&lt;br /&gt;|changed|changed|&lt;/pre&gt;После нажатия на кнопку Test, FitNesse запускает SLIM сервер, который подключается к FitNesse серверу по указанному адресу и порту и начинают свой тестовый диалог. В процессе этого диалока он подгружает тестируемые мной модули и выполняет записанный в таблицах сценарий. Результаты (зеленое/красное - хорошо/плохо) сразу же отображаются в окне броузера.&lt;br /&gt;&lt;br /&gt;На этом пожалуй все. Может быть я не раскрыл свои постом всех тайн FitNesse, я их и сам не знаю. :) Единственное, что стоит понимать - это то, что тестирование через FitNesse вовсе не отменяет юниттестирования. Во первых, тесты FitNesse хранятся в стороне от кода. Их, по моему, не очень удобно, хотя и можно, грузить в SVC. Кроме того их не очень удобно запускать в автоматическом режиме. К ним можно относиться как к высокоуровневым функциональным тестам, которые обеспечивают удобный интерактив. У меня например FitNesse тесты во всю дергают подопытный сервер, и это, в отличии от юниттестов, удобно.&lt;br /&gt;&lt;br /&gt;PS: Может быть мне замутить скринкаст? Никогда не пробовал.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-108025050877414691?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/108025050877414691/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=108025050877414691' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/108025050877414691'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/108025050877414691'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2010/06/blog-post.html' title='Фитнесс для питона'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-3237731922198722108</id><published>2010-05-28T14:08:00.002+04:00</published><updated>2010-07-02T12:56:17.333+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='boost'/><category scheme='http://www.blogger.com/atom/ns#' term='test'/><title type='text'>Boost data-driven test</title><content type='html'>Возникла необходимость проверить работу алгоритма на нескольких исходных данных. Поступил сигнал, что сервер не читает базы данных предыдущих версий. Сервер у нас пока сильно разобран, так что он может. Надо бы это дело потестировать юниттестами. Собрали базы данных разных версий, файлы Berkley DB по сути своей они.&lt;br /&gt;&lt;br /&gt;Да, я знаю что тестировать файлы а уж тем более базы данных - некошерно, но лучше иметь такие тесты, чем не иметь никаких. &lt;br /&gt;&lt;br /&gt;Итак поехали...&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Сперва это выливается в энное количество тестов следующего вида:&lt;br /&gt;&lt;pre&gt;BOOST_AUTO_TEST_CASE(import_3_database)&lt;br /&gt;{&lt;br /&gt;  BOOST_REQUIRE_EQUAL(DbProxy("bakup-3.db").getServerVersion(), 3);&lt;br /&gt;  BOOST_REQUIRE_NO_THROW(DbProxy("bakup-3.db").dbConvert());&lt;br /&gt;}&lt;/pre&gt;Очень однообразных, и немного более навороченных, тестов... &lt;br /&gt;&lt;br /&gt;Здесь надо применить Custom assertion! В результате чего мы получаем меньше кода, но однообразия меньше не становится:&lt;br /&gt;&lt;pre&gt;BOOST_AUTO_TEST_CASE(import_3_database)&lt;br /&gt;{&lt;br /&gt;  CSTOM_REQUIRE_CONVERT("bakup-3.db", 3);&lt;br /&gt;}&lt;/pre&gt;Но зато становится ясно, что все, что различает наши тесты между собой - это имя файла и номер версии. Значит необходимо сделать из всего этого управляемый данными тест. Но поскольку это достаточно редкая техника, в boost она слабо развита.&lt;br /&gt;&lt;br /&gt;Можно было бы написать так:&lt;br /&gt;&lt;pre&gt;BOOST_AUTO_TEST_CASE(import_database)&lt;br /&gt;{&lt;br /&gt;  CUSTOM_REQUIRE_CONVERT("bakup-3.db", 3);&lt;br /&gt;  CUSTOM_REQUIRE_CONVERT("bakup-4.db", 4);&lt;br /&gt;  ...&lt;br /&gt;}&lt;/pre&gt;Но это было бы ошибкой, которая заключается в том, что ошибка в первом тесте автоматически приведет к невыполнению всех последующий. Можно было бы использовать CHECK вместо REQUIRE, но я предпочитаю REQUIRE и не ищу легких путей. Предпочитаю правильные пути...&lt;br /&gt;&lt;br /&gt;Есть в boost штука, которая называется BOOST_PARAM_TEST_CASE. Это генератор (как у меня блин питоновая терминология прет), который по функции и паре итераторов генерирует тестовый набор. Но есть несколько проблем. &lt;br /&gt;&lt;br /&gt;Во первых тестовая функция принимает только один параметр - значение из текущего итератора, следовательно прототип CUSTOM_REQUIRE_CONVERT нас уже не устраивает, потому что требует двух параметров. Можно упаковать два наших параметра в объект, но я для простоты взял std::pair.&lt;br /&gt;&lt;pre&gt;typedef pair&amp;lt;const char *, uint32_t&amp;gt; dbe;&lt;/pre&gt;Сформировав набор тестовых данных&lt;br /&gt;&lt;pre&gt;static dbe dba[] = {&lt;br /&gt; dbe("bakup-3.db", 3),&lt;br /&gt; dbe("bakup-4.db", 4),&lt;br /&gt; ...&lt;br /&gt;};&lt;/pre&gt;Мы можем получить из них тестовый набор&lt;br /&gt;&lt;pre&gt;BOOST_PARAM_TEST_CASE(testConversion, &lt;br /&gt; dba, dba + sizeof(dba) / sizeof(dbe))&lt;/pre&gt;Где testConversion, это собственно новая тестовая функция, которая пришла на замену CUSTOM_REQUIRE_CONVERT, и принимает &lt;code&gt;const dbe &amp;&lt;/code&gt; вместо пары значений.&lt;br /&gt;&lt;br /&gt;Но наличие тестового набора не дает нам ровным счетом ничего, пока мы не добавили его в главный тестовый набор. Честно скажу, подходящего макроса в BOOST TEST я не нашел. И чтобы не изобретать свой велосипед - начал рыться в чужом. Где выяснилось, что BOOST_AUTO_TEST_CASE для своей саморегистрации использует BOOST_AUTO_TU_REGISTRAR, который нам в чистом виде тоже не подходит, Но если порыть еще глубже, то мы можем докопаться до boost::unit_test::ut_detail::auto_test_unit_registrar, который в одном из своих конструкторов принимает в частности test_unit_generator const &amp;, который возвращается BOOST_PARAM_TEST_CASE.&lt;br /&gt;&lt;br /&gt;Попробуем все это объединить:&lt;br /&gt;&lt;pre&gt;static ut_detail::auto_test_unit_registrar registrar&lt;br /&gt; (BOOST_PARAM_TEST_CASE(testConversion, &lt;br /&gt;  dba, dba + sizeof(dba) / sizeof(dbe)));&lt;/pre&gt;&lt;br /&gt;И наступило почти счастье, каждый тесткейс запускается изолированно, Правда все они носят имя testConversion. Наверное индивидуальный их запуск будет затруднителен. Да, так и есть.&lt;br /&gt;&lt;pre&gt;./Runner --log_level=test_suite --run_test=*/testConversion                                                                                                   &lt;br /&gt;Running 6 test cases...&lt;br /&gt;...&lt;/pre&gt;Ну за все приходится платить. В данном случае мы получаем мало кода, что уже хорошо.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-3237731922198722108?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/3237731922198722108/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=3237731922198722108' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/3237731922198722108'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/3237731922198722108'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2010/05/boost-data-driven-test.html' title='Boost data-driven test'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-792819069543691609</id><published>2010-05-17T14:58:00.001+04:00</published><updated>2010-06-23T16:01:48.011+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='мысли'/><category scheme='http://www.blogger.com/atom/ns#' term='usability'/><category scheme='http://www.blogger.com/atom/ns#' term='идеи'/><title type='text'>Раскладка для телефона</title><content type='html'>Прочитал статью "&lt;a href="http://habrahabr.ru/blogs/ui_design_and_usability/92153/"&gt;Улучшенная раскладка для телефона&lt;/a&gt;", задумался...&lt;br /&gt;&lt;br /&gt;Основная проблема не T9 режима - это подряд идущие символы, которые приходятся на одну клавишу. Необходимо выжидать, чтобы текущий символ зафиксировался, чтобы можно было начать набирать новый.&lt;br /&gt;&lt;br /&gt;И тут меня осенило...&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Надо расположить буквы в соответствии с порядком их использования в словах!&lt;br /&gt;&lt;br /&gt;Возьмем для примера "Войну и мир", соберем статистику по буквам вообще и по рядом стоящим буквам. Нам не важно, какая буква идет раньше, а какая позже. Просто, если стоят рядом - они образуют пару, которую лучше располагать на разных клавишах телефона.&lt;br /&gt;&lt;br /&gt;Самые популярные буквы должны располагаться на первых позициях, это правило вступает в некоторый конфликт с правилом парности. Наиболее популярные в русском языке буквы - оаеи (именно в таком порядке). Их стоило бы поставить на первые позиции, если бы не тот факт что совместно они используются крайне редко. Но это требует проверочки.&lt;br /&gt;&lt;br /&gt;Для начала стоит попробовать расположить буквы по популярности а комбинировать по редкости:&lt;br /&gt;&lt;pre&gt;тмхщ ауц срчъ&lt;br /&gt;игж  оьы  нпш&lt;br /&gt;лдзф еяю вкбэ&lt;br /&gt;     _,.?&lt;br /&gt;&lt;/pre&gt;Выглядит конечно жестко. :)&lt;br /&gt;Да еще й и ё забыл.&lt;br /&gt;&lt;br /&gt;А если попробовать выбрать оптимальные варианты по парности...&lt;br /&gt;&lt;br /&gt;Для проверки мы возьмем словарь и будем проверять количество букв, которые попадают на одну и ту же кнопку.&lt;br /&gt;&lt;br /&gt;Целый выходные мой компьютер в 4 ядра выбирал оптимальную раскладку, так и не довыбирал до конца, но я думаю что она близка к оптимальной. Вот она:&lt;br /&gt;&lt;pre&gt;дбх  рмчз вкэф&lt;br /&gt;еиуъ оаьы нпжц&lt;br /&gt;сгшщ  тлё  яйю&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Стандартная раскладка с моего телефона дает 20% из ~160000 слов, которые можно набрать без пауз.&lt;br /&gt;Оптимизированная раскладка дает 72% слов, буквы в которых не пересекаются по кнопкам.&lt;br /&gt;&lt;br /&gt;Можно конечно посчитать среднее количество нажатий на кнопки, но помоему это неинтересная характеристика.&lt;br /&gt;&lt;br /&gt;Давайте лучше прикинем какое количество слов приходится на одну комбинацию кнопок T9? Но тут что-то странное получается. Среднее количество слов на комбинацию клавиш получается близким к 1, причем для моей супероптимальной раскладки больше, чем для стандартной. Может быть стоит оценить среднее число из некоторого количества максимальных комбинаций?&lt;br /&gt;&lt;br /&gt;Всеравно что-то странное получается. стандартная раскладка дает 94% уникальных комбинаций, в то время как моя, оптимизированная на уникальность, - всего лишь 91%... Подозрительно...&lt;br /&gt;&lt;br /&gt;PS: Проблему с T9 я потом еще обдумаю, пока стоит отложить эту ерунду... Чем я вообще занимаюсь?&lt;br /&gt;&lt;br /&gt;PPS: Еще подумал что вот железнодорожники раскрасили свои поезда в разные цвета, хотя для них это совершенно бесполезно, в то время как в метро все поезда одного цвета, хотя раскрасить поезда по цвету линий - было бы крайне полезно ИМХО. :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-792819069543691609?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/792819069543691609/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=792819069543691609' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/792819069543691609'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/792819069543691609'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2010/05/blog-post.html' title='Раскладка для телефона'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-629156243755534517</id><published>2010-04-27T15:12:00.001+04:00</published><updated>2010-06-23T16:02:13.560+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='kde'/><category scheme='http://www.blogger.com/atom/ns#' term='exherbo'/><title type='text'>libpthread-stubs.so.0 not found</title><content type='html'>Недавно, после очередного обновления, случилась поломка Exherbo. После обновления libpthread-stubs с версии 0.2 на версию 0.3 перестали загружаться в частности иксы. Ну я знал на что иду, когда ставил Exherbo, нас такими вещами не удивишь. &lt;br /&gt;&lt;br /&gt;Гораздо хуже было, когда, в 2006 в Gentoo сломался expat. Там ни одно приложение вообще не работало, в том числе и python, без которого житть не может emerge.&lt;br /&gt;&lt;br /&gt;Здесь - так, цветочки. Хотя reconcilio почему-то не хочет лечить ситуацию и спотыкается на первом же пакете.&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;div style="text-align: right;"&gt;Восемь ночей Айболит не ест не пьет и не спит,&lt;/div&gt;&lt;div style="text-align: right;"&gt;Восемь ночей подряд он лечит несчастных зверят&lt;/div&gt;&lt;br /&gt;Четыре дня я сидел без иксов. По одному пакетику пересобирая то, что можно пересобрать. До тех пор, пока все не пересобралось. (Надо сказать времени не очень много, по вечерам часочек выкроишь, и то хорошо.)&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: right;"&gt;Вот и вылечил он их, Лимпопо!&lt;/div&gt;&lt;br /&gt;Кроме того я наконец то созрел до того, чтобы попробовать что-то отличное от KDE. И накатил себе LXDE. Производительность пока радует. Отвращение к gtk я в себе подавил, пусть в конце концов будет что угодно, главное чтобы работать было удобно.&lt;br /&gt;&lt;br /&gt;Хотя в плане использования памяти про это забывать тоже не следует - нужно подбирать соответствующие приложения. :) Где бы мне найти редактор, который, как и Kate, имеет маркер статического переноса строк?&lt;br /&gt;&lt;br /&gt;Вообще человеку с устоявшимися привычками нужно сравнительно не много. Мой список необходимых приложений десктопных насчитывает 4 пункта. Собственно броузер, почта, аська (вполне вероятно что уйду полностью на джаббер, надоела мне аська) и удобный текстовый редактор без наворотов.&lt;br /&gt;&lt;br /&gt;А остальное все - время от времени. Там не столь уж важно - насколько они тормозят и жрут памяти.&lt;br /&gt;&lt;br /&gt;Пока попробую посидеть на LXDE - побалуюсь с разными приложениями. &lt;br /&gt;&lt;br /&gt;Насчет почты я вообще думаю что стоит настроить службу, которая бы вытягивала почту в локальный мейлбокс или еще куда. Тогда морда станет вообще несущественна. Мне кажется, это очень здравый подход - "бэкендовость". То есть, основную логику приложения необходимо строить независимо от используемых интерфейсов. Может быть как службу? Но нету в юниксе такого понятия.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-629156243755534517?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/629156243755534517/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=629156243755534517' title='Комментарии: 3'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/629156243755534517'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/629156243755534517'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2010/04/libpthread-stubsso0-not-found.html' title='libpthread-stubs.so.0 not found'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-7029524857863324457</id><published>2010-04-22T18:10:00.001+04:00</published><updated>2010-06-23T16:02:41.936+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><title type='text'>Более-менее...</title><content type='html'>Все таки мы неправильно как-то живем. Нашими интерфейсами руководят низменные железные ограничения. Вот например - часто в интерфейсах нас просят ввести 0, если ограничений не предполагается. Но, по моему 0 - это ноль, это совершенно не похоже на бесконечность. И если с точки зрения архитектуры удобно делить значения на нулевые и ненулевые, то с точки зрения интерфейса - это нелогично.&lt;br /&gt;&lt;br /&gt;И размышляя таким образом о физической природе чисел я дошел до стандартной библиотеки...&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;C++ конечно, язык со строгой типизацией - никуда не денешься.&lt;br /&gt;&lt;br /&gt;Сравнение знакового и беззнакового числа нелогично только с точки зрения ограниченности платформы. Мы знаем, что компилятор пытается привести числа к одному типу с чем испытывает многочисленные проблемы.&lt;br /&gt;&lt;br /&gt;Хотя с точки зрения математики int(-10) определенно меньше чем uint(10). А int(-2000000000) определенно меньше uint(3000000000). Почему же нам запрещают их сравнивать?&lt;br /&gt;&lt;br /&gt;То же самое касается min/max, которые вообще требуют строго одинаковых типов - негибко.&lt;br /&gt;Гибкость с типами позволяет, кроме того, гораздо шире трактовать понятие целое число.&lt;br /&gt;&lt;br /&gt;И это даже можно реализовать...&lt;br /&gt;Только почему-то наткнулся на странную фигню - компилятор говорит что нельзя реализовать шаблонный operator &lt; вне класса... Ну да ладно, продемонстрирую идею на примере minДля начала напишем тестик:&lt;pre&gt;BOOST_AUTO_TEST_CASE(minimal)&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;BOOST_REQUIRE_EQUAL(min(-10, 10), -10);&lt;br /&gt;&lt;br /&gt;BOOST_REQUIRE_EQUAL(min(-2000000000, 3000000000), -2000000000);&lt;br /&gt;&lt;br /&gt;BOOST_REQUIRE_EQUAL(min(3000000000, -2000000000), -2000000000);&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;Первая строка - вызывает стандартный min, Но последующие две строки под него никак не подходят.&lt;br /&gt;И тут вступает наша реализация:&lt;br /&gt;&lt;pre&gt;template&amp;lt;typename A, typename B&amp;gt;&lt;br /&gt;struct min_type_selector {&lt;br /&gt; typedef typename mpl::if_c&amp;lt;is_signed&amp;lt;A&amp;gt;::value,&lt;br /&gt;  typename mpl::if_c&amp;lt;is_signed&amp;lt;B&amp;gt;::value,&lt;br /&gt;   typename mpl::if_c&amp;lt;(sizeof(A) &amp;gt; sizeof(B)), A, B&amp;gt;::type, A&amp;gt;::type,&lt;br /&gt;  typename mpl::if_c&amp;lt;is_signed&amp;lt;B&amp;gt;::value,&lt;br /&gt;   B, typename mpl::if_c&amp;lt;(sizeof(A) &amp;gt; sizeof(B)), A, B&amp;gt;::type&amp;gt;::type&lt;br /&gt;  &amp;gt;::type type;&lt;br /&gt;&lt;br /&gt; // Переполнение результата может вызвать только беззнаковое значение,&lt;br /&gt; // По размеру не меньше резулььтата&lt;br /&gt; enum { b_can_overload = ((sizeof(B) &amp;gt;= sizeof(type) &amp;&amp; is_unsigned&amp;lt;B&amp;gt;::value)) };&lt;br /&gt; enum { a_can_overload = ((sizeof(A) &amp;gt;= sizeof(type) &amp;&amp; is_unsigned&amp;lt;A&amp;gt;::value)) };&lt;br /&gt;&lt;br /&gt; static type highest() { return numeric::bounds&amp;lt;type&amp;gt;::highest(); }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;template&amp;lt;typename A, typename B&amp;gt;&lt;br /&gt;typename min_type_selector&amp;lt;A, B&amp;gt;::type min(const A &amp;a, const B &amp;b) {&lt;br /&gt; typedef min_type_selector&amp;lt;A, B&amp;gt; TS;&lt;br /&gt; if (TS::b_can_overload &amp;&amp; b &amp;gt; numeric_cast&amp;lt;B&amp;gt;(TS::highest()))&lt;br /&gt;  return numeric_cast&amp;lt;typename TS::type&amp;gt;(a);&lt;br /&gt; if (TS::a_can_overload &amp;&amp; a &amp;gt; numeric_cast&amp;lt;A&amp;gt;(TS::highest()))&lt;br /&gt;  return numeric_cast&amp;lt;typename TS::type&amp;gt;(b);&lt;br /&gt; return min(numeric_cast&amp;lt;typename TS::type&amp;gt;(a), numeric_cast&amp;lt;typename TS::type&amp;gt;(b));&lt;br /&gt;}&lt;/pre&gt;Вот...&lt;br /&gt;&lt;br /&gt;Кому нужно сравнивать такие большие числа - не очень то понятно, но может быть это пригодиться для того, чтобы постоянно не приводить два сравниваемых числа к одному типу?&lt;br /&gt;&lt;br /&gt;А может и проще можно написать?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-7029524857863324457?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/7029524857863324457/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=7029524857863324457' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/7029524857863324457'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/7029524857863324457'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2010/04/blog-post_22.html' title='Более-менее...'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-279538187734230630</id><published>2010-04-13T11:24:00.003+04:00</published><updated>2010-04-13T11:53:59.858+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='хорошая практика'/><title type='text'>Больше предупреждений, хороший и разных</title><content type='html'>Хорошая практика программирования рекомендует включать максимум предупреждений компилятора и добиваться того, чтобы их не возникало в процессе компиляции. Заставить один C++ проект компилироваться без предупреждений достаточно легко. Но если в рамках одного проекта используются модули на C/C++ - все становится значительно интереснее.&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;Есть предупреждения, применимые только для C++ (например: &lt;code&gt;-Weffc++, -Woverloaded-virtual, -Wold-style-cast&lt;/code&gt;). Я не пробовал включать их для си, могу предположить, что последует ругань и правильно. А поскольку для C они не имеют смысла - в данном контексте они не интересны.&lt;br /&gt;&lt;br /&gt;Для обоих языков в первом приближении я отобрал три варнинга: &lt;code&gt;-Wsign-conversion -Wconversion -pedantic&lt;/code&gt;. Остановимся на них поподробнее.&lt;br /&gt;&lt;br /&gt;Начать стоит с того, что в си enum - всегда int.&lt;br /&gt;&lt;pre&gt;enum {&lt;br /&gt; TEST1 = 0x100000000ULL,&lt;br /&gt; TEST2 = 0xffffffffU,&lt;br /&gt; TEST3 = 0x7fffffff&lt;br /&gt;};&lt;br /&gt;$ gcc -c -std=c99 -pedantic test.c&lt;br /&gt;test.c:2: предупреждение: в ISO C значения перечислимого типа ограничены диапазоном типа ‘int’&lt;br /&gt;test.c:3: предупреждение: в ISO C значения перечислимого типа ограничены диапазоном типа ‘int’&lt;/pre&gt;Причем это справедливо и для amd64, в этом легко убедиться например так:&lt;br /&gt;&lt;pre&gt;BOOST_STATIC_ASSERT(sizeof(int) == 4);&lt;/pre&gt;В то же время в C++ с enum не возникает никаких проблем. В C++ тип enum есть собственно enum, даже знаковость которого определяется позже. Единственный возникающий в данной ситуации момент - стандарт C++ 99 года не любит определений ULL, считая их &lt;i&gt;C99 long long integer constant&lt;/i&gt;, Для C++ даже U писать не обязательно, главное, чтобы значение могло уместиться в long, то есть быть не больше 32-64 бит в зависимости от типа платформы.&lt;br /&gt;&lt;br /&gt;Это наводит на мысль, что переносимое приложение не должно использовать в enum значения больше 32 бит длиной.&lt;br /&gt;&lt;br /&gt;Значение &lt;code&gt;sizeof(TEST1)&lt;/code&gt; в С++ варьируется в зависимости от наполнения enum от 4 до 8.&lt;br /&gt;&lt;br /&gt;Другой интересный момент, справедливый для обоих языков:&lt;br /&gt;&lt;pre&gt;const unsigned int t1 = TEST1;&lt;br /&gt;const unsigned int t2 = 0;&lt;br /&gt;const unsigned int t3 = argc &gt; 1 ? TEST1 : 0;&lt;br /&gt;$ gcc -m64 -o test -std=c99 -Wsign-conversion test.c&lt;br /&gt;test.c:3: предупреждение: conversion to ‘unsigned int’ from ‘int’ may change the sign of the result&lt;/pre&gt;Ошибка возникает в третьей строке фрагмента, и лечится заменой 0, на 0U... Хотя тот же 0 во второй строке не вызывает проблем.&lt;br /&gt;&lt;br /&gt;И напоследок - ошибочная ситуация в gcc:&lt;br /&gt;При попытке присвоить битовому полю значение какой-то переменной практически всегда происходит ошибка, и обойти ее практически не представляется возможным.&lt;br /&gt;&lt;pre&gt;unsigned int x = 0x7f;&lt;br /&gt;struct {&lt;br /&gt; unsigned int a:7;&lt;br /&gt;} t = { .a = x };&lt;br /&gt;$ gcc -std=c99 -Wconversion test.c&lt;br /&gt;test.c:4: предупреждение: conversion to ‘unsigned char:7’ from ‘unsigned int’ may alter its value&lt;/pre&gt;Не существует способа привести переменную к битовому полю.&lt;br /&gt;&lt;br /&gt;В принципе я не вижу большой необходимости из кожи вон лезть, чтобы задушить любую ругань компилятора. Наша цель - обеспечить корректность кода. Ругань компилятора - это средство для привлечения внимания к подозрительным местам.&lt;br /&gt;&lt;br /&gt;Главное чтобы борьба за чистоту кода производилась с пониманием первопричин. Тупые приведения типов (через reinterpret_cast конечно) до добра еще никого не доводили. Даже если эта конструкция и находит применение в коде - она достаточно бросается в глаза и вызывает стойкое желание избавиться от нее. Но лучше оставить предупреждение, которое бросается в глаза еще сильнее.&lt;br /&gt;&lt;br /&gt;Можно предложить борцам на чистоту кода периодически устраивать параноидальные проверки с большим количеством опций, которые, возможно, не удастся расчистить целиком. А в обычные дни обходится более скромным подмножеством опций, но при этом обязательно используя -Werror. :)&lt;br /&gt;&lt;br /&gt;PS: Интересное на этом конечно же не заканчивается - это лишь первый взгляд. Может быть последует продолжение, если будет не лень, совсем я что-то забыл про блог.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-279538187734230630?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/279538187734230630/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=279538187734230630' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/279538187734230630'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/279538187734230630'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2010/04/blog-post.html' title='Больше предупреждений, хороший и разных'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-8663847533672661676</id><published>2010-02-05T15:27:00.001+03:00</published><updated>2010-07-02T11:46:22.574+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mercurial'/><category scheme='http://www.blogger.com/atom/ns#' term='gentoo'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>Mercurial сервер</title><content type='html'>Стоит у меня под столом UltraSPARC5. Машина старая, валялась без дела. А я давний любитель всего экзотического решил приобщить ее для общественной пользы.&lt;br /&gt;&lt;br /&gt;Залил туда Gentoo, поставил вебсервер, mediawiki, ejabberd... Хотел поставить Google Wave, но в то время он был еще сырой, и не работал. Да и java на спарк не встает, во всяком случае у Gentoo не встает.&lt;br /&gt;&lt;br /&gt;И тут, недавно, меня посетила еще одна мысль. Подниму ка я там scm сервер. Это позволит хранить отдельно всякие вне проектные рабочие разработки. Лишняя копия, как говорится, никогда не бывает лишней. Эта, пусть слабенькая, машинка прекрасно с справится с этой задачей.&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;Пусть простят меня поклонники Линуса Торвальдса - git мне никогда не нравился, хотя мне приходилось им пользоваться. На данный момент мне нравится Mercurial.&lt;br /&gt;&lt;br /&gt;Согласно &lt;a href="http://www.opennet.ru/base/dev/mercural_cms_install.txt.html"&gt;этой инструкции&lt;/a&gt; мы настраиваем пользователя и наслаждаемся репозиторием через ssh.&lt;br /&gt;&lt;br /&gt;Борьба с вебмордой неожиданно затянулась. Хоть для меня скорость и не является решающим фактором - я старательно следовал инструкциям по настройке fastcgi, но добился лишь того, что я могу ходить на сервер от корня (от http://.../hg), но попытка ввести что нибудь после /hg неизменно приводит к проблемам. Сервер перенаправляет /hg на /hg.fcgi и других запросов упорно не хочет принимать. Ну не писать же везде /hg.fcgi/blablabla... лишнее.&lt;br /&gt;&lt;br /&gt;А поскольку скорость не является для меня решающим фактором - я в конце концов нашел &lt;a href="http://mercurial.selenic.com/wiki/HgWebDirStepByStep#Configuring_lighttpd"&gt;официальную инструкцию по настройке cgi под lighttpd&lt;/a&gt;. Она попроще и после нее все работает почти сразу.&lt;br /&gt;&lt;br /&gt;Для коммитоов https не нужен, настроим авторизацию на пуш согласно той же официальной инструкции.&lt;br /&gt;&lt;br /&gt;Но возникла проблема. htpasswd - является частью апача и в комплект lighttpd не входит. Ну не ставить же апач ради такой фигни? Значит можно выбрать другой метод авторизации. Меня бы устроила встроенная авторизация на основе /etc/passwd, но так lighttpd кажется не умеет. &lt;a href="http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ModAuth"&gt;Здесь&lt;/a&gt; описаны возможность mod_auth. Генерируем /home/scm/.htdigest с его помощью.&lt;br /&gt;&lt;pre&gt;$HTTP["querystring"] =~ "cmd=unbundle" {&lt;br /&gt;        auth.require = (   "" =&gt; (&lt;br /&gt;                "method"  =&gt; "digest",&lt;br /&gt;                "realm"   =&gt; "Mercurial repo",&lt;br /&gt;                "require" =&gt; "valid-user"&lt;br /&gt;        ))&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;auth.backend = "htdigest"&lt;br /&gt;auth.backend.htdigest.userfile = "/home/scm/.htdigest"&lt;/pre&gt;Но этого недостаточно. Нужно еще в конкретном репозитории разрешить не-ssl пушинг, и прописать юзеров, которые могут это делать.&lt;br /&gt;&lt;pre&gt;scm@sparc ~/hg/xap/.hg $ cat hgrc&lt;br /&gt;[web]&lt;br /&gt;push_ssl = false&lt;br /&gt;allow_push = dron&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Теперь можно проверить... (я конечно и в процессе неоднократно проверял, сейчас финальный тест)&lt;br /&gt;&lt;pre&gt;$ hg clone http://10.4.2.91/hg/xap&lt;br /&gt;...&lt;br /&gt;10 files updated, 0 files merged, 0 files removed, 0 files unresolved&lt;br /&gt;$ cd xap&lt;br /&gt;$ echo "Ридми я до сих пор не написал" &gt; readme.txt&lt;br /&gt;$ hg add readme.txt&lt;br /&gt;$ hg commit -m "Тестовый коммит"&lt;br /&gt;$ hg push&lt;br /&gt;pushing to http://10.4.2.91/hg/xap&lt;br /&gt;searching for changes&lt;br /&gt;http authorization required&lt;br /&gt;realm: Mercurial repo&lt;br /&gt;user: dron@infosec.ru&lt;br /&gt;password:&lt;br /&gt;abort: authorization failed&lt;/pre&gt;Тудыть ее... А, забыл lighttpd перезагрузить...&lt;br /&gt;&lt;pre&gt;...&lt;br /&gt;user: dron&lt;br /&gt;password:&lt;br /&gt;abort: HTTP Error 500: Internal Server Error&lt;/pre&gt;Доступа чтоль не хватает? &lt;pre&gt;$ cd /home/scm/hg; chmod -R g+w *&lt;/pre&gt;(Пользователь lighttpd у нас включен в группу scm). А вот и нет... недостаточно... только &lt;pre&gt;$ cd /home/scm/hg; chown -R lighttpd:lighttpd *&lt;/pre&gt;спас сервер. Не понятно. Везде для групп стоит rw, для каталогов - rwx. Но установка одной группы в lighttpd не спасает положение.&lt;br /&gt;&lt;br /&gt;Теперь мне совсем не ясно - зачем я заводил юзера scm? Хотя может быть для fcgi (с отдельной службой, вероятно работающей от имени scm) это и было нужно. Но пусть пока будет так.&lt;br /&gt;&lt;br /&gt;Остались несколько проблем, и https не самая большая из них. Вот самая большая:&lt;br /&gt;&lt;pre&gt;$ hg push&lt;br /&gt;...&lt;br /&gt;user: dron@infosec.ru&lt;br /&gt;password:&lt;br /&gt;abort: authorization failed&lt;br /&gt;$ hg push&lt;br /&gt;...&lt;br /&gt;user: dron&lt;br /&gt;password:&lt;br /&gt;adding changesets&lt;br /&gt;add changeset a63be34dcf21&lt;br /&gt;adding manifests&lt;br /&gt;adding file changes&lt;br /&gt;adding readme.txt revisions&lt;br /&gt;added 1 changesets with 1 changes to 1 files&lt;br /&gt;updating the branch cache&lt;/pre&gt;Вот так, dron в качестве имени - воспринимает, а dron@infosec.ru - нет. Вероятно проблема где-то mod_auth, потому что не сходится авторизация. И что с этим делать?..&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-8663847533672661676?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/8663847533672661676/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=8663847533672661676' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/8663847533672661676'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/8663847533672661676'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2010/02/mercurial.html' title='Mercurial сервер'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-8234357041265267427</id><published>2010-01-21T14:26:00.004+03:00</published><updated>2010-01-21T14:32:49.771+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ошибки'/><title type='text'>Сбербанк жжет</title><content type='html'>В принципе, я представляю себе что такое сертификат. Но был вот намедне в сбербанке, где получил следующий чек:&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_eOHzlCMDZZM/S1g4PAVGmPI/AAAAAAAAAJI/0USpRc13dbM/s1600-h/sberbank" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_eOHzlCMDZZM/S1g4PAVGmPI/AAAAAAAAAJI/0USpRc13dbM/s320/sberbank" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;Тогда у меня еще промелькнула мысль, что где-то я это уже видел. Вспомнил! То же самое я наблюдал, когда распечатывал дампы в программе в %u формате, передавая char...&lt;br /&gt;&lt;br /&gt;То есть на самом деле сертификат чека должен выглядеть как: 2bdc2fa0ffc1fef883c699b758e9ff45ba43a672. &lt;br /&gt;&lt;br /&gt;Только какой же это, нафиг, сертификат?!?&lt;br /&gt;&lt;br /&gt;PS: какой-то у меня микроблоггинг пошел. :)&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-8234357041265267427?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/8234357041265267427/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=8234357041265267427' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/8234357041265267427'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/8234357041265267427'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2010/01/blog-post_21.html' title='Сбербанк жжет'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_eOHzlCMDZZM/S1g4PAVGmPI/AAAAAAAAAJI/0USpRc13dbM/s72-c/sberbank' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-1529355122407454805</id><published>2010-01-16T00:10:00.002+03:00</published><updated>2010-04-27T15:16:39.509+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gentoo'/><category scheme='http://www.blogger.com/atom/ns#' term='exherbo'/><title type='text'>На гребне волны...</title><content type='html'>&lt;p align="right"&gt;Дочка Убунту прибежала к Дебиану и, весело смеясь, &lt;br /&gt;поцеловала его в лоб: "С днём рождения, папа!" &lt;br /&gt;Затем она окинула радостным взглядом сидящих за &lt;br /&gt;столом гостей и спросила своим звонким голосом: &lt;br /&gt;— Папа, а где Gentoo, разве он ещё не пришёл? &lt;br /&gt;— Нет, он ещё только собирается.&lt;/p&gt;&lt;br /&gt;Я человек, уже, наверное, окончательно потерянный для традиционных систем. Народ мигрирует со скучного debian-stable на "веселую" OpenSuse. В чем счастье, Роман? В Gentoo я могу настроить едва ли не каждую опцию каждого пакетика. И я напрочь лишен этого в пребилденных системах. Мне тесно в их жестких рамках, Я даже не могу заоптимизировать пакетик так как захочу - я должен жить так, как хотят другие... Не хочу я так жить, не хочу.&lt;br /&gt;&lt;br /&gt;Я люблю Gentoo. Но последнее время мне кажется, что Gentoo законсервативилось. Стабильная версия не создает почти никаких проблем, не смотря на то, что я ее каждую неделю обновляю. Скучно.&lt;br /&gt;&lt;br /&gt;Куда же податься старому linux-экстремалу?&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;Gentoo приучил меня к тому, что ни один файл в системе не существует просто так, если файл есть, значит он кому нибудь нужен, и я легко могу сказать кому. Это приятное ощущение контроля над системой не может не радовать.&lt;br /&gt;&lt;br /&gt;Но для прогрессивного человека есть еще один аспект - стремление к новому. Еженедельно выходят новые версии различного открытого софта. Прежде чем этот софт попадет в репозитории систем и застабилизируется - проходит разное время, от месяца до года.&lt;br /&gt;&lt;br /&gt;На стабильных версиях сидеть - скучно. Gentoo в стабильной версии уже три года стоит на моей рабочей машине и не создает проблем, хотя обновляется каждую неделю.&lt;br /&gt;&lt;br /&gt;Как сказал один из наших сотрудников, когда мы заговорили о линуксах о всяких: "Если человеку скучно в Gentoo - то это уже не лечится..."&lt;br /&gt;&lt;br /&gt;Эксперементировать с Gentoo мне уже не очень интересно. Ведь иногда хочется позаниматься чем-то кроме обновления и восстановления системы. Поэтому на всякий случай у меня два корневых раздела.&lt;br /&gt;Предполагается что на втором разделе находится работающая, но, может быть, не такая новая версия системы. Но это тоже толком не работает. Обычно у меня там стоит прошлогодняя инсталляция Gentoo, в которую я почти никогда не возвращаюсь. И второй рут использую для инсталляции новой Gentoo при выходе нового релиза, чтобы не забыть как это делается.&lt;br /&gt;&lt;br /&gt;Держать две одинаковых системы как-то бессмысленно. Но и достойных альтернатив Gentoo я не вижу, кроме разве что &lt;b&gt;&lt;a href="http://www.exherbo.org/"&gt;Exherbo&lt;/a&gt;&lt;/b&gt;. &lt;br /&gt;&lt;br /&gt;Exherbo - это почти тот же самый Gentoo. Пакеты там так же гибко настраиваются и так же собираются из исходников. В нем используется другой пакетный мнеджер - &lt;a href="http://paludis.pioto.org/"&gt;Paludis&lt;/a&gt;. Вместо одного репозитория он оперирует набором узкоспециальных репозиториев, количество которых в моей системе уже превысило два десятка.&lt;br /&gt;&lt;br /&gt;И самое экстремальное то, что система еще на стадии раннего бета тестирования. Стабильных пакетов в Exherbo нету вообще. Пакеты не просто помечены как нестабильные - они действительно самые свежие. Система для настоящих джедаев. Эти программы в debian stable появятся едва ли не через год... &lt;br /&gt;&lt;br /&gt;Но сообщество Exherbo значительно меньше Gentoo'шного, развитие системы хотя и идет быстро, но многих программ пока просто нету. Но мы не привыкли отступать, будем писать ебилды, которые здесь называются эксересами. Больше эксересов хороших и разных.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-1529355122407454805?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/1529355122407454805/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=1529355122407454805' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/1529355122407454805'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/1529355122407454805'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2010/01/blog-post.html' title='На гребне волны...'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-8522771787204314757</id><published>2009-12-02T23:16:00.003+03:00</published><updated>2010-07-02T11:44:51.119+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><title type='text'>Игры со временем</title><content type='html'>Многие начинающие agile команды наверняка испытывают проблемы с планированием. И наша команда тоже через это прошла. Мы долго и упорно пытались планировать время, строить графики сгорания, пока не поняли что смысла не будет. И теперь начинаю понимать - почему...&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;&lt;b&gt;Не нужно планировать время.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Очень много времени в SCRUM тратится на планирование. Мало того, что мы должны разделить все истории на задачи, мы еще должны, как дураки, оценивать время играя в карты. &lt;br /&gt;&lt;br /&gt;Программистам не нужно время. Дайте программисту четко поставленную задачу и не отвлекайте, пока не будет готово. &lt;br /&gt;&lt;br /&gt;Время - это больше для руководителей. Это им интересно знать сколько часов отработал каждый (что в принципе противоречит комадной разработке), сколько часов осталось до релиза и сколько историй можно пропихнуть в следующую итерацию, чтобы было готово вчера. Это все голая статистика, и у продукт оунера есть все возможности для ее сбора и анализа. :)&lt;br /&gt;&lt;br /&gt;Чтобы программисты могли точно оценивать время - нужен большой опыт. Причем опыт именно в предсказании времени :). Можно прекрасно представлять себе объем работ, но постоянно ошибаться со сроками.&lt;br /&gt;&lt;br /&gt;Кроме того, можно достаточно легко представить сколько времени займет очередное изменение, но конкретно плавать в оценке сроков задач, которые предстоит сделать под конец итерации, потому что объем предварительных измнений - только в головах...&lt;br /&gt;&lt;br /&gt;И это тоже проблема. Поэтому &lt;b&gt;не надо планировать все задачи сразу&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;Если вы планируете внедрять SCRUM - послушайте моего совета. На бумажках нельзя писать абстрактные и неконкретные вещи. Каждая бумажка должна представлять из себя конкретную задачу для одного человека. Не получается чтобы по одной бумажке и программист программировал и тестер тестировал. Не пойдет скрам. Бумажки будут мотаться по доске без видимого результата. Еще раз: конкретная задача для одного человека. Взял, сделал, done, без вариантов!&lt;br /&gt;&lt;br /&gt;Но тут возникает проблема, потому что не всегда можно расписать на конкретные задачи то, что не понятно или неизвестно. Я думаю - что и не нужно. &lt;i&gt;После этого поклонники настоящего скрама закидают меня гнилыми помидорами, но я продолжу.&lt;/i&gt; Даже если фича описана конкретно - все шаги по ее реализации сформулировать на раннем этепа крайне сложно. Это только идеальные команды в вакууме могут это сделать.&lt;br /&gt;&lt;br /&gt;Это чем-то перекликается с GTD Дэвида Аллена. Тем, что все запланировать практически нереально, но первое конкретное действие легко определяется почти всегда (Или фичу нужно сразу вернуть оунеру).&lt;br /&gt;&lt;br /&gt;Вероятно на этом принципе держится Канбан. MMF - достаточно крупное понятие, и программист должен видеть конкретные действия, которые способны продвинуть задачу вперед. На доске место для них не предусмотрено. И если конкретности вИдения не достает - то канбан не пойдет, встанет.&lt;br /&gt;&lt;br /&gt;В SCRUM проще. Мы разбиваем задачу на работы и прикидываем время выполнения этих работ. Только проблема в том, что если работа неконкретная, то и время выполнения получается неконкретное, и следовательно вряд ли оно будет соблюдено.&lt;br /&gt;&lt;br /&gt;И получается, что время не играет роли. Если задача и действия по ней конкретные - она будет двигаться вперед, в противном случае мы будем топтаться на месте. А время - чисто статистическая характеристика, нужная, как я уже сказал, только PO.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Но это вовсе не означает что время совершенно не нужно&lt;/b&gt; для программистов.&lt;br /&gt;&lt;br /&gt;Программирование - процесс творческий. И зачастую связанный с познанием неизведанного. А познание неизведанного - процесс крайне трудно поддающийся планированию. Когда речь идет о неизведанном - разговоры о времени неуместны? Еще как уместны!&lt;br /&gt;&lt;br /&gt;Для начала нужно конкретно сформулировать для себя - что ты хочешь познать, ибо правильный вопрос содержит в себе половину ответа. После этого конкретно оценить сколько времени это может занять.  Даже если по истечении указанного времени просветления не наступает - работа закончена, и ты можешь, на основании полученного опыта, сформулировать для себя новый вопрос, поиску ответа на который и посвятить следующие n часов. Но не больше. :)&lt;br /&gt;&lt;br /&gt;То есть просто временной лимит. Который, следует заметить, для конкретной работы не просто не нужен - а даже вреден, поскольку вносит лишний нервирующий фактор. Риск неуложиться во время, демотивация, и тд и тп...&lt;br /&gt;&lt;br /&gt;Вот где-то такие мысли у меня по поводу agile. Не SCRUM, не Kanban...&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;PS: Опять давно ничего не писал, мыслей вроде много, а писать - руки не доходят. Как с этим бороться?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-8522771787204314757?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/8522771787204314757/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=8522771787204314757' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/8522771787204314757'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/8522771787204314757'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2009/12/blog-post.html' title='Игры со временем'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-5886442388242470885</id><published>2009-10-14T15:38:00.005+04:00</published><updated>2009-10-14T16:40:28.137+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gentoo'/><category scheme='http://www.blogger.com/atom/ns#' term='kde'/><title type='text'>KDE3 is dead?</title><content type='html'>На прошлой неделе в Gentoo размаскировали KDE-4.3 для платформы amd64. При этом, после окончательной стабилизации KDE4, KDE3 будет удалена из репозитория навсегда.&lt;br /&gt;&lt;br /&gt;Двоякое ощущение. &lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;С одной стороны дома я уже давно сижу на KDE4.2, дома у меня больше возможностей и желания для экспериментов. С другой стороны KDE4 расстраивает меня своим уходом в красивости. Да мне пофиг красивости, хотя дочке очень нравятся снежинки.&lt;br /&gt;&lt;br /&gt;Но правда открытого софта такова, что старая версия уже никому не нужна. И никто не будет возиться с багами, которых там еще много. Ну будем надеяться, что в kde4 помимо красивых плазмоидов у разработчиков дойдут руки и до полезных и нужных вещей, как то работа с сертификатами, получение адресов из LDAP, почему-то все мои проблемы крутятся в основном вокруг kmail? Нет, в kopete очень слабая поддержка jabber. :)&lt;br /&gt;&lt;br /&gt;Короче, переехал на kde-4.3.1. Прошарил свою систему, удалил оттуда все, что зависело от qt3, и теперь у меня чистая qt4 система.&lt;br /&gt;&lt;br /&gt;Кроме того, я наконец то нашел решение проблемы ntlmaps, терзавшей меня долгое время. Проблема заключается в том, что в один прекрасный момент он перестал запускаться из init скрипта. С консоли запускается, а из init-скрипта ни в какую. Кроме того я давным давно не могу пустить через него firefox - ntlmaps не проксирует запросы почему-то. А иногда еще и проц жрет почем зря - под 100%.&lt;br /&gt;&lt;br /&gt;Обнаружилась вполне достойная альтернатива - &lt;a href="http://cntlm.sourceforge.net/"&gt;cntlm&lt;/a&gt; , которая пока правда не входит в репозиторий gentoo, но ebuild можно скачать &lt;a href="http://bugs.gentoo.org/show_bug.cgi?id=220205"&gt;отсюда&lt;/a&gt;, чуть чуть поплясать с бубном и все, настало полнейшее счастье, и причем значительно более шустрое.&lt;br /&gt;&lt;br /&gt;Значит жизнь продолжается! :) Что касается сертификатов - Thawte наконец таки перестал раздавать публичные сертификаты. И значит информацию о зарплате отныне будут доводить на наших, внутренних.&lt;br /&gt;Пойду получать новый сертификат Информзащиты.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-5886442388242470885?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/5886442388242470885/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=5886442388242470885' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/5886442388242470885'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/5886442388242470885'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2009/10/kde3-is-dead.html' title='KDE3 is dead?'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-1206609946660516595</id><published>2009-09-14T22:07:00.009+04:00</published><updated>2010-07-02T14:04:44.562+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mercurial'/><category scheme='http://www.blogger.com/atom/ns#' term='hardware'/><category scheme='http://www.blogger.com/atom/ns#' term='google'/><title type='text'>Куда едут мыши?</title><content type='html'>Уже наверное полгода замечаю странное поведение мышки, она ни с того не с сего вдруг начинает ехать вниз... Причем по разному, то быстрее, то медленнее...&lt;br /&gt;&lt;br /&gt;... Я уже собирался было ее выкинуть, но тут меня осенило.&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.btc.ru/card/22/"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 300px; height: 137px;" src="http://www.btc.ru/catalog/22/front.jpg" border="0" alt="" /&gt;&lt;/a&gt;Клавиатура у меня безпроводная, BTC-9116URF. Она совмещает в себе клавиатуру и мышь. Черная штука в правом-верхнем углу - это джойстик.&lt;br /&gt;&lt;br /&gt;И вот, когда я уже собрался выкинуть это глючную мышь, я вдруг сообразил, что это просто клавиатура джойстиком упирается в монитор, джойстик скрючивается и мышиный курсор начинает ехать вниз. А я почти полгода ломаю голову...&lt;br /&gt;&lt;br /&gt;А тем временем Google включил на GoogleCode Mercurial. Я сразу же, как узнал, одно из своих извращений перевел - побаловаться для начала. wiki они отделили, теперь wiki хранится в отдельном репозитории, версии посмотреть можно, а вот как склонировать - могу только догадываться. Возможно, что не предполагает клонирования, только веб-редактирование. Ну и ладно, а то раньше веб-редактирование сильно засоряло репозиторий, я предпочитал редактировать локально.&lt;br /&gt;&lt;br /&gt;Кроме того балуюсь с Google Wave, много всяких интересных идей, но о них попозже.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-1206609946660516595?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/1206609946660516595/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=1206609946660516595' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/1206609946660516595'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/1206609946660516595'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2009/09/blog-post.html' title='Куда едут мыши?'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-6556427142059235562</id><published>2009-09-10T14:40:00.005+04:00</published><updated>2010-07-02T13:57:13.416+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='boost'/><category scheme='http://www.blogger.com/atom/ns#' term='test'/><title type='text'>The big class unittest</title><content type='html'>Тестирование унаследованного программного обеспечения - это всегда проблема. Зачастую для написания теста приходится править и код приложения, чего конечно, хотелось бы избежать...&lt;br /&gt;&lt;br /&gt;Вот и у меня такая же ситуация. Все имена и методы по возможности изменены, все совпадения случайны.&lt;br /&gt;&lt;br /&gt;Есть большой класс... Назовем его CBigApp... 173 публичных метода, еще 40 частных. Видимо для того, чтобы с ним было проще работать реализация разнесена приблизительно на 20 файлов... Ну чтож, это облегчает нашу задачу.&lt;br /&gt;&lt;br /&gt;А задача заключается в том, что приложение почему-то перестало импортировать конфигурацию от предыдущей версии. Хороший момент для написания первого юниттеста! :)&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;Не смотря на то, что этот объект традиционный одиночка, конструктор публичный и мы можем попытаться его создать... но лучше не стоит, при конструировании он создает 4 базы данных и порождает нить (но не уверен что одну)...&lt;br /&gt;&lt;br /&gt;Можно создать ему конструктор, который ничего не создает, но это именно то, чего мы пока хотим избежать - модификация кода приложения. Да и одним конструктором дело точно не ограничится.&lt;br /&gt;&lt;br /&gt;Для проверки импорта конфигурации нам вполне неплохо подходит одна функция - назовем ее import_config, хоят по легенде это сделано давным давно, в 19-м веке. :) Эта функция практически не пользуется другими методами класса, кроме функции convert_config, которая в свою очередь дергает несколько мелких функций по конвертации. Все эти функции не зависят от остального содержимого класса... одна беда - они private.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Как говорят великие, такой набор функций - хороший кандидат на извлечение класса по виду ответственности.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Призовем на помощ препроцессор. Поскольку оригинальное описание класса нас совершенно не устраивает - мы его прячем:&lt;br /&gt;&lt;pre&gt;namespace hidden {&lt;br /&gt;#include "CBigApp.h"&lt;br /&gt;}&lt;/pre&gt;Если мы этого не сделаем, то оно заинклюдится из сишного файла, который мы хотим заинклюдить к себе. Но для начала мы опишем свою версию класса, и делать это мы будем в cьюте, чтобы изолировать его от взаимозависимостей, ведь у нас как бы появятся свои версии функций. Неизбежны проблемы при линковке тестового приложения. Сьют позволяет изолировать эти манипуляции.&lt;br /&gt;&lt;pre&gt;BOOST_AUTO_TEST_SUITE(suiteCBiGApp_ImportConfig)&lt;br /&gt;&lt;br /&gt;struct CBigApp {&lt;br /&gt;void import_config(const archive &amp;aconfig, const std::string &amp;config_file);&lt;br /&gt;void convert_config(const std::string &amp;config_file, u_int version);&lt;br /&gt;void fix_10_value(const std::string &amp;value &amp;);&lt;br /&gt;void fix_21_value(const std::string &amp;value &amp;);&lt;br /&gt;void fix_22_value(const std::string &amp;value &amp;);&lt;br /&gt;};&lt;/pre&gt;Это собственно наше тестовое видение класса. Оно еще не окончательное и нам еще придется с ним повозиться. Прототипы мы без искажений скопировали из CBigApp.h. Ну а теперь подтягиваем реализацию.&lt;br /&gt;&lt;pre&gt;#include "Import.cpp"&lt;/pre&gt;Может так сложиться, что помимо вышеописанных функций в этом файле реализуются и другие. Тогда и их прототипы необходимо вписать в тестовый класс.&lt;br /&gt;&lt;br /&gt;Может быть эта реализация ссылается на другие функции класса, описанные в другом файле. Их тоже можно описать в структуре с необходимой реализацией.&lt;br /&gt;&lt;pre&gt;void create_minimal_config(const std::string &amp;)&lt;br /&gt;{ throw logic_error("Не используется"); }&lt;/pre&gt;Помимо того наверняка будет так, что в этом файле включаются и другие инклюды - все эти включения, в том числе и стандартные необходимо перенести в начало нашего юниттест-файла, чтобы они первый раз включились в глобальном пространстве имен, второй раз они уже не будут включаться.&lt;br /&gt;&lt;br /&gt;После этого у нас появилась возможность вызвать тест... &lt;br /&gt;&lt;pre&gt;BOOST_AUTO_TEST_CASE(testImport10)&lt;br /&gt;{&lt;br /&gt;CBigApp app;&lt;br /&gt;BOOST_REQUIRE_NO_THROW(app.import_config(cfg10, "config_file-1.0.cfg"));&lt;br /&gt;::unlink("config_file-1.0.cfg");&lt;br /&gt;}&lt;/pre&gt;&lt;span style="font-style:italic;"&gt;Да, я знаю, что использовать файловую систему в юниттестах - плохо... но лучше иметь юниттесты, которые используют файловую систему (базы данных, подключения по сети), чем не иметь никаких. Для успокоения совсети их можно назвать функциональными. :)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;В тестировании можно пойти дальше, объявив некоторые из методов как virtual, и заменить их в процессе тестирования на что-то удобное для себя:&lt;br /&gt;&lt;pre&gt;BOOST_AUTO_TEST_CASE(testImport21)&lt;br /&gt;{&lt;br /&gt;struct inCBigApp : public CBigApp {&lt;br /&gt;virual fix_10_value(const std::string &amp;value &amp;)&lt;br /&gt;{ throw logic_error("Не должен вызываться"); }&lt;br /&gt;} app;&lt;br /&gt;BOOST_REQUIRE_NO_THROW(app.import_config(cfg21, "config_file-2.1.cfg"));&lt;br /&gt;::unlink("config_file-2.1.cfg");&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Очень хорошо, что в данном случае класс разбросан по файлам, это облегчает процесс подтягивания нужного функционала в минимальных объемах. Но даже если вся реализация в одном файле, главное чтобы описание было в другом, и тогда его можно будет подменить на свое - со своими методами доступа, с нужными тебе виртуальными функциями, которые замещаются по мере необходимости. И все это происходит без модификации кода продукта.&lt;br /&gt;&lt;br /&gt;Вроде пока все.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-6556427142059235562?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/6556427142059235562/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=6556427142059235562' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/6556427142059235562'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/6556427142059235562'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2009/09/big-class-unittest.html' title='The big class unittest'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-5611075832268172681</id><published>2009-09-01T13:14:00.007+04:00</published><updated>2010-07-02T13:57:31.615+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='boost'/><category scheme='http://www.blogger.com/atom/ns#' term='test'/><title type='text'>null ostream</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ozon.ru/context/detail/id/4127815"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 200px; height: 290px;" src="http://www.ozon.ru/multimedia/books_covers/1000929029.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;Последнее время старательно осваиваю TDD. На работе это пока не используется, но для себя все пишу через тесты. Привычку вырабатываю. :) Купил вот недавно самую дорогую книгу в своей жизни: Шаблоны тестирования xUnit. Рефакторинг кода тестов. Очень познавательная книга. Юнит тестинг без фанатизма. Там в частности написано, что использовать базы данных в тестах можно! Но есть способы лучше. Вообще главная мораль этой книги - что наличие тестов, каких бы то ни было значительно лучше, чем их отсутствие.&lt;br /&gt;&lt;br /&gt;Но собственно написать я хотел о другом. Изобретаю консольное приложение. Консольное приложение должно что-то выводить на консоль. Для этого традиционно используется cout. И собственно приложению ничего больше не нужно.&lt;br /&gt;&lt;br /&gt;Но когда речь заходит о тестах - cout становится серьезной помехой.&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;Я выбрал следующий путь решения. Методы, которые что-то выводят, получают в качестве параметра &lt;code&gt;ostream &amp;&lt;/code&gt;. Это позволяет в тестах подсунуть вместо cout что-то другое, например ostringstream. И проверить что же собственно вывелось на консоль после вызова метода.&lt;br /&gt;&lt;br /&gt;Но иногда тестам и этого не нужно. Бывает нужно передать что нибудь, только чтобы метод им удовлетворился и проглотил. И встает вопрос dummy ostream - потока-заглушки.&lt;br /&gt;&lt;br /&gt;Вариант #1 с заглушиванием cout:&lt;br /&gt;&lt;pre&gt;std::cout.exceptions(std::ios::goodbit); &lt;br /&gt;std::cout.setstate(std::ios::failbit);&lt;br /&gt;std::cout &lt;&lt; 1; // ignore&lt;/pre&gt;... мне совершенно не нравится. Да и для тестов он не очень удобен. Каждый раз глушить и разглушать обратно? Нет, нам нужен объект, наследник ostream, который просто не делает ничего.Сделать так можно. Решение приводить не буду, &lt;a href="http://www.velocityreviews.com/forums/showpost.php?p=2532799&amp;postcount=3 "&gt;сошлюсь&lt;/a&gt;. Но давайте посмотрим что есть на эту тему в boost.Решение #3, найденное в интернете:&lt;pre&gt;struct null_sink : boost::io::sink {&lt;br /&gt;void write(const char*, std::streamsize) { }&lt;br /&gt;};&lt;br /&gt;typedef boost::io::stream_facade&amp;lt;null_sink&gt; null_ostream;&lt;/pre&gt;... сейчас не работает. Не скажу точно когда работало, не важно.Решение #4:&lt;pre&gt;typedef boost::iostreams::stream&amp;lt;boost::iostreams::null_sink&gt; null_ostream;&lt;/pre&gt;... работает, но для того, чтобы все было гладко, перед использованием надо вызвать &lt;code&gt;out.open(boost::iostreams::null_sink());&lt;/code&gt;, что не совсем удобно.И последнее...&lt;code&gt;onullstream&lt;/code&gt; описан в файле &lt;code&gt;boost/test/utils/nullstream.hpp&lt;/code&gt;.Одного только не понимаю, почему я не могу создавать его непосредственно при вызове?&lt;pre&gt;int foo(ostream &amp;out);&lt;br /&gt;BOOST_CHECK_EQUAL(foo(onullstream()), 1)&lt;/pre&gt;... возвращает ошибку, о том, что нет метода foo, в который можно было бы передать onullstream... но если создать onullstream заранее, то никаких возражений у компилятора не возникает.&lt;pre&gt;onullstream out;&lt;br /&gt;BOOST_CHECK_EQUAL(foo(oot), 1)&lt;/pre&gt;... Успешно. Что-то я наверное делаю не так? :)&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-5611075832268172681?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/5611075832268172681/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=5611075832268172681' title='Комментарии: 9'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/5611075832268172681'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/5611075832268172681'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2009/09/null-ostream.html' title='null ostream'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-6734505910951726278</id><published>2009-09-01T11:53:00.005+04:00</published><updated>2010-07-02T11:47:17.403+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='windows'/><title type='text'>Unix way?</title><content type='html'>Недавно встретилась статья про то, как один человек пытался установить обои на два монитора в GNOME. К сожалению ссылку найти не могу, но вкратце: Нужно написать небольшое приложение, которое "легко" позволяет это сделать.&lt;br /&gt;&lt;br /&gt;Я могу понять. Всетаки линукс, среда обитания красноглазых линуксоидов... :) Думаете в Windows такого нету?&lt;br /&gt;&lt;br /&gt;Озадачился тут намедне вопросом, о том как по умолчанию включить NumLock в Windows XP. Вариант установки в биосе - не очень гибок... хотелось чтобы Windows делал это сам.&lt;br /&gt;&lt;br /&gt;Спросил у гугля, недолго думая пошел по первой ссылке на &lt;a href="http://support.microsoft.com/kb/314879"&gt;support.microsoft.com&lt;/a&gt;, где мне предложили... написать для этой цели скрипт.&lt;br /&gt;&lt;br /&gt;PS: Чуть погодя на нашел, какое значение в реестре надо подправить, чтобы все стало как надо. С этой же статьи есть ссылка на другую статью, где все описано правильно. Но ход мыслей нравится...&lt;br /&gt;&lt;br /&gt;PPS: Совсем забросил блог, надо как-то исправляться...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-6734505910951726278?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/6734505910951726278/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=6734505910951726278' title='Комментарии: 4'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/6734505910951726278'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/6734505910951726278'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2009/09/unix-way.html' title='Unix way?'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-6390041066914679073</id><published>2009-07-28T12:55:00.003+04:00</published><updated>2009-07-28T13:21:03.953+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='gcc'/><title type='text'>typeinfo for int</title><content type='html'>Загадочный всетаки компилятор - gcc...&lt;br /&gt;&lt;br /&gt;Начать реализацию обработки исключений я решил в простенькой конструкции в коде:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;try {&lt;br /&gt; throw 1;&lt;br /&gt;} catch (...) {&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Но наткнулся на ошибку - undefined reference to `typeinfo for int'.&lt;br /&gt;И вот возникла непонятная задача - как же мне описать typeinfo for int?&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;gcc очень загадочен. О существовании типа std::type_info он знает безо всяких дополнительных объявлений, что не мешает описать его локально. Но в gcc этот класс чисто базовый, констуктор у него защищен. На это можно было бы наверное наплевать и объявить все по своему, если бы в этом был смысл.&lt;br /&gt;&lt;br /&gt;Но необходимый мне typeinfo должен иметь другой тип: __fundamental_type_info. И мне нужно проинициализировать его статически, для чего я долго изголялся с размещающими new в статическом буфере...&lt;br /&gt;&lt;br /&gt;Стоит отметить что до сих пор линкер исправно ругался на отсутсвие typeinfo. Но после этого неожиданно начал ругаться на отсутвие 'vtable for __cxxabiv1::__pointer_type_info', странно.&lt;br /&gt;&lt;br /&gt;Исследование модуля objdump'ом показало в нем наличие большого количества typeinfo. Стал выяснять - откуда они взялись. И вот ведь загадочный gcc...&lt;br /&gt;&lt;br /&gt;Стоит вставить следующий код:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;namespace __cxxabiv1 {&lt;br /&gt;class __fundamental_type_info : public std::type_info&lt;br /&gt;{&lt;br /&gt;virtual ~__fundamental_type_info() { }&lt;br /&gt;};&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Как все необходимые фундаментальные typeinfo появляются как по волшебству. И с размещающим new я изголялся зря. :)&lt;br /&gt;&lt;br /&gt;А с исключениями пока еще далеко не все понятно, разбираюсь.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-6390041066914679073?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/6390041066914679073/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=6390041066914679073' title='Комментарии: 3'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/6390041066914679073'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/6390041066914679073'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2009/07/typeinfo-for-int.html' title='typeinfo for int'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-6505439430120728534</id><published>2009-07-24T17:25:00.004+04:00</published><updated>2009-07-24T22:45:12.997+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='gcc'/><title type='text'>Исключительная ситуация</title><content type='html'>Нет, у меня все в порядке, дела идут и жизнь легка. Просто лето и отпуск, и я совершенно забросил свой блог. Но делать так ни в коем случае нельзя. У меня уже был подобный опыт по забрасыванию рассылки comp.soft.prog.asmos на Subscribe.ru, которая находится в дауне до сих пор. Чем больше времени проходит с момента последнего поста, тем проще ничего не писать.&lt;br /&gt;&lt;br /&gt;А темой сегодняшнего поста я избрал исключения. Но я не стану расскзывать тривиальные вещи, про то, что исключения из деструктора не бросатся, это и так все знают. Мне вдруг стало интересно как это работает изнутри. Но пока здесь одни вопросы. Разбираться надо.&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;gcc очень наглый компилятор. Он может спокойно инлайнить функции, даже если используется -O0. Он может нормальные казалось бы вызовы стандартных функций заменять ассемблерными мнемониками. Но с исключениями все обстоит еще сложнее. Стандартный, казалось бы, С++ код превращается в нагромождения непонятных вызовов c которыми я и хотел бы разобраться, чтобы прикрутить исключения к своему ядру.&lt;br /&gt;&lt;br /&gt;Правда, тут все зависит от цены, так сказать. Патч для ядра linux, позволяющий использовать C++ с исключениями занимает 600к, в то время как вся моя кроссплатформенная часть (для которой собственно рунтайм и тащится) занимает 200к. Неравноценный получается обмен.&lt;br /&gt;&lt;br /&gt;В самом gcc все реализовано максимально переносимо, из за чего, вероятно, трудно все это понять. Большой уровень косвенности. Мне же переносимость в данном случае не нужна, нужна минимальная реализация для конкретной платформы.&lt;br /&gt;&lt;br /&gt;Так как же работают исключения? gcc, не смортя на всю свою наглость, конечно молодец. Для корректной отработки деструкторов выделенных в стеке объектов в нем используются так называемые "landing pad", область приземления? или как это правильно перевести. Область приземления располагается в конце каждого программного блока, в котором требуется деинициализация. Причем gcc очеь грамотно задвигает все, что не требуется деинициализировать.&lt;br /&gt;&lt;br /&gt;Координаты этих областей перечисленны в "exception handling tables". Эти таблицы формируются компилятором для каждой функции. Хотя может и не для каждой, точно сказать пока не могу.&lt;br /&gt;&lt;br /&gt;При возникновении исключения управление передается в функцию __cxa_throw, и дальше начинается сплошной грязный хак. Управление обратно уже не возвращается. Происходит разворот стека, для каждой функции производится поиск таблиц исключений, и в зависимости от адреса, где вызывалась функция __cxa_throw, выбирается ближайший landing pad и управление передается на него.&lt;br /&gt;&lt;br /&gt;Кстати, именно на функцию __cxa_throw надо ставить брекпоинт для программы, собранной с помощью gcc, если есть желание отловить момент возникновения исключения в отладчике.&lt;br /&gt;&lt;br /&gt;Чтобы механизм разворота стека заработал дальше, в случае отсутствия обработчиков исключений, в конце функции ставится вызов _Unwind_Resume, в котором может быть инициирована дальнейшая раскрутка стека, если исключение имеет место быть. Но ставится он не в каждой функции. Иногда даже перед вызовами деструкторов. По какому принципу он расставляется - я пока не осознал.&lt;br /&gt;&lt;br /&gt;Стандарт оговаривает и структуры, которые вращаются внутри __cxa_throw и других функций, связанных с исключениями, но для минимальной реализации на это можно забить. Главное - это понять логику разворота стека и связывания функций с соответствующими таблицами прерываний.&lt;br /&gt;&lt;br /&gt;Так же для меня является загадкой, почему разработчики gcc так перемешали интерфейсы __cxa* и _Unwind*. Но в недрах реализации они переплетены столь плотно, что разорвать их практически нереально.&lt;br /&gt;&lt;br /&gt;Если вдруг кто-то уже разбирался с обработкой исключений в gcc - отзовитесь, у меня много вопросов. :) Хотя постепенно осознание придет, если долго разбираться.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-6505439430120728534?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/6505439430120728534/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=6505439430120728534' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/6505439430120728534'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/6505439430120728534'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2009/07/blog-post.html' title='Исключительная ситуация'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-3124635845846310149</id><published>2009-06-03T21:32:00.004+04:00</published><updated>2010-07-02T14:12:52.379+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='мысли'/><category scheme='http://www.blogger.com/atom/ns#' term='VCS'/><title type='text'>CVCS мертв?</title><content type='html'>Было время, когда никто не слышал про бранчи. Собственно и система контроля была одна - cvs. Нет две, еще был rcs, но это помоему совсем уж дедушка систем контроля версий.&lt;br /&gt;&lt;br /&gt;Но времена меняются очень быстро. Subversion за считанные годы просто похоронил cvs. Да и его скоро отправят на свалку истории...&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;Несколько дней назад &lt;a href="http://www.opennet.ru/opennews/art.shtml?num=21980"&gt;упал savannah.gnu.org&lt;/a&gt;. Вследствии отказа RAID-массива содержимое проектных баз было безвозвратно утеряно. Последний нормальный бекап - месячной давности (sic!). Какой же у них рейд, если всеравно все рухнуло?&lt;br /&gt;&lt;br /&gt;И вот, бедные владельцы проектов, которых угораздило хранить свои проекты в cvs/svn вынуждены по крохам восстанавливать содержимое баз (буквально с помощью сообщества).&lt;br /&gt;&lt;br /&gt;И вот после этого подумаешь - всетаки умные люди не зря придумали DVCS? Скорее бы уже google code поднял меркуриал, я мигрирую.&lt;br /&gt;&lt;br /&gt;Собственно для меня история проекта имеет достаточно незначительную ценность. Я просто не знаю зачем она мне может понадобиться. Но прикольно то, что с 2002 года sourceforge бережно хранит мою базу. И только.&lt;br /&gt;&lt;br /&gt;В корпоративном плане история несомненно нужна. Хотя бы для того, чтобы выяснить - какой же идиот написал этот код?&lt;br /&gt;&lt;br /&gt;Ценность бранчей пока еще ясна не всем, возможно по причине использования устаревших средств, которые с этими самыми бранчами не особо дружат. Я вот точно не знаю, последние версии SourceSafe научились делать бранчи? Perforce например делает вид что умеет это делать, но при этом историю теряет. То есть новый бранч - новая история. И на вопрос из предыдущего абзаца ответить уже не удается.&lt;br /&gt;&lt;br /&gt;Кроме того не знаю как остальным - а мне кажется крайне неприличным выкладывать в базу изменения, которые точно не собираются. При этом если я переименовываю файл в Perforce, я категорически не могу больше никакое изменение в него внести, хотя собираемость проекта при этом явно нарушается.&lt;br /&gt;&lt;br /&gt;Собственно смысл этого понятен, при переименовании файла перфорсу хочется сэкономить место в базе и связать новый файл со старым (по идентичности содержимого). Только мне то какое до этого дело? Кроме того я явно говорю ему что этот файл я синтегрировал из этого - отслеживай елыпалы.&lt;br /&gt;&lt;br /&gt;Кроме того я привык вносить изменения понемногу, мне просто жизненно необходима собственная база, из которой я мог бы одним чейнджсетом все перенести в базу perforce. Очень хочется такую систему контроля (конечно распределенную), которая умела бы оперировать с чужеродными репозиториями, как со своими. Многого хочу?&lt;br /&gt;&lt;br /&gt;А savannah.gnu.org конечно круто опозорился. Все срочно переходят на hg/git на других площадках.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-3124635845846310149?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/3124635845846310149/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=3124635845846310149' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/3124635845846310149'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/3124635845846310149'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2009/06/cvcs.html' title='CVCS мертв?'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-4042811215937756408</id><published>2009-05-20T17:11:00.009+04:00</published><updated>2009-09-14T22:52:17.059+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gentoo'/><category scheme='http://www.blogger.com/atom/ns#' term='gcc'/><category scheme='http://www.blogger.com/atom/ns#' term='QT'/><category scheme='http://www.blogger.com/atom/ns#' term='kde'/><title type='text'>Оптимизация в gcc, факты</title><content type='html'>При обновлении своей системы наткнулся на неприятный момент, сборка любых KDE компонент начала вдруг запарываться с руганью: &lt;pre&gt;checking if UIC has KDE plugins available... no&lt;/pre&gt;&lt;br /&gt;Я далек от мысли что у всех все плохо в течении двух недель (где то так у меня впервые не собралась kopete), а Gentoo мантайнеры не чешутся. Поэтому стал разбираться откуда растут ноги.&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;Стандартной рекоммендацией в такой ситуации считается - пересобрать qt и kde, но легче от этого не стало. Первым делом я конечно заподозрил, что возможно нестабильную kde-3.5.10 сломали, снял все маски - жужжит (c). Потом я подумал, что, возможно, мешается qt:4, снес его, благо он был мне нужен только для perforce gui, можно потерпеть чуток, но счастья опять не наступило. Не наступило счастье и после полной пересборки системы, что уже совсем непонятно, уж полная пересборка должна помочь?&lt;br /&gt;&lt;br /&gt;Долго гуглил... Не помню уже где, увидел упоминание про оптимизацию и gcc-4.3.2, а у меня вся система собрана на -Os. Решил поставить стандартный -O2, ради эксперимента. И, о чудо, компиляция компонентов kde прошла. На этом можно было бы остановиться, но кроме осознания факта неработоспособности qt3+kde3 собранных gcc-4.3.2 с опцией -Os, я узнал много нового про gcc, чем не могу не поделится. &lt;br /&gt;&lt;br /&gt;Многие наверное будут удивлены, но опция -march=core2 не включает оптимизацию с применением sse*, как принято считать, а всего лишь допускает использование соответствующих встроенных функций. Как убедились, да очень просто:&lt;br /&gt;&lt;pre&gt;void test()&lt;br /&gt;{&lt;br /&gt;        // sse2 builtin&lt;br /&gt;        __builtin_ia32_movnti(0, 0);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;$ gcc -march=pentium -c test.cpp&lt;br /&gt;test.cpp: In function ‘void test()’:&lt;br /&gt;test.cpp:3: ошибка: нет декларации ‘__builtin_ia32_movnti’ в этой области видимости&lt;br /&gt;$ gcc -march=core2 -c test.cpp&lt;br /&gt;$&lt;/pre&gt;&lt;br /&gt;Но в то же время использование правильной архитектуры вовсе не стимулирует компилятор к оптимизации кода с применением расширений. Как определили это? да очень просто:&lt;br /&gt;&lt;pre&gt;$ gcc -march=core2 -Q --help=target&lt;br /&gt;  ...&lt;br /&gt;  -msse                                 [выключено]&lt;br /&gt;  -msse2                                [выключено]&lt;br /&gt;  -msse3                                [выключено]&lt;br /&gt;  -msse4                                [выключено]&lt;br /&gt;  ...&lt;/pre&gt;&lt;br /&gt;Для того чтобы эта оптимизация выполнялась - необходимо явно задавать -mssse3 -mmmx или другие, необходимые для вашей архитектуры.&lt;br /&gt;&lt;br /&gt;Надо сказать, что конструкция &lt;code&gt;gcc -Q --help=CLASS&lt;/code&gt; очень полезна во всех отношениях. Я раньше этого не знал. В качестве CLASS можно подставлять в частности target, optimisers, warnings тем самым анализируя настройки компилятора с используемыми в вашем проекте опциями.&lt;br /&gt;&lt;br /&gt;PS: Одного я только не понимаю, как -Os может столь фатально влиять на связь приложения с библиотекой?&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-4042811215937756408?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/4042811215937756408/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=4042811215937756408' title='Комментарии: 6'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/4042811215937756408'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/4042811215937756408'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2009/05/gcc.html' title='Оптимизация в gcc, факты'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-1378460965781764459</id><published>2009-03-27T12:51:00.005+03:00</published><updated>2009-09-14T22:56:59.276+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='отладка'/><category scheme='http://www.blogger.com/atom/ns#' term='ошибки'/><title type='text'>Ошибка в стандартном инклюде</title><content type='html'>Интересную ошибку словил на днях...&lt;br /&gt;&lt;pre&gt;$ c++ ... -c file.cpp -o file.o&lt;br /&gt;In file included from /usr/include/c++/4.2/bits/basic_ios.h:44,&lt;br /&gt;                 from /usr/include/c++/4.2/ios:50,&lt;br /&gt;                 from /usr/include/c++/4.2/ostream:45,&lt;br /&gt;                 from /usr/include/c++/4.2/iostream:45,&lt;br /&gt;                 from configuration.h:4,&lt;br /&gt;                 from wrap.h:15,&lt;br /&gt;                 from file.cpp:15:&lt;br /&gt;/usr/include/c++/4.2/bits/locale_facets.h:4576: error: template-id 'do_get&lt;&gt;' for 'std::string std::messages&lt;wchar_t&gt;::do_get(int, int, int, const std::string&amp;) const' does not match any template declaration&lt;br /&gt;$&lt;/pre&gt;&lt;br /&gt;&lt;i&gt;Всякие совпадения с реальными файлами являются случайными :)&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Причем выяснилось, что если поменять инклюды местами - становится легче. В этом надо разобраться...&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;Проблема возникает с темплейтами в locale_facets.h.&lt;br /&gt;&lt;br /&gt;Для начала прогоню две версии через препроцессор. После долгого сравнения выясняется, что в правильной версии проблемная строка (locale_facets.h:)выглядит так:&lt;br /&gt;&lt;pre&gt; template&lt;&gt;&lt;br /&gt;    wstring&lt;br /&gt;    messages&lt;wchar_t&gt;::do_get(catalog, int, int, const wstring&amp;) const;&lt;/pre&gt;&lt;br /&gt;А в неправильной:&lt;br /&gt;&lt;pre&gt;  template&lt;&gt;&lt;br /&gt;    string&lt;br /&gt;    messages&lt;wchar_t&gt;::do_get(catalog, int, int, const string&amp;) const;&lt;/pre&gt;&lt;br /&gt;Очень странно, с какого праздника препроцессор в исходном тексте:&lt;br /&gt;&lt;pre&gt;  template&lt;&gt;&lt;br /&gt;    wstring&lt;br /&gt;    messages&lt;wchar_t&gt;::do_get(catalog, int, int, const wstring&amp;) const;&lt;/pre&gt;&lt;br /&gt;заменил wstring на string?&lt;br /&gt;&lt;br /&gt;Да очень просто. В одном из инклюдов проекта кто-то очень умный поставил:&lt;br /&gt;&lt;pre&gt;#define wstring string&lt;/pre&gt;&lt;br /&gt;Если все стандартное инклюдится заранее - проблем нету. В противном случае стандартные инклюды тянутся из проектных инклюдов, и в результате ошибка компиляции. И как это называется?&lt;br /&gt;&lt;br /&gt;Вообще я раньше наивно полагал что не стоит выносить сор из избы, то бишь каждый инклюд должен сам инклюдить все, что нужно ему для успешной компиляции.&lt;br /&gt;&lt;br /&gt;Но последнее время я серьезно увлекся TDD, и изменил свое мнение на полностью противоположное. Инклюды, включенные в другие инклюды - это жесткая связанность. Исходный файл превращается в объектный, инклюды в этом процессе играют вспомогательную роль. И на полученный объектный файл мы уже не можем особо повлиять, все зависимости там уже есть. Но что касается описания класса - это достаточно абстрактное понятие. И в некоторых случаях описания классов можно даже полностью подменять для тестирования, но только в том случае если они не включены в самом инклюде.&lt;br /&gt;&lt;br /&gt;Вот, как говориться КСCЗБ. Ну и кто написал эту ерунду (это я про define), пойду искать...&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-1378460965781764459?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/1378460965781764459/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=1378460965781764459' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/1378460965781764459'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/1378460965781764459'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2009/03/blog-post_27.html' title='Ошибка в стандартном инклюде'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-6062545092247947619</id><published>2009-03-10T11:46:00.004+03:00</published><updated>2009-03-10T22:01:21.322+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gentoo'/><category scheme='http://www.blogger.com/atom/ns#' term='kde'/><title type='text'>kde4: впечатления</title><content type='html'>Прошол уже наверное почти месяц, как я решил попробовать kde4. В gentoo оно пока замаскировано но не очень жестко, так, слегка - под ~x86.&lt;br /&gt;&lt;br /&gt;Эксперимент я провожу на домашнем компьютере. На рабочем - я работаю, и не могу надолго выводить его из строя. Что в процессе экспериментов случалось уже неоднократно.&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;Вся система у меня живет под "x86", И все пакеты я размаскирую индивидуально через /etc/portage/package.keywords. После установки kde файл /etc/portage/package.keywords/kde4 насчитывает около 125 строк. Но помимо этого мне пришлось размаскировать xorg-x11, который тоже состоит из весьма большого количества мелких пакетиков.&lt;br /&gt;&lt;br /&gt;Раньше я спокойно всю систему держал на ~x86, но потом надоело ходить по краю и я перешел на стабильные версии. Иногда только хочется экстрима, вот как щас. :)&lt;br /&gt;&lt;br /&gt;Что-то я уже запамятовал, какая версия kde встала первой, возможно что kde-4.1, но помню точно, что kdm4 сразу не заработал. Он запускался, но экран на седьмой консоли оставался пустым. Первое время приходилось пользоваться kdm3&lt;br /&gt;&lt;br /&gt;Кстати про kde3. Обязательно используйте USE="kdeprefix". Без него kde3 сразу же перестал нормально работать, перемешались ресурсы обоих кед. kde3 необходимо обновить до 3.5.10, котороый, в свою очередь, тоже замаскирован (читай - еще 60 строк в /etc/portage/package.keywords/kde3 :) ).&lt;br /&gt;&lt;br /&gt;После первого обновления заработал kdm4. Но куда-то делись все иконки из таскбара. Благо у меня их там не очень много, и я легко находил их на ощупь.&lt;br /&gt;&lt;br /&gt;Второе обновление захотело новый xorg-server. Удовлетворив все зависимости получил полностью неработающую систему. &lt;br /&gt;&lt;br /&gt;Сперва драйвер radeon отказывался запускаться по причине устаревшего abi, полегчало после перекомпиляции.&lt;br /&gt;&lt;br /&gt;После этого kdm запустился, но клавиатура с мышью почему-то не оказывают видимого влияния на систему. И сидишь как дурак, перед экраном kdm, не в состоянии ничего сделать. Только reset.&lt;br /&gt;&lt;br /&gt;Проанализировав логи сервера обнаружил загадочное сообщение:  "AllowEmptyInput default to "yes", keyboard and mouse are disabled", ну что-то около того. Установил переменную в no, клавиатура вернулась на место.&lt;br /&gt;&lt;br /&gt;Мышки опять нет, и опять что-то на тему abi... это мы уже проходили.&lt;br /&gt;&lt;br /&gt;После этого все стало почти замечательно. Только вот в kde-4.2.1 в правом верхнем углу экрана постоянно крутится измеритель производительности какой-то. В принципе работает исправно, на голом десктопе показывает зеленый, сейчас, в konqueror (я теперь могу писать сообщения в blogger в конкуероре!) - красный. Окошки растягиваются, когда их дергаешь... компизовский чтоль изврат? правда компьютер у меня слабоватый, и в эти моменты индикатор чернеет... Можно конечно со стилями побаловатьcя, эффекты поотключать, но мне не столь важно, kate не тормозит. :)&lt;br /&gt;&lt;br /&gt;Дочка один раз что-то нажала, и вокруг курсора появились крутящиеся звездочки. Три веселых крутящихся звездочки. Как она это сделала?&lt;br /&gt;&lt;br /&gt;Вот. А в практическим плане можно отметить вот konqueror, который на движке webkit теперь медленно, но верно показывает 85/100 пунктов в acid3 (firefox 3.0.6 показывает 71/100). И пожалуй все. Остальные приложения как были так и остались. &lt;br /&gt;&lt;br /&gt;Очень много еще всяких глюков, перечислять не буду.&lt;br /&gt;&lt;br /&gt;Похоже, что все новшества kde4 сконцентрированы в основном вокруг графики. Я бы сидел бы на kde3, но с одной стороны интересно что же нас ждет, а с другой стороны в kde3 вряд ли что-то изменится, там своих проблем хватает, которые никто исправлять уже не будет.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-6062545092247947619?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/6062545092247947619/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=6062545092247947619' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/6062545092247947619'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/6062545092247947619'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2009/03/kde4.html' title='kde4: впечатления'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-1902528612902114806</id><published>2009-03-04T14:27:00.010+03:00</published><updated>2009-03-04T14:52:47.501+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='хорошая практика'/><title type='text'>Эффективная работа с унаследованным кодом</title><content type='html'>Вышла в свет русская версия книги Майкла К. Физерса (Michael Feathers) - "Эффективная работа с унаследованным кодом" (Working Effectively with Legacy Code). Какой я блин шустрый, успел заказать ее на озоне за 854 рубля, хотя сейчас она стоит уже 909... &lt;br /&gt;&lt;br /&gt;Не пропустите.&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ozon.ru/context/detail/id/2553986/"&gt;&lt;img style="float:left; margin: 0 10px 10px 0;cursor:pointer; cursor:hand; height: 284px;" src="http://www.ozon.ru/multimedia/books_covers/0131177052.01._sclzzzzzzz_.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.ozon.ru/context/detail/id/4311012/"&gt;&lt;img style="margin: -20px 10px 10px 0;cursor:pointer; cursor:hand; height: 284px;" src="http://www.ozon.ru/multimedia/books_covers/1001044133.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;PS: Только что-то Озон не торопится мне её доставлять. Уже два дня как должен был доставить.&lt;br /&gt;&lt;br /&gt;PPS: Что-то я совсем расслабился, в блог писать некогда. :)&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-1902528612902114806?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/1902528612902114806/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=1902528612902114806' title='Комментарии: 3'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/1902528612902114806'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/1902528612902114806'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2009/03/blog-post.html' title='Эффективная работа с унаследованным кодом'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-8848377038880938951</id><published>2009-01-15T13:30:00.005+03:00</published><updated>2009-01-15T14:22:49.898+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='мысли'/><category scheme='http://www.blogger.com/atom/ns#' term='хорошая практика'/><title type='text'>Хронический аудиал</title><content type='html'>&lt;p align='right'&gt;Что касается женщин, то это чувство сугубо интимное...&lt;/p&gt;&lt;br /&gt;Есть некоторые идеомы, считающиеся хорошими. Например считается правильным писать константную часть слева в условии, для того чтобы на операцию '=' вместо '==' ругался компилятор а не конечный пользователь.&lt;br /&gt;&lt;pre&gt;if (MIN_ELEMENTS == i) ...&lt;br /&gt;&lt;/pre&gt;Я долго не мог понять почему мне это так не нравится, и наконец сформулировал для себя ответ на этот вопрос.&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;Писать так в частности рекоммендует Стив Макконел (Steve McConnell) в книге "Совершенный код". Там же рекоммендуется упорядочивании аргументы в соответствии со значениями на числовой прямой.&lt;br /&gt;&lt;pre&gt;if (MIN_ELEMENTS &lt;= i &amp;&amp; i &lt;= MAX_ELEMENTS) ...&lt;br /&gt;&lt;/pre&gt;Очень похожая ситуация, хотя меня она коробит меньше.&lt;br /&gt;&lt;br /&gt;Есть теория, что люди делятся на визуалов, аудиалов и еще некоторых, которые в данном случае не важны. А может быть и два вышеуказанных тоже не важны, а ответ лежит совсем в другой плоскости. :)&lt;br /&gt;&lt;br /&gt;Может быть такая запись считается удобной и правильной для тех, кто оценивает код визуально. Что же касается меня - я код предпочитаю читать. И читается примерно следующее:&lt;br /&gt;&lt;pre&gt;Если MIN_ELENEMTS равен...&lt;br /&gt;&lt;/pre&gt;Стоп, как может быть константное значение сегодня равно, а завтра не равно? В этом выражении как будто содержится предположение, что MIN_ELEMENTS может измениться.&lt;br /&gt;&lt;br /&gt;Кроме того в предыдущей строке мы вероятно работали с i, почему в условии во главу угла возводится совсем другая сущность? А почему собственно мне кажется что первый идентификатор в выражении возведен во главу угла?&lt;br /&gt;&lt;pre&gt;i равно чему-то; если i равно MAX_ELEMENTS...&lt;br /&gt;&lt;/pre&gt;Все последовательно и логично. Но это если код читать... Если воспринимать код целостно, то, возможно, все воспринимается несколько иначе.&lt;br /&gt;&lt;br /&gt;Тесты наверное врут, когда определяют меня как кинестатика-визуала. Хотя с другой стороны я люблю чтобы было красиво. Я смотрю на код и целиком. Только когда я смотрю на код - я почему-то не смотрю на идентификаторы, Свысока я разглядываю группы операторов, то есть мыслю уже на другом уровне.&lt;br /&gt;&lt;br /&gt;С другой стороны неприятие распределения в соответствии с числовой прямой может связано со складом ума. Предполагаю, что эта запись очень близка к математической, сам то я от математики далек. Может быть людям с математическим складом ума она кажется более естественной чем мне, гуманитарию.&lt;br /&gt;&lt;br /&gt;Я конечно такой человек, что никогда не бываю полностью довольным существующим положением вещей. Но мне бы очень не понравилось, если бы подобные идеомы были бы внесены в соглашение о кодировании. Слишком индивидуальные это вещи.&lt;br /&gt;&lt;br /&gt;PS: Новогодние праздники сильно выбивают из колеи. Ленишься и ничего не хочется делать. Приходится себя заставлять, ну хоть сегодня напиши хоть что нибудь. :)&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-8848377038880938951?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/8848377038880938951/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=8848377038880938951' title='Комментарии: 9'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/8848377038880938951'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/8848377038880938951'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2009/01/blog-post.html' title='Хронический аудиал'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-806603210665283087</id><published>2008-12-23T00:03:00.004+03:00</published><updated>2010-12-27T11:57:02.398+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='отладка'/><title type='text'>uleak</title><content type='html'>Создал новый проект на googlecode, который назвал &lt;a href="http://code.google.com/p/uleak/"&gt;uleak&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Сперва хотел просто выложить куда нибудь исходничек. Но подумал, что из этого может получиться что-то путное, если еще немного поработать.&lt;br /&gt;&lt;br /&gt;Почему такое странное название? С названиями у меня всегда проблема. С одной стороны длинное название труднее запоминать. А с другой стороны длинные названия обычно больше говорят о себе. Но всетаки предпочитаю краткость. uleak - это типа как umount... :) &lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;Надо сказать что в данном виде код пока что мало пригоден к использованию. Требует настройки на цель тестирования, и не имеет никаких сборочных сценариев.&lt;br /&gt;&lt;br /&gt;К тому же, я там всякой фигни наворотил насчет фильтрации функций. Вероятно их надо будет потереть все. Да и с блокировками тоже малость намудрил.&lt;br /&gt;&lt;br /&gt;Да и не все мысли еще воплотились. Например, под linux наверняка можно использовать libUnwind, которая почему-то не работает под FreeBSD. Но под linux uleak пока не заработает. В линуксе его наверное можно будет использовать к уже скомпиленным проектам через LD_PRELOAD, но я никогда с этим не работал.&lt;br /&gt;&lt;br /&gt;Если у кого-то есть в сопровождении проблемные проекты, можно попробовать погонять их с uleak. Это поможет сделать его более универсальным и полезным.&lt;br /&gt;&lt;br /&gt;PS: Кроме того на сайте uleak я доработал &lt;a href="http://code.google.com/p/uleak/wiki/Classification"&gt;классификацию проблем&lt;/a&gt;, с удовольствием выслушаю критику.&lt;br /&gt;&lt;br /&gt;PPS: самый короткий пост?&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-806603210665283087?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/806603210665283087/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=806603210665283087' title='Комментарии: 21'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/806603210665283087'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/806603210665283087'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2008/12/uleak.html' title='uleak'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>21</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-549319796125600085</id><published>2008-12-17T22:42:00.005+03:00</published><updated>2008-12-18T00:32:48.834+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='работа'/><category scheme='http://www.blogger.com/atom/ns#' term='отладка'/><title type='text'>Классификация проблем с памятью</title><content type='html'>Что-то я очень глубоко углубился в эту тему. Но, стабильность сервера пока оставляет желать лучшего, значит я наверное еще не одну статью про отладку напишу.&lt;br /&gt;&lt;br /&gt;До сих пор я не задумывался о том сколько проблем бывает с памятью. Если аккуратно программировать то о них и не приходится задумываться. Но если в наследство достается старый проект, скорее всего он везет с собою массу проблем разного рода. А еще если подумать о том, что архитектура системы представляется пока слабо, руки вообще опускаются.&lt;br /&gt;&lt;br /&gt;Кто-то скажет - переписать... Нет, это путь тупиковый. Всмысле переписать - это непроизводительная деятельность, Надо учиться наводить порядок. :) Но, ближе к теме.&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;Основной проблемой с памятью является ее &lt;b&gt;утечка&lt;/b&gt;. Самая вероятная и часто встречающаяся проблема. Особенно в коде, который активно использует динамическую память. Я как-то выработал у себя привычку не пользоваться динамической памятью без лишней необходимости. Код получается проще, чище и предсказуемее. Ну и что, что на это тратится стек, у меня его много, не вижу проблем.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Но в деле ловли утечек мой ликтрейсер себя пока не показал особо. Проблема в том, что многочисленные операции с памятью производятся из библиотек, и для того чтобы выявить место в приложении - необходимо разворачивать стек. Это отдельная тема для разговора, завтра наверное опишу.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Нарушение границы блока&lt;/b&gt; мне попалось не далее как сегодня. Выделялась память для локального буфера (фу), 26 байт (два раза фу), потом она заполнялась данными и прогонялась через RC2_cbc_encode, который выравнивает данные в большую сторону на 8 байт. Итого 6 байт за границей блока. Но в данном случае это скорее всего не вызывало проблем. malloc вероятно до 16 байт выравнивает и сам, и реально в блоке 6 дополнительных байт точно было. Так никто бы и не узнал о проблеме.&lt;br /&gt;&lt;br /&gt;Эта ошибка является типичной при работе с си-строками.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;В ликтрейсере для этого пришлось ввести дополнительное поле в дескрипторе блока, чтобы предыдущий блок при переполнении портил бы это поле, а данные блока не портил бы. При освобождении состояние этого поля и хвоста блока контролируется и можно точно сказать на сколько байт нарушена память.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Использование блока после освобождения&lt;/b&gt;. Самая опасная форма - модификация блоков, последствия таких ошибок очень сложно предсказать. Но эту форму теоретически можно отслеживать. Если же доступ к блоку осуществляется на чтение, отследить это невозможно. Можно попытаться подобрать данные для заполнения блока при освобождении так, чтобы приложение на них сломалось.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Мой ликтрейсер теоретически может определить изменение блока после освобождения, но это сопряжено со значительными расходами по времени. Да и в связи с тем, что управление код получает только при операциях с памятью, время обнаружения достаточно непредсказуемо. Можно сделать полную проверку памяти при каждой операции, но это очень долго. Хотя, если есть подозрения на порчу памяти после освобождения - это можно попробовать.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Двойное освобождение блока&lt;/b&gt; достаточно серьезная проблема. Если блок с момента освобождения не изменился, то менеджер памяти скорее всего отследит эту ситуацию, но если менеджер памяти уже успел подсуетиться и отдать этот блок кому-то еще, последствия просто непредсказуемы. Он скорее всего освободит его. При этом выделивший ее код останется в неведении.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Менеджер памяти в ликтрейсере устроен так, что дефрагментация памяти и повторное использование блоков, особенно на ранней стадии работы, сведены к минимуму. Что позволяет надеяться что при повторном освобождении этот блок окажется нетронутым, и мы сможем констатировать этот факт. Увеличение размера хипа увеличивает эти шансы.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Использование неинициализированной памяти&lt;/b&gt;. Не знаю как можно извратиться так, чтобы работать с неинициализированным блоком. Но если есть подозрения - можно заполнять блоки при выделении специальным знчением, чтобы сломать приложение.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Выделение блока нулевой длины&lt;/b&gt;. В стандарте си по этому поводу написано, что поведение может определяться реализацией. &lt;code&gt;If the size of the space requested is zero, the behavior is implementation-deﬁned: either a null pointer is returned, or the behavior is as if the size were some nonzero value, except that the returned pointer shall not be used to access an object.&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Однако далеко не всем приложения может понравиться NULL в ответ на malloc. Хотя помоему это наиболее правильный вариант. Допустимым также можно считать указатель куда нибудь на ридонли память, чтобы приложение не пыталось туда что-нибудь писать. Кстати вот не знаю как должен вести себя в этом случае operator new?&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Выделение блоков для этого дела только зря нагружает менеджер, но мне для статистики нужно.&lt;/i&gt; :)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Освобождение нулевого указателя&lt;/b&gt;. Это даже и не проблема а вполне допустимая операция. Но если приложение дергает ее слишком часто - повод задуматься.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;В ликтрейсере даже ругань по этому поводу выключил, очень ее много...&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Спонтанное замусоривание памяти&lt;/b&gt;. Скорее всего возникает в следствии других ошибок. Прежде чем бороться с духами в приложении, лучше разобраться с явными вещами. :)&lt;br /&gt;&lt;br /&gt;PS: Еще немного поковыряюсь с ликтрейсером и наверное выложу его куда нибудь. Может быть будет полезен.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-549319796125600085?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/549319796125600085/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=549319796125600085' title='Комментарии: 5'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/549319796125600085'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/549319796125600085'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2008/12/blog-post_17.html' title='Классификация проблем с памятью'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-6470136931002790543</id><published>2008-12-08T17:10:00.002+03:00</published><updated>2008-12-10T23:30:37.275+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='работа'/><title type='text'>Ловушка для меморилика (проблемы)</title><content type='html'>Основная проблема с перехватыванием функций, работающих с памятью - это бесконечная рекурсия. Десятки функций стандартной библиотек хотят память. Но и нам хочется не просто заменить malloc на свой, но и довести до программиста какую-то полезную информацию. И тогда приходять они... проблемы...&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;Первая проблема возникает тогда, когда мы пытаемся воспользоваться функцией printf. И заключается она примерно в следующем: первый раз malloc вызывается задолго до вызова функции main, и видимо задолго до инициализации подсиситемы ввода-вывода. В результате попытка дернуть printf из malloc приводит к тому, что printf пытается выделить буфер, и опять таки вызывает наш malloc. Замена оператора printf чем нибудь (sprintf, puts, и тд) ничего путного не принесла. Но наша библиотека в любом случае требует инициализации. Мы просто проинициализируем буфер stdout, можно в _IONBF, и эта проблема себя исчерпывает.&lt;br /&gt;&lt;code&gt;&lt;br /&gt;setvbuf(stdout, NULL, _IONBF, 0);&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Другая проблема проявляет себя во всей красе, когда мы пытаемся использовать библиотеку в многопоточном приложении. Как ни крути, а медленный менеджер хипа надо защищать блокировками. Но pthread_mutex_lock, опять таки, вызывает malloc для инициализации tls, локов и тд. Надо сказать что libpthread во FreeBSD весьма закрытая вещ. Все структуры у них сугубо приватны, всмысле в инклюды не включены, и выделить и проинициализоровать лок самостоятельно не выходит.&lt;br /&gt;&lt;br /&gt;Долго бился над этой проблемой. Пытался прикрутить свои блокировки на ассемблере, не помогает. Еще что-то пытался - сейчас уже не вспомню. Но приложение упорно уходило в кору по исчерпанию стека. В результате поступил следующим образом: если гора не идет к Магомету... в смысле, если pthread_mutex_lock вызывает malloc, тогда мы не будем из  malloc вызывать pthread_mutex_lock. Но и совсем от него мы тоже не может отказаться. Мы не будем вызывать блокировку только в том случае, если malloc вызывается из недр libpthread... хотя наверное можно было бы просто сделать проверку на рекурсию, флажек какой нибудь, это наверное тоже сработало бы. Хотя я вроде даже что-то такое пробовал, не помню. Сделал по хитрому. я проверяю адрес возврата на попадание в области критичных к рекурсии функций, и в этом случае не произвожу блокировку. Извращенный метод конечно, но показало себя вполне надежным.&lt;br /&gt;&lt;br /&gt;Но это была еще и не последняя проблема. Последняя проблема с трудом поддается моему пониманию. Заключается она в том, что при переключении потоков приложение падало в функции _thr_setcontext, на операции FXRSTOR. Поковырявшись немного в ядре вычитал, что блок данных для хранения контекста FPU должен быть выровнен на 16 байт. Исправилось выравниванием всех блоков в менеджере хипа на 16 байт. Но так и не могу понять каким образом сохранение контекста FPU производится в буфер, выделенный пользовательским malloc, в пользовательском же пространстве? Возможно, там используется какой-то хитрый коллбек из ядра... странно это. Я полагал, что этим должно заниматься ядро.&lt;br /&gt;&lt;br /&gt;После всего этого ликтрейсер полноценно заработал. Но отдельно я еще расскажу, что, кроме явных утечек, мы можем с помощью него обнаружить.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-6470136931002790543?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/6470136931002790543/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=6470136931002790543' title='Комментарии: 3'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/6470136931002790543'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/6470136931002790543'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2008/12/blog-post_08.html' title='Ловушка для меморилика (проблемы)'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-5433339507756921882</id><published>2008-12-03T11:06:00.009+03:00</published><updated>2008-12-04T17:38:05.323+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='работа'/><title type='text'>Ловушка для меморилика (слайды)</title><content type='html'>&lt;p align='right'&gt;Струя воды толщиной в спичку&lt;br /&gt;дает утечку двести литров в сутки...&lt;br /&gt;(c) Афоня&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;Нелегкая это работа, замещать malloc. Столько хвостов за ним отовсюду тянется. Всю голову чуть не сломал, пока наконец удалось прикрутить ликтрейсер к многопоточному серверу. Подопытный пока чувствует себя хорошо и функционирует как обычно.&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;Правда тормозит немного. Потому, что помимо медленного менеджера памяти, я там еще и замусоривание блоков прикрутил при выделении и при освобождении, если кто-то попытается использовать память после освобождения - это станет для него фатально.&lt;br /&gt;&lt;br /&gt;Но обо всем попорядку. Как же это работает?&lt;br /&gt;&lt;br /&gt;Сразу отмечу, что данный код работает только под FreeBSD 32bit, возможно он сможет работать и под Linux - не проверял, но точно не заработает на 64-х битной платформе. Кроме того весь код приводить тоже не буду, может быть выложу куда нибудь.&lt;br /&gt;&lt;br /&gt;Для того, чтобы избежать любой модификации кода мы делаем как бы свою библиотеку стандартных функций по работе с памятью. В этот список входят следующие функции:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;extern "C" void *malloc (size_t size);&lt;br /&gt;extern "C" void *calloc (size_t number, size_t size);&lt;br /&gt;extern "C" void *realloc (void *ptr, size_t size);&lt;br /&gt;extern "C" void *reallocf (void *ptr, size_t size);&lt;br /&gt;extern "C" void free (void *ptr);&lt;br /&gt;extern "C" char *strdup(const char *str);&lt;br /&gt;void *operator new(size_t size);&lt;br /&gt;void operator delete (void *ptr) throw();&lt;br /&gt;void *operator new[] (unsigned int size);&lt;br /&gt;void operator delete[] (void *ptr) throw();&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Каждая из этих функций представляет из себя обертку к медленному и простому хип менеджеру.&lt;br /&gt;Например:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;extern "C"&lt;br /&gt;void *malloc (size_t size)&lt;br /&gt;{&lt;br /&gt; return salloc (size);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Но этого мало. Прежде чем переходить к менеджеру хипа необходимо определить точку вызова функции. Сделать это можно просто, в стеке после первого параметра функции хранится адрес возврата. Его достаточно для идентификации места вызова, но я, как дурак, зачем то, пытаюсь детектить вызывающие инструкции.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;static&lt;br /&gt;uint32_t getCallPoint(const void *stack)&lt;br /&gt;{&lt;br /&gt; const uint32_t *sptr = reinterpret_cast&lt;const uint32_t *&gt;(stack);&lt;br /&gt; return sptr[-1];&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;extern "C"&lt;br /&gt;void *malloc (size_t size)&lt;br /&gt;{&lt;br /&gt; const uint32_t cp = getCallPoint(&amp;size);&lt;br /&gt; return salloc (size, cp);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Вот так будет достаточно. Что же касается менеджера памяти, то переопределив malloc во FreeBSD мы потеряли всякую возможность воспользоваться стандартным, и вынуждены писать свой. Но так даже лучше, в четвертой статье расскажу почему.&lt;br /&gt;&lt;br /&gt;Релизация у него будет предельно проста. Заводится статический буффер большого размера. Определяется структура заголовка блока, которая состоит из двух полей: cp - точка выделения блока, и size - размер блока. Если cp имеет нулевое значение - это обозначает, что блок пуст.&lt;br /&gt;&lt;br /&gt;И для учета блоков по точкам вызова мы заводим массив структур:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;struct callpoint {&lt;br /&gt; uint32_t cp;&lt;br /&gt; uint32_t current_blocks;&lt;br /&gt; uint32_t max_blocks;&lt;br /&gt; uint32_t size;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;static struct callpoint scps[cnum];&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Размеры хипа и таблицы точек вызова я выбрал вроде бы с запасом, 16 мегабайт и 4096 точек. При выделении каждого блока я нахожу соответствующую точке запись и увеличиваю счетчик блоков. Если current_blocks превышает max_blocks, это может быть утечка. Для понижения уровня шума max_blocks можно проинициализировать некоторым значением - у меня 100. То есть до 100 блоков на точку - ругани не будет, дальше будет. И при каждом повышении количества блоков ругань будет продолжаться.&lt;br /&gt;&lt;br /&gt;При освобождении блока я извлекаю точку вызова из информации блока, ищу эту точку в таблице и понижаю счетчик current_blocks.&lt;br /&gt;&lt;br /&gt;В таком виде это будет легко работать на однопоточных приложениях. Про многопоточные позже.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-5433339507756921882?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/5433339507756921882/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=5433339507756921882' title='Комментарии: 6'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/5433339507756921882'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/5433339507756921882'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2008/12/blog-post.html' title='Ловушка для меморилика (слайды)'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-2745943946843721275</id><published>2008-11-26T22:00:00.005+03:00</published><updated>2008-12-01T22:55:48.724+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='работа'/><title type='text'>Ловушка для меморилика</title><content type='html'>Не знаю как люди ловаят мемориликов. Пробовал google-perftools, что-то ничего не говорит даже на примитивный пример с единственным malloc. valgrind можно было бы попробовать прикрутить, но это связано с определенными трудностями, поскольку меморилик затаился в сервере c замкнутой программной средой на базе FreeBSD.&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;К ловле меморилика надо подходить творчески.&lt;br /&gt;&lt;br /&gt;Заменить все вызовы malloc на debug_malloc, а потом вглядываться в исписанный экран в поисках утечки - это не наш метод. Хотя при должном уровне автоматизации он тоже должен дать плоды, но такой метод обычно требует модификации кода, и поэтому не является предпочтительным.&lt;br /&gt;&lt;br /&gt;Что касается должного уровня автоматизации, я считаю что мало вывести на экран информацию. Гораздо лучше, если эту информацию предварительно обработать. Что же мы можем сделать в случае выделения/освобождения памяти?&lt;br /&gt;&lt;br /&gt;Для выделения памяти приложением используются несколько функций, и для освобождения тоже несколько. Поскольку это функции, то их обязательно кто нибудь должен вызывать, и по адресу возврата из стека мы конечно не сможем определить файл и строку, но сможем определить адрес инструкции, которая инициировала ту или иную операцию с памятью. По адресу легко можно определить функцию, воспользовавшись nm.&lt;br /&gt;&lt;br /&gt;И как это может нам помочь? Количество вызовов операций по работе с памятью - достаточно ограниченное. Не составит большого труда следить за всеми обнаруженными точками вызовов. А чтобы это было полезным - мы будем собирать статистику по количеству блоков на каждую точку выделения. Если тенденция выделения блоков стремится вверх, значит в этой точке вызова идет утечка.&lt;br /&gt;&lt;br /&gt;Некоторая проблема есть в том, что работать придется практически на системном уровне. Для реализации мы пишем свои версии malloc, free, realloc, strdup, ::operator new и других, оперирующие с памятью функций. в начале каждого обработчика определяем точку вызова. Но возможности вызвать функции из стандартных библиотек у нас уже нету.&lt;br /&gt;&lt;br /&gt;Поэтому выделять память нам тоже придется по своему. Скорость не важна, можно просто выделяем большой статический буфер, и примитивным образом делим его на блоки. Но главное, не забываем собирать статистику. Необходимо помнить какой блок из какой точки вызова выделен, в случае освобождения блока мы понижаем счетчик этой точки вызовов. Паралельно с выделением/освобождением можно следить за размером блоков, эта информация может быть полезной при локализации места ошибки.&lt;br /&gt;&lt;br /&gt;Помимо счетчика блоков точки вызова мы отслеживаем также максимальное значение счетчика блоков точки вызова. В случае, если счетчик превышает свое максимальное значение - ругаемся. Пока статистика работы приложения не накопилась - ругани очень много. Но с каждой минутой ее становится меньше и меньше, пока не останутся одни только меморилики, счетчики которых будут только расти.&lt;br /&gt;&lt;br /&gt;Но на практике реализация всего этого встречает несколько проблем. О них в следующий раз.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-2745943946843721275?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/2745943946843721275/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=2745943946843721275' title='Комментарии: 11'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/2745943946843721275'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/2745943946843721275'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2008/11/blog-post_26.html' title='Ловушка для меморилика'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-5017218692631560580</id><published>2008-11-20T13:07:00.002+03:00</published><updated>2008-11-20T13:32:30.233+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='работа'/><title type='text'>Отгадки времени</title><content type='html'>Забавная проблема возникла на работе. Разрабатываем мы Континент, в нем есть компонент - сервер доступа. Он позволяет пользователям подключаться к VPN извне. Авторизация осуществляется на сертификатах, технология открытых ключей, как там ее.&lt;br /&gt;&lt;br /&gt;Появился баг - Невозможно создать сертификат с датами начала/окончания срока действия меньше/больше соответственно 1950/2049гг. Причем интерфейс позволяет ввести в качестве года значение от 1753 до 4111. И откуда взялись эти странные цифры?&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;Приоритет у запроса естественно был ниже плинтуса, но руки до него всетаки дошли и выяснилось следующее... Время в сертификате может храниться в двух форматах: UTCTime и generalizedTime. Отличаются они собственно одним - UTCTime ограничивает значение года только двумя значащими цифрами, а generalizedTime - позволяет указывать четыре.&lt;br /&gt;&lt;br /&gt;Понятно уже, что сервером обрабатывался только первый вариант. Там правда были прикручены какие-то костыли на тему трех и четырехзначного значения года, но никаких попыток обработать поля типа generalizedTime не производилось.&lt;br /&gt;&lt;br /&gt;Дело не сложное, переписал функцию, и появилась возможность анализировать и тот и другой, но не все так гладко. (Иначе и не стал бы растекаться тут мысью по дереву). Сравнивается то все это дело с текущим временем, для того, чтобы определить действует ли сейтификат в данный момент.&lt;br /&gt;&lt;br /&gt;Но текйщий момент времени мы можем получить только в time_t, диапазон которого ограничен датами от 1970 до 2037 года. &lt;br /&gt;&lt;br /&gt;Но и generalizedTime сконвертировать в time_t сразу не получится. Можно воспользоваться структурой tm, диапазон которой снизу ограничен 1900 годом.&lt;br /&gt;&lt;br /&gt;Сплошные ограничения. Могли бы создать проблемы, если бы текущее время системы можно было задвинуть за пределы 1970 года. Думаю что ни одна система этого сейчас не потерпит, а нам нужно только убедиться, что сертификат действует сейчас. Поэтому время сертификата можно смело обрубить до диапазона time_t, и сравнивать с текущим.&lt;br /&gt;&lt;br /&gt;Хотя сам сертификат может иметь даты в значительно более широких пределах. Вопрос в том, кому это надо? По хорошему, выписывать сетификаты задним числом вообще не правильно.&lt;br /&gt;&lt;br /&gt;Ссылки по теме: RFC2459, RFC3161.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-5017218692631560580?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/5017218692631560580/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=5017218692631560580' title='Комментарии: 4'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/5017218692631560580'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/5017218692631560580'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2008/11/blog-post_20.html' title='Отгадки времени'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-3810162152778076030</id><published>2008-11-18T15:32:00.004+03:00</published><updated>2010-07-02T11:43:39.605+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='работа'/><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='планирование работ'/><title type='text'>Заниматься делом</title><content type='html'>У нас внедряется SCRUM. Сейчас идет третья двухнедельная итерация с момента внедрения. Можно сказать, что только начали ощущать вкус этого дела. До реальной пользы от гибких технологий нам еще далеко.&lt;br /&gt;&lt;br /&gt;Момент внедрения выбран не особо удачно. Cертификация на носу, а через неделю после нее релиз. Модульным тестированием в проекте и не пахнет, автоматизация на нуле, и даже ночные билды не обходятся без человеческого участия.&lt;br /&gt;&lt;br /&gt;Но статья не про это.&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;Традиционный SCRUM, ежели таковой встречается в природе, подразумевает однородность комманд. То есть вся команда должна состоять из специалистов одного профиля. Например из одних программистов. Наши команды не такие. На треть они состоят из тестировщиков. Что вносит смуту в организацию работ. Наш таскборд состоит из 5 колонок: todo-coding-implemented-testing-done. Я бы конечно оставил три, но это вызывает проблемы с идентификацией работ по тестированию. Может быть выделять их цветом?&lt;br /&gt;&lt;br /&gt;Самое главное в SCRUM - научиться выделять работы. Не просто абстрактные возможности (как мне не нравится слово фичи), а конкретные действия, которые необходимо провести, чтобы реализовать данную возможность. Осознание этого позволяет точнее оценивать продолжительность работы.&lt;br /&gt;&lt;br /&gt;Ничто так не поднимает дух команды, как стремительно понижающийся график сгорания работ (burndown chart). :) Для этого очень важно соблюдать правило - одна бумажка - одно дело - один человек. Задачи перемещаются только в сторону завершения. Это в любой методологии написано, но у нас, почему-то, приживается с трудом. Упорно пытаемся одну бумажку делить на разработчика, тестировщика, еще кого нибудь, поэтому до завершения они добираются достаточно медленно, к концу итерации дай бог. :)&lt;br /&gt;&lt;br /&gt;Видимо это происходит из привычной всем схемы работы над ошибками - ошибка может десятки раз ходить от тестировщика к разработчику, до тех пор, пока ее не исправят и не закроют. А это происходит из за того, что кто-то не ставит перед собой реальных задач. Гадание на кофейных гущах какое-то. Исправлять ошибку можно долго, можно заниматься этим годами. Но в условиях SCRUM надо научиться отвечать на вопрос - чем я собираюсь заниматься сегодня. Не так, что сегодня я мусолю ошибку номер xxxx, хрен знает что там такое. А стараться конкретизировать работу. Например: Чтобы исправить эту ошибку я прикручу такие-то возможности, и это позволит понять в чем дело. &lt;br /&gt;&lt;br /&gt;Вовсе необязательно сразу иметь готовый ответ на все, зачастую это невозможно. Достаточно наметить ясные пути решения и запланировать первые работы. После того как эти работы завершены - уже с новым взглядом на проблему можно запланировать несколько следующих.&lt;br /&gt;&lt;br /&gt;Об этом &lt;a href="http://local.joelonsoftware.com/mediawiki/index.php/%D0%9F%D0%BB%D0%B0%D0%BD%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE_%D0%BE%D0%B1%D0%B5%D1%81%D0%BF%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D1%8F_%D0%BC%D0%B0%D0%BB%D0%BE%D0%B9_%D0%BA%D1%80%D0%BE%D0%B2%D1%8C%D1%8E"&gt;писал Джоэл&lt;/a&gt;, что выпонение конкретных и тривиальных задач не составляет проблем ни у кого. Необходимо только научиться разбивать нетривиальные и неоднозначные задачи на простые.&lt;br /&gt;&lt;br /&gt;Есть некоторая проблема в том, что список работ постоянно пополняется новыми задачами по старым проблемам, но я не вижу в этом ничего страшного. В любом случае работы рассматриваются приоритетно и все надо делать. Низкоприоритетные работы могут остаться не выполненными - это тоже нормально.&lt;br /&gt;&lt;br /&gt;Что касается тестировщиков, во избежание большого количества бумажек только крупные работы у нас имеют отдельный этап тестирования. Мелкие работы так и кочуют через все пять колонок таскборда, главное чтобы они не возвращались обратно. Если тестирование выявляет ошибки - ошибки появляются на новых (красных) бумажках с новым временем.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-3810162152778076030?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/3810162152778076030/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=3810162152778076030' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/3810162152778076030'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/3810162152778076030'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2008/11/blog-post_18.html' title='Заниматься делом'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-6350865574459431678</id><published>2008-11-11T17:13:00.006+03:00</published><updated>2008-11-11T23:25:13.484+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='дети'/><category scheme='http://www.blogger.com/atom/ns#' term='gentoo'/><title type='text'>Компьютер для ребенка</title><content type='html'>Этим постом начну цикл статей про компьютер для ребенка. Последнее время как-то не до блога особенно, на работе вводится SCRUM, и времени практически нету. Но жизнь идет и мысли надо куда-то девать?&lt;br /&gt;&lt;br /&gt;Но ближе к теме. Мне кажется многие родители, да почти все, весьма халатно относятся к данной теме. У моего ребенка до сих пор не было собственного компьютера, но в этом году он пошел в школу, и я решил что пора заняться этим делом и наконец таки попытаться переломить у него стойкий стереотип что компьютер - это игрушка.&lt;br /&gt;&lt;br /&gt;Поскольку компьютер я делаю не для игр, то проблема железа не стоит. Для обучающих целей подходит абсолютно любой компьютер, даже очень старый. Ну разве что монитор пожидкокристалличнее выбрать. Были мысли даже сделать x-терминал, но немного подумав решил, что при отсутствии домашнего сервера детскому компьютеру стоит быть более самостоятельным.&lt;br /&gt;&lt;br /&gt;В качестве системы я естественно выбрал свою любимую Gentoo.&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;Не знал, что cdrom приводы Pioneer такие проблематичные, linux категорически отказывается воспринимать его как cdrom, без магического &lt;code&gt;hdc=noprobe hdc=cdrom&lt;/code&gt;. Я несколько дней потратил в поисках нормально загружающегося и содержащего все необходимые инструменты linux'а, в конце концов обнаружил магическую комбинацию и вернулся к тому, с чего начал - с Gentoo &lt;code&gt;install-x86-minimal-2008-r1.iso&lt;/code&gt;. &lt;br /&gt;&lt;br /&gt;Забыл сказать, что детский компьютер у меня Pentium-MMX (молодой еще, всего 10 лет ему :D ). Видео они конечно смотреть на нем не смогут (если я видеокарту не поставлю какую нибудь более мощную), но аудио слушать смогут вполне. Да и десктоп должен вполне нормально крутится. При случае сделаю апгрейд.&lt;br /&gt;&lt;br /&gt;Итак, чтобы накатить Gentoo на такой допотопный компьютер надо много времени... Но есть способ проще - Воспользуемся distcc. Сами portage делаем доступными с моего компьютера по NFS. Но есть еще проблема с компилятором. у меня &lt;code&gt;i686-pc-linux-gnu&lt;/code&gt;, а там &lt;code&gt;i486-pc-linux-gnu&lt;/code&gt;. Переводить его на i586 не вижу большого смысла, Я вообще не вижу особой разницы между i486, i586, i686, если кто знает о такой разнице - сообщите мне пожалуйста. Но для полноценной работы distcc необходимо, чтобы на моем родительском хосте стоял, кроме всего прочего, еще и &lt;code&gt;i486-pc-linux-gnu&lt;/code&gt;. &lt;br /&gt;&lt;br /&gt;Для этого устанавливаем crossdev, portage overlays должны быть настроены, и выполняем &lt;br /&gt;&lt;code&gt;&lt;br /&gt;# crossdev -S i486-pc-linux-gnu&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Через некоторое время все необходимое устанавливается, но не совсем. Не знаю по каким причинам все установленные пакеты не включаются в world-файл и будут снесены при &lt;code&gt;emerge --depclean&lt;/code&gt;. Для того чтобы этого избежать я добавил их в &lt;code&gt;/var/lib/portage/world&lt;/code&gt; руками.&lt;br /&gt;&lt;code&gt;&lt;br /&gt;crossdev-i486-pc-linux-gnu/binutils&lt;br /&gt;crossdev-i486-pc-linux-gnu/linux-headers&lt;br /&gt;crossdev-i486-pc-linux-gnu/glibc&lt;br /&gt;crossdev-i486-pc-linux-gnu/gcc&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Свои системы я набиваю полнее, но здесь можно отказаться от многого ненужного. &lt;br /&gt;&lt;br /&gt;Например нету никакой необходимости интернационализировать консоль. как следствие keymaps и consolefonts тоже можно отключить.&lt;br /&gt;&lt;code&gt;&lt;br /&gt;# rc-update del keymaps&lt;br /&gt;# rc-update del consolefonts&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Также нет никакой необходимости в info, man и doc.&lt;br /&gt;&lt;code&gt;&lt;br /&gt;make.conf: FEATURES="noman nodoc noinfo"&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;На данный момент у меня завершается частичная компиляция kde. В следующий раз я расскажу, что собственно хочу туда залить и какие сетевые возможности собираюсь предоставить детям.&lt;br /&gt;&lt;br /&gt;Ссылки:&lt;br /&gt;&lt;a href="http://ru.gentoo-wiki.com/HOWTO_Portage_через_NFS"&gt;HOWTO: Portage через NFS&lt;/a&gt; (на данный момент недоступно, не знаю вернется ли вновь)&lt;br /&gt;&lt;a href="http://www.gentoo.org/doc/ru/distcc.xml"&gt;Описание distcc в Gentoo&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.gentoo.org/doc/en/cross-compiling-distcc.xml"&gt;DistCC Cross-compiling Guide&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;PS: Надо сказать что смотреть длинные видео через youtube не особо удобно. Смотрел тут про концепты по &lt;a href="http://deepencpp.blogspot.com/2008/11/concepts-extending-c-templates-for.html"&gt;ссылке Юрия Волкова&lt;/a&gt;, на 20 минуте (смотрел я с долгими паузами) все заглючило и перестало воспроизводиться. Что сподвигло меня на поиск даунлоадеров, помню был какой-то консольный, найти не могу, зато нашел &lt;a href="http://packages.gentoo.org/package/kde-misc/youtube-servicemenu"&gt;kde-misc/youtube-servicemenu&lt;/a&gt;, теперь можно сохранять ролики из контекстного меню konqueror.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-6350865574459431678?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/6350865574459431678/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=6350865574459431678' title='Комментарии: 4'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/6350865574459431678'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/6350865574459431678'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2008/11/blog-post.html' title='Компьютер для ребенка'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-299284081695534493</id><published>2008-10-08T12:32:00.006+04:00</published><updated>2010-07-02T13:59:46.497+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gentoo'/><category scheme='http://www.blogger.com/atom/ns#' term='crypto'/><title type='text'>Управление сертификатами?</title><content type='html'>У нас в фирме практикуется подписывание и шифрование сообщений. Оно конечно не является строго обязательным, но некоторая информация присылаются в шифрованном виде. В любом случае это очень полезная возможность и неплохо было бы ее иметь.&lt;br /&gt;&lt;br /&gt;Но в линуксе с этим обстоит как-то не слишком радостно. Может быть в других дистрибутивах дела обстоят получше, не знаю. У меня все происходит примерно так:&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;Не знаю почему, но видимо в linux бытует такое мнение, что PGP работает на ключах. Хотя я считаю что инфраструктура шифрования базируется на сертификатах. Это конечно мелочи, но управление сертификатами в линуксе реализовано из рук вон плохо.&lt;br /&gt;&lt;br /&gt;Для начала импорт сертификата. Сертификат с закрытым ключем хранится в контейнере pkcs12, gpgsm (утилита для манипулирования сертификатами) в этом формате воспринимает только ключи. Начинаем колдовать.&lt;br /&gt;&lt;br /&gt;Сперва обеспечим автоматический запуск gpg-agent. Честно говоря, не знаю как правильно сделать это в kde. Хотя судя по всему &lt;a href="http://gentoo-wiki.com/HOWTO_KMail_gpg-agent_kde#Setting_up_gpg-agent_with_KDE"&gt;здесь&lt;/a&gt; описан правильный рецепт (надо дописать себе скриптик для выгрузки). Но есть одна проблема. Иногда gpg-agent может ругаться со словами:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;gpg-agent[17182]: can't connect to `/home/gor/.gnupg/S.gpg-agent': В соединении отказано&lt;br /&gt;gpg-agent: нет gpg-agent доступого для данной сессии&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Это решается путем добавления флага &lt;code&gt;--use-standard-socket&lt;/code&gt; при вызове агента или добавлением опции &lt;code&gt;use-standard-socket&lt;/code&gt; в файле конфигурации &lt;code&gt;~/.gnupg/gpg-agent.conf&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Импортируем закрытый ключ:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;$ openssl pkcs12 -in keycert.p12 -out keycert.pem -nodes&lt;br /&gt;$ openssl pkcs12 -in keycert.pem -export -out key.p12 -nocerts -nodes&lt;br /&gt;$ gpgsm --call-protect-tool --p12-import --store key.p12&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Непонятно почему, но извлечь ключ сразу из .p12 не получается. Зато получается извлеч сертификат.&lt;br /&gt;&lt;code&gt;&lt;br /&gt;$ openssl pkcs12 -in keycert.p12 -out certs.pem -nokeys&lt;br /&gt;$ gpgsm --import certs.pem&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Чтобы это все заработало необходимо иметь доверие к корневому сертификату. Списки доверенных сертификатов хранятся в &lt;code&gt;~/.gpg/trustlist.txt&lt;/code&gt;. Там должен быть указан fingerptint корневого сертификата и опциональный флаг. Можно поручить это дело gpg-agent'у, указав ему при запуске опцию &lt;code&gt;--allow-mark-trusted&lt;/code&gt;, или &lt;code&gt;allow-mark-trusted&lt;/code&gt; в файле &lt;code&gt;~/.gnupg/gpg-agent.conf&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Но это еще далеко не все. Мы можем попытаться указать сертификат S/MIME в kmail, но на попытку подписи получим сообщение - Ошибка шифрования. Чтобы узнать подробности необходимо включать протокол работы gpgsm. Это можно сделать через настройку kmail, правда я не совсем понимаю как работает socket в качестве файла протокола, я указал просто имя файла. Что касается debug-level, то можно использовать следующие значения: none, basic, advanced, expert, guru. И после включения протокола можно узнать, что для полного счастья gpgsm не хватает dirmngr, это демон хранения CRL (почему он не в зависимостях?).&lt;br /&gt;&lt;code&gt;&lt;br /&gt;# emerge dirmngr&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;После этого в kmail почти все работает. Кроме одного неприятного момента. В окнах pinentry все сообщения выводятся закорючками, хотя судя по логу кодировку она использует системную.&lt;br /&gt;&lt;br /&gt;Для шифрования почты кому либо надо его сертификат указать в настройках абонента в адресной книге, ну это в принципе логично.&lt;br /&gt;&lt;br /&gt;PS: Все манипуляции с сертификатами, по идее, призвана обеспечивать программа Kaleopatra. Не знаю в каком формате сертификаты ей нужны, но ни .p12, ни .pem она не воспринимает.&lt;br /&gt;&lt;br /&gt;Полезные ссылки:&lt;br /&gt;&lt;a href="http://www.mew.org/feature/smime.html.en"&gt;Mew's S/MIME Support&lt;/a&gt;&lt;br /&gt;&lt;a href="http://gentoo-wiki.com/HOWTO_KMail_gpg-agent_kde"&gt;HOWTO KMail gpg-agent kde&lt;/a&gt;&lt;br /&gt;&lt;a href="http://netzmb.blogspot.com/2008/03/gnupg-gpg-agent_12.html"&gt;запоминалка gnupg-пароля, используем gpg-agent&lt;/a&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-299284081695534493?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/299284081695534493/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=299284081695534493' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/299284081695534493'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/299284081695534493'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2008/10/blog-post_08.html' title='Управление сертификатами?'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-159875585533214226</id><published>2008-10-04T16:20:00.009+04:00</published><updated>2010-12-27T12:20:37.052+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='работа'/><title type='text'>Автоматизация тестирования</title><content type='html'>За что я люблю свою работу - это за то, что не скучно. Я бы наверное умер бы от скуки лет пять назад, если бы трудился все свое время над одним единственным проектом. Может быть поэтому и бытует мнение, что раз в три года надо менять работу? Мне не скучно. Редкий проект затягивается больше чем на год. Причем разнообразие в моей работе весьм радикально. Позапозавчера я писал под Линукс, позавчера под линукс для ARM, вчера под FreeBSD на Perl, сегодня я занимаюсь автоматизацией тестирования. :) Под Windows я тоже иногда пишу. Между АРМ и Perl почти месяц потратил на поддержку АРМ ЭЦП. И еще жду не дождусь, когда меня допустят до CSP, ух, я его перекопаю. Но это если меня на сервер под FreeBSD не посадят. Что-то мне FreeBSD не нравится, сил нету, хотя мне же под нею и не жить. Жить я предпочитаю в Linux, даже Windows запускаю в виртуали, благо компьютер мощный.&lt;br /&gt;&lt;br /&gt;Но ближе к делу. Итак Автоматизация тестирования. Встала тут задача автоматизировать тестирование нашего сервера &lt;a href="http://www.infosec.ru/products/products/continent/"&gt;Континент&lt;/a&gt; (здесь могла бы быть ваша реклама, но стоит наша). Чтобы сразу после ночных билдов сервер автоматически инсталлировался, запускался и специальным инструментом, который мы писали на прошлом этапе, тестироватся бы на соответствие.&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;Собственно сервер представляет из себя замкнутую среду на базе FreeBSD, ни о каких vmware-tools речи там быть не может. Но надо ведь его как-то проинсталлировать без вмешательства человека. А инсталляция происходит в интерактивном режиме, вопрос/ответ.&lt;br /&gt;&lt;br /&gt;Три дня я ломал голову над тем как можно постать в гостевую систему в vmware нажатия клавиш. Я посмотрел VI Perl (не работает ни с VMWare Server ни с Workstation), VIX - работает, но список его функций без mware-tools весьма ограничен. Там даже нельзя подключить носитель!&lt;br /&gt;&lt;br /&gt;Я сел за Visual Studio и долго изголялся с SendInput, но VMWare Ctrl+G получает благополучно, а после блокировки клавиатуры - ничего не ловит, видимо перехватывает ввод где-то еще глубже, хотя уж куда глубже? SendInput прокачивает на ввод сканкоды.&lt;br /&gt;&lt;br /&gt;Нагуглил, что есть filter driver. И даже видел фрагменты кода, как с помощью этого симулировать нажатия на клавиши, но фрагмент кода был весьма невелик, что-то не осилил я эту премудрость. Да и не факт что это сработало бы с vmware.&lt;br /&gt;&lt;br /&gt;Причем в процессе разбирательства с SendInput я вспомнил про то, что QEMU позволяет вводить символы в гостевой ОС без блокирования клавиатуры. Проверил свои догадки - точно работает, всмысле вводит все как положено в гостевой системе. Но использование QEMU не входило в наши основные планы, в которые входило создание тима в vmware workstation и тестирование серверов в тиме.&lt;br /&gt;&lt;br /&gt;И только под конец рабочего дня, когда я уже отчаялся послать что-то в vmware, мне пришла в голову замечательная мысль. А почему бы мне не автоматизировать инсталляцию с помощью QEMU, при этом вовсе не обязательно в том же QEMU производить и тестирование. Тем более, что QEMU прекрасно поддерживает vmdk.&lt;br /&gt;&lt;br /&gt;И вот в пятницу с утреца я довел до ума программку, которая посылает строки в виртуальную машину. После чего засел за Visual Build, который первым делом вызывал QEMU для инсталляции, выжидал определенное время до первого вопроса инсталлятора (Хотите ли вы установить Континент?), и начинал посылать туда 'y', всякие необходимые цифры. После окончания инсталляции дожидается перезагрузки, убивает QEMU, запускает ее снова, уже для загрузки с винта, опять куча вопросов, и наконец последняя перезагрузка, QEMU по halt выключается сам, после чего запускается машина vmware, с уже настроенной рабочей конфигурацией, и сконфигурированный сервер стартует как ни в чем не бывало.&lt;br /&gt;&lt;br /&gt;Только потом я уже сообразил, что наверное можно было бы обойтись и без отдельной программки для передачи символов. Visual Build поддерживает различные скрипты, которые наверное вполне могут позволить сделать FindWindow, SetForegroundWindow и SendInput. Но в скриптах я не силен, мне проще отдельную программульку написать.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-159875585533214226?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/159875585533214226/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=159875585533214226' title='Комментарии: 0'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/159875585533214226'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/159875585533214226'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2008/10/blog-post.html' title='Автоматизация тестирования'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-2617602968239475955</id><published>2008-10-01T15:19:00.006+04:00</published><updated>2010-07-02T11:45:51.931+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='windows'/><title type='text'>Windows как второй монитор...</title><content type='html'>Сейчас стало модно работать за двумя мониторами, или даже за &lt;a href="http://gentoo-wiki.com/Triple_Monitors"&gt;тремя&lt;/a&gt;. Причем технология работы различается.&lt;br /&gt;&lt;br /&gt;Традиционно двухмониторное рабочее место организуется путем объединения двух мониторов в один виртуальный рабочий стол. Вроде бы не за чем иметь один рабочий стол, достаточно того, чтобы мышка могла переезжать с одного экрана на другой. Это позволить переносить приложения и работать полноценно за обоими мониторами. К сожалению я еще недостаточно ориентируюсь в теме использования нескольких мониторов, и не до конца представляю себе рабочий процесс на двух объединенных в один рабочий стол мониторах. Проверю как нибудь на работе. &lt;br /&gt;&lt;br /&gt;Можно поступить немного проще, и сделать один монитор информационным, то есть копипастить будет нереально, но информация будет видна. А X11 позволяет использовать в качестве дисплеев даже экраны соседних компьютеров.&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;Вот собственно над этим и задумался я, решив использовать дисплей соседней винды для отображения информации. И это оказалось очень даже просто.&lt;br /&gt;&lt;br /&gt;Для начала идем с винды на &lt;a href="http://x.cygwin.com"&gt;сайт&lt;/a&gt;, и жмем кнопку 'Install Cygwin/X now'. В появившемся окне инсталлятора cygwin выбираем xorg-x11-base из категории X11. После окончания установки запускаем cygwin&lt;br /&gt;&lt;code&gt;C:\cygwin\Cygwin.bat&lt;/code&gt;&lt;br /&gt;и в появившемся окне запускаем xorg server&lt;br /&gt;&lt;code&gt;$ startx&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Теперь можно подключаться удаленно. Для этого надо переустановить переменную DISPLAY и запустить необходимое приложение. &lt;br /&gt;&lt;code&gt;$ DISPLAY=192.168.1.3:0.0 kate &amp;&lt;/code&gt;&lt;br /&gt;после чего мы сможем увидеть на windows машине, нет, не kate, а сообщение об ошибке:&lt;br /&gt;&lt;code&gt;... X: client 6 rejected from ip 192.168.1.2&lt;/code&gt;&lt;br /&gt;Чтобы windows машина нас пустила, необходимо на ней выполнить команду:&lt;br /&gt;&lt;code&gt;xhost +192.168.1.2&lt;/code&gt;.&lt;br /&gt;Теперь снова повторяем вызов kate (к примеру) и видим нашу Катю на рабочем столе Windows.&lt;br /&gt;&lt;br /&gt;К сожалению информация о хсте не сохранится до следующего запуска. Чтобы она сохранилась надо редактировать файл /etc/X*.hosts, как написано в man xhost, но что-то у меня пока не сработало...&lt;br /&gt;&lt;br /&gt;Только не стоит забывать что само то приложение реально работает на Linux машине, Можно легко дезориентироваться, ибо изображение находится на мониторе виндовой тачки, и управлять им надо виндовой мышкой.&lt;br /&gt;&lt;br /&gt;PS: Хотя с другой стороны наверное логично то, что kde desktop не может использовать удаленные рабочие столы. Забросить туда приложение наверное не сложно, а после этого оно становится недосягаемо для текущей мышки - проблема.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-2617602968239475955?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/2617602968239475955/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=2617602968239475955' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/2617602968239475955'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/2617602968239475955'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2008/10/windows.html' title='Windows как второй монитор...'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-5424733114527724455</id><published>2008-09-30T10:47:00.007+04:00</published><updated>2010-04-27T15:16:56.116+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='мысли'/><category scheme='http://www.blogger.com/atom/ns#' term='gentoo'/><category scheme='http://www.blogger.com/atom/ns#' term='exherbo'/><title type='text'>Революции нужны?</title><content type='html'>Я сторонник эволюционного подхода. То есть я верю что любая программа может планомерно мутировать куда нужно. При условии, что совместимость со всем прошлым не стоит как задача. То есть я не отрицаю частичную совместимость. Например KDE 4.0, 4.1, 4.2 должны быть совместимы между собой. Но нету никакой необходимости поддеживать запуск приложений 10-ти летней давности. Это нужно только гнусным проприетарщикам. :)&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;В то же время совместимость - понятие разноплановое. Совместимость бывает бинарная, или сборочная, или скриптовая.&lt;br /&gt;&lt;br /&gt;Бесспорно то, что программы должны развиваться. То есть, новый функционал неизбежно появляется, если программа конечно не умерла :). С появлением нового функционала старый функционал должен отмирать, и исключаться.&lt;br /&gt;&lt;br /&gt;Это в идеале. В реальности, особенно в мире свободного ПО, активная разработка зачастую скатываеся к наращиванию функционала. А поскольку все это делается еще в свободное время - на чистку времени совершенно не остается, и программа начинает прогибаться под грузом функциональности. А поскольку программа свободна - в какой-то момент это кому-то надоедает и появляется форк.&lt;br /&gt;&lt;br /&gt;Но иногда появляются не просто форки а качественные переосмысления идей первого продукта. То есть новый продукт выполняя сходные функции работает совершенно иначе. Он конечно может использовать некоторые наработки предшественников, но тем не менее ни о какой совместимости в данном случае не может быть и речи. Революция?&lt;br /&gt;&lt;br /&gt;К чему я это все. Последнее время мой любимый gentoo явно находится в застое. Вероятно это происходит потому, что количество проектов велико, и ни на какие творческие поиски просто не остается времени, рутинное добавление новых пакетов - все что осталось. В то время как новое ПО требует нового отношения. И, как видно не всегда старых средств хватает.&lt;br /&gt;&lt;br /&gt;Сейчас в gentoo явная проблема например с KDE. Часть команды KDE по политическим разноглаcиям покинула проект, и стабильные пользователи gentoo еще не скоро увидят KDE4 (Кстати не понимаю, почему она не в слоте).&lt;br /&gt;&lt;br /&gt;Такая ситуация, видимо, давно уже кому-то надоела и возник проект &lt;a href="http://www.exherbo.org/"&gt;Exerbo&lt;/a&gt;, где переделана сама структура портеджей. А кроме того новые сценарии инициализаци системы и некоторые другие вкусности. Но одна беда - система еще не достаточно наполнена пакетами. Но это быстро проходит. буквально два месяца назад там еще не было даже иксов, но сейчас там уже есть kde4. Пожалуй как нибудь на досуге я посмотрю на не поближе (в плане поставить), Потому что это самый вероятный кандидат на замену моей любимой gentoo.&lt;br /&gt;&lt;br /&gt;Наверное, мысль поста как-то ускользнула. Просто в любом проекте в какой-томомент назревает необходимость выбросить все и начать сначала. Или хотя бы наметить пути дальнейшего наступления.&lt;br /&gt;Собственно революция - это быстрая эволюция, зачастую можно все то же проделать и в более спокойном режиме, просто надо остановить наращивание, осознать направление движения, и смелее отрезать все лишнее.&lt;br /&gt;&lt;br /&gt;PS: А что творится в недрах Windows - я даже представить боюсь, хотя они тоже иногда забивают на совместимость, но это пока исключение. Совместимость - их хлеб. А Windows еще не умер от груза совместимости? есть ли жизнь после XP? о чем это я...&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-5424733114527724455?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/5424733114527724455/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=5424733114527724455' title='Комментарии: 8'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/5424733114527724455'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/5424733114527724455'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2008/09/blog-post_30.html' title='Революции нужны?'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-7979155700694631368</id><published>2008-09-26T15:03:00.012+04:00</published><updated>2010-07-02T11:42:46.704+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='рефакторинг'/><category scheme='http://www.blogger.com/atom/ns#' term='gcc'/><title type='text'>deprecated: gcc vs vs vs vs...</title><content type='html'>vs Visual Studio... Опять наверное прописные истины, но хочу рассказать про аттрибут deprecated.&lt;br /&gt;&lt;br /&gt;Аттрубут deprecated - это не только ценный инструмент для командной разработки (чтобы довести до других членов команды необходимость изменения API), но так же он незаменим при рефакторинге.&lt;br /&gt;&lt;br /&gt;Я очень часто применяю его, если мне хочется что-то удалить, но предварительно нелишним будет узнать где это что-то используется. Тогда я это что-то объявляю как deprecated, и после компиляции точно знаю файлы и строки где это используется. Вовсе не обязательно удалять сразу, есть время подумать, подчистить и когда варнинги исчезнут - удалить окончательно.&lt;br /&gt;&lt;br /&gt;Все, про рефакторинг больше ничего не скажу.&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;Хочется сравнить возможности атрибутов на gcc и visual с++. Поскольку атрибуты не входят в стандарт, то в каждом компиляторе это делается как попало.&lt;br /&gt;&lt;br /&gt;Начнем с gcc. Для объявления чего-то устаревшим в нем используется конструкция &lt;code&gt;__attribute__((deprtecated))&lt;/code&gt;. Её можно применять для переменных и типов: &lt;code&gt;&lt;br /&gt;int a __attribute__((deprtecated));&lt;br /&gt;struct a_struct {} __attribute__((deprtecated));&lt;br /&gt;struct { int a_field __attribute__((deprtecated)); };&lt;br /&gt;void func(int a_arg __attribute__((deprtecated))) {}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Практическая польза от последнего - спорна, но может пригодиться для очень больших функций. Код же разный бывает, в конце концов.&lt;br /&gt;&lt;br /&gt;Для функций: &lt;br /&gt;&lt;code&gt;void func() __attribute__((deprtecated));&lt;/code&gt; // в прототипе&lt;br /&gt;&lt;code&gt;void __attribute__((deprtecated)) func() {}&lt;/code&gt; // в декларации&lt;br /&gt;&lt;br /&gt;Причем если поставить атрибут не на место, то gcc будет ругаться грязно и непонятно насчет точек с запятыми, еще какой-то фигни.&lt;br /&gt;&lt;br /&gt;В visual c++ дело обстоит так: указание аттрибута осуществляется с помощью &lt;code&gt;__declspec(deprecated)&lt;/code&gt; и используется практически единообразно.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;__declspec(deprecated) int a;&lt;br /&gt;struct __declspec(deprecated) a_struct {};&lt;/code&gt; // почему после struct то?&lt;code&gt;&lt;br /&gt;struct { __declspec(deprecated) int a_field; };&lt;br /&gt;void func(__declspec(deprecated) int a_arg) {}&lt;/code&gt; // игнорируется&lt;code&gt;&lt;br /&gt;__declspec(deprecated) void func();&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;В принципе схоже, свои заморочки, но их все перекрывает возможность указать сообщение.&lt;br /&gt;&lt;code&gt;__declspec(deprecated("use foo instead")) void func();&lt;/code&gt;&lt;br /&gt;В gcc такая возможность только обсуждаются.&lt;br /&gt;&lt;br /&gt;Правда как всегда в Microsoft - без ложки дегтя не обходится. Указал сперва сообщение по русски, но в Output увидел только квадратики... только два квадратика разного размера. Хотя в сообщении было явно больше двух букв...&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-7979155700694631368?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/7979155700694631368/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=7979155700694631368' title='Комментарии: 5'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/7979155700694631368'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/7979155700694631368'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2008/09/deprecated-gcc-vs-vs-vs-vs.html' title='deprecated: gcc vs vs vs vs...'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-852698507929734471</id><published>2008-09-24T23:00:00.003+04:00</published><updated>2008-09-24T23:25:22.231+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='boost'/><title type='text'>Разбор командной строки в boost</title><content type='html'>Долго ломал голову как сделать обработку командной строки в boost по хитрому. А по хитрому - это так: сперва указываются глобальные опции, потом некоторая команда, потом локальные опции, свойственные конкретной команде. Но program_option из boost, упрямо засасывает все опции сразу, и чтобы придумать способ - пришлось покопаться в исходниках.&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;И как всегда, после того как разобрался, решение оказывается простым и понятным, но где оно было раньше - не понятно. Всмысле это могло бы быть написано в докумментации.&lt;br /&gt;&lt;br /&gt;Начнем с устройства &lt;code&gt;program_options::command_line_parser&lt;/code&gt;. Устроен он следующим образом:&lt;br /&gt;&lt;br /&gt;Имеется некоторый набор парсеров стиля (style_parser), которые по некоторым критериям выбирают из строки опции. набор стайл парсеров формируется на основе стиля командной строки, который может варьироваться в некоторых пределах - поддержка длинных имен, значения у опций, опции формата DOS и тд.&lt;br /&gt;&lt;br /&gt;Каждый парсер возвращает список опций (&lt;code&gt;vector&amp;lt;program_options::option&amp;gt;&lt;/code&gt;), обработанных им на данном этапе. Это может быть пустой список, одна или много опций, хотя парсить много опций за раз нет необходимости, там цикл и остатки командной строки обязательно снова пройдут через каждый парсер. Обработка заканчивается после того, как командная строка опустевает.&lt;br /&gt;&lt;br /&gt;После прохождения командной строки через набор парсеров формируется список опций. неопциональные элементы в котором представлены некоей нетипизированной опцией.&lt;br /&gt;&lt;br /&gt;Это было введение. :)&lt;br /&gt;&lt;br /&gt;Теперь предположим, что командная строка предположительно будет разбираться за два прохода. Первый проход выделяет глобальные опции (идущие перед командой) и команду соответственно. А второй проход получит список аргументов, объединяющий в себе локальные опции и все остальное.&lt;br /&gt;&lt;br /&gt;Но как и в любом деле здесь главное вовремя остановиться, то есть хотелось бы чтобы boost не анализировал строку до конца в поисках опций. И тут нам на помощь приходит &lt;code&gt;extra_style_parser&lt;/code&gt;. Дополниельный парсер стиля - это отдельная функция. Её задачей будет при обнаружении первого неопционального слова, предположительно команды, оставшуюся часть строки без разбора загнать в результат. Cлайды:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;vector&amp;lt;program_options::option&amp;gt; stop_on_command (vector&amp;lt;string&amp;gt; &amp;args)&lt;br /&gt;{&lt;br /&gt; vector&amp;lt;program_options::option&amp;gt; result;&lt;br /&gt; const string &amp;tok = args[0];&lt;br /&gt; if (tok[0] != '-') {&lt;br /&gt;  BOOST_FOREACH (string &amp;arg, args) {&lt;br /&gt;   program_options::option opt;&lt;br /&gt;   opt.value.push_back(arg);&lt;br /&gt;   result.push_back(opt);&lt;br /&gt;  }&lt;br /&gt;  args.clear();&lt;br /&gt; }&lt;br /&gt; return result;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Используем это при разборе строки:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; program_options::command_line_parser parser (argc, argv);&lt;br /&gt; parser.extra_style_parser (stop_on_command);&lt;br /&gt;&lt;br /&gt; ...&lt;br /&gt;&lt;br /&gt; program_options::store(parser.run(), vm);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Естественно чтобы это дело сработало необходимо создать позиционный параметр неограниченного количества, куда будут сложены все локальные опции/аргументы.&lt;br /&gt;&lt;br /&gt;Вот собственно и все. Может пригодиться кому.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-852698507929734471?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/852698507929734471/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=852698507929734471' title='Комментарии: 7'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/852698507929734471'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/852698507929734471'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2008/09/boost.html' title='Разбор командной строки в boost'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-1190663939121999897</id><published>2008-09-15T22:03:00.004+04:00</published><updated>2008-09-15T22:40:42.082+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><title type='text'>Компиляцию варнингом не испорть...</title><content type='html'>Но не все варнинги одинаково полезны. Включение варнингов предполагает, что при компиляции ты вообще не будешь их видеть. То есть, на предупреждения надо реагировать и исправлять их. Но если предупреждения вываливаются из внешнего кода (из инклюдов), то вывод засоряется, свои предупреждения теряются и и приходится мучаться. Лишние предупреждения надо убирать, но как?&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;Я очень люблю предупреждения компилятора. :) В своих проектах я всегда выставляю &lt;code&gt;-Wall -Wextra -Weffc++&lt;/code&gt;. Последний тоже весьма полезен, поскольку позволяет писать на C++ в соответствии с рекоммендациями Скота Майерса, что позволяет избежать лишних побочных эффектов.&lt;br /&gt;&lt;br /&gt;Но вот некоторые, не будем показывать пальцем, хотя это boost, не используют эту опцию. В результате чего вы выходе имею горы предумреждений и никакой возможности их устранить. Можно конечно патчить boost, или даже слать патчи разработчикам, но мне некогда этим заниматься. Но и отключать любимые варнинги тоже не хочется. Должен быть путь управлять этим на уровне кода.&lt;br /&gt;&lt;br /&gt;Вот в MSVC испокон веков существует #pragma warning, которая легко и непринужденно позволяет делать все это. Но в gcc все обстоит не столь радужно.&lt;br /&gt;&lt;br /&gt;Вероятно, в gcc-2.96 появилась &lt;code&gt;#pragma GCC system_header&lt;/code&gt;. Которая должна отключить генерацию последующего кода, при условии, что используется она в теле файла инклюда. Но мне почему-то не удалось заставить ее работать. Может быть ей требуется исключительно &lt;code&gt;#include &lt;&gt;&lt;/code&gt;, В то время как локальные инклюды &lt;code&gt;#include ""&lt;/code&gt; не прокатывают? не знаю.&lt;br /&gt;&lt;br /&gt;Вычитал, что есть &lt;code&gt;#pragma GCC diagnostic&lt;/code&gt;, правда появилась эта прагма только в gcc-4.2. Она позволяет выбирать реакцию на предупреждения от игнорирования до ошибки.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#pragma GCC diagnostic ignored "-Weffc++"&lt;br /&gt;#include &amp;lt;boost/...&gt;&lt;br /&gt;#pragma GCC diagnostic warning "-Weffc++"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Это дело работает, но основной gcc в моей Gentoo на данный момент 4.1.2, Хотелось бы заставить компилиться без ошибок и на нем. Как же юзается этот system_header???&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-1190663939121999897?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/1190663939121999897/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=1190663939121999897' title='Комментарии: 11'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/1190663939121999897'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/1190663939121999897'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2008/09/blog-post_15.html' title='Компиляцию варнингом не испорть...'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-524017114208122372</id><published>2008-09-07T21:23:00.011+04:00</published><updated>2008-09-07T22:37:49.958+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='рефакторинг'/><title type='text'>О макросах бедных замолвите слово...</title><content type='html'>Макросы конечно опасны. Так же, как опасны и многие другие, весьма повседневные вещи. И всем понятно, что нет никакой необходимости применять макросы препроцессора в C++. Но здесь речь пойдет не о C++, хотя во второй части, посвященной рефакторингу, я немного коснусь и его. Совсем чуть-чуть. Мог бы даже и не говорить об этом во вступлении.&lt;br /&gt;&lt;br /&gt;Но если говорить о C, то в некоторых случаях без макросов просто никуда...&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;Начнем с тех моментов, когда нет никакой необходимости применять макросы. Это происходит тогда, когда типы параметров и результата заранее известны. То есть ситуация предельно конкретная. Нет необходомости использовать макрос. Вполне можно описать функцию. Даже в инклюде, если она используется из множества файлов, описав ее как &lt;code&gt;static inline&lt;/code&gt;. За счет контроля типов этот способ гораздо предпочтительнее в плане надежности.&lt;br /&gt;&lt;br /&gt;Проблема возникает тогда, когда типы заранее неизвестны. Обычно это указывает на весьма широкое использование какой либо мелкой функции, типа &lt;code&gt;max&lt;/code&gt;. В C++ для этого дела обычно применяют шаблонные функции. Но си не имеет шаблонов. В си, для таких случаев, альтернативы макросам просто нету.&lt;br /&gt;&lt;br /&gt;Но при программировании макросов есть много подводных камней. Они многократно описаны, переписывать это я не буду. Скажу лишь что лучше всего избегать любых побочных эффектов в макросах. Макросы должны вести себя как соответствующие функции. Это упростит понимание и поддержку.&lt;br /&gt;&lt;br /&gt;За исключением одного момента. Есть в препроцессоре две переменных - &lt;code&gt;__FILE__&lt;/code&gt; и &lt;code&gt;__LINE__&lt;/code&gt;. Использование их в инлайн функции сводит смысл их использования практически к нулю. Поэтому я позволяю себе использовать макроопределение, которое помимо параметров использует эти две переменных, но привязывает их к месту вызова макроса. Хотя с другой стороны это трудно назвать побочным эффектом, поскольку состояние выполнения никак не меняется. Но если попытаться заменить макрос на функцию, то соответствующая информация просто не будет доступна.&lt;br /&gt;&lt;br /&gt;Вот совсем недавно ковырялся тут со своим проектам. У меня там широко используются утверждения (asserton). Я конечно стараюсь чтобы выражения в утверждениях были понятны, но в отрыве от контекста они обычно ни о чем не говорят. Поэтому я дополнил утверждения текстовой строкой, которая выводится в случае нарушения. После этого я заметил один момент.&lt;br /&gt;&lt;br /&gt;Выражение &lt;code&gt;assert(x &lt; y)&lt;/code&gt; содержит в себе условие допустимости выполнения. И это вполне адекватно воспринимается. Но если попытаться дополнить его текстовой строкой, которая должна отображаться в случае нарушения условия - &lt;code&gt;assert(x &lt; y, "слишком большой x")&lt;/code&gt;, То все становится с ног на голову. Почему же x большой, если он меньше y? Долго думал во что мне переименовать assert, чтобы можно было использовать обратную логику утверждений, но потом бросил это дело, ибо assert - это просто утверждение.&lt;br /&gt;&lt;br /&gt;Но логику выражений я твердо решил перевернуть (мои утверждения носят название STUB_ASSERT, но это почти ничего не меняет). А поскольку недвано начитался Фаулера, то делать это начал по всем правилам. :)&lt;br /&gt;&lt;br /&gt;Сперва я создал другую функцию, на самом деле это просто макрос, которая ориентировалась на обратную логику утверждений. То есть выражение описывает условие остановки программы и сообщение, выводимое при остановке программы. Так логично.&lt;br /&gt;&lt;br /&gt;Старый макрос я хотел бы объявить устаревшим, я всегда так делаю с функциями, чтобы обнаружить места где он используется, но есть проблема. В препроцессоре почти невозможно объявить макроопределеение устаревшим. Поэтому я превратил его в функцию, при этом я потерял возможность видеть файл/строку сбоя, но поскольку я всеравно собирался его удалять - мне это всеравно.&lt;br /&gt;&lt;br /&gt;После чего я, долго и нудно, менял все функции на новый вариант, паралельно переворачивая логику утверждений. Поскольку функция использовалась широко - это была долгая работа, но поскольку старая функция существовала независимо от новой - я мог производить эту модификацию поэтапно. После того, как старый вариант исчез из обращения - я просто взял с помощью sed переименовал все новые функции на старые: &lt;code&gt;sed -i -e 's/REAL_ASSERT/STUB_ASSERT/g'&lt;/code&gt;. И получил старое имя макроса и новую логику его использования. Все встало на свои места и стало логичным. Теперь главное не начать использовать новую логику по старому. :)&lt;br /&gt;&lt;br /&gt;А теперь немного про рефакторинг. Большинство методов рефакторинга ориентируются исключительно на объектность. Но если смотреть свысока, то можно заметить что си имеет модули. Каждый модуль имеет свое состояние - свои статические переменные. Которые так же как и в C++ стоит делать приватными - статическими. Правило сокрытия информации распространяется на модули си практически так же как и на классы. То есть все, что не экспортируется лучше делать статическим. Это, просто-напросто, уменьшает количество сущностей, взаимоотношения которых нужно отслеживать программисту. Видя, что функция приватная/статическая мы сразу же, без лишних умственных напряжений, понимаем где она может быть использована. Рефакторинг в си может выполняться путем перемещения функций между модулями или например делением одного модуля на несколько по смыслу функций.&lt;br /&gt;&lt;br /&gt;И вот еще один момент. Выделение метода в C++ происходит обычно в тот же класс. В си выделение метода будет происходить в модуль. Новая функция, естественно, имеет локальную область видимости - то есть объявляется как статик. Такое можно применять даже в C++ если например стоит задача минимизировать количество изменений, но для исправления ошибки требуется вынести часть кода из функции, или просто добавить в функцию некоторое новое поведение, не меняя при этом описание класса, которое обычно располагается в другом файле. В дальнейшем, при проведении планового рефакторинга, эту функцию легко можно включить в объект.&lt;br /&gt;&lt;br /&gt;PS: может быть это все прописные истины. Но некоторые и их не знают, да и не грех лишний раз повторить любому. :)&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-524017114208122372?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/524017114208122372/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=524017114208122372' title='Комментарии: 6'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/524017114208122372'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/524017114208122372'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2008/09/blog-post_07.html' title='О макросах бедных замолвите слово...'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-5329847388474839768</id><published>2008-09-05T15:02:00.008+04:00</published><updated>2010-07-02T14:04:55.220+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hardware'/><title type='text'>Последняя статья...</title><content type='html'>Сегодня последний день первого года существования этого блога :). Надо это дело как-то отметить. Серьезных материалов пока что-то в голову не приходит, буду писать всякую разную ерунду.&lt;br /&gt;&lt;br /&gt;И в этой статье вы услышите про плохое поведение ntlmaps, про применимость макросов препроцессора и еще может быть какую нибудь другую ерунду. :) Но коротенькие статьи я не воспринимаю. Должна быть в статье какая нибудь глобальная мысль, размазанная по нескольким страницам текста. А то как у некоторых - "У меня сегодня хорошее настроение, поэтому я пишу эту статью, чтобы поделиться этим хорошим настроением со всеми остальными. Все, пока." - Не мой формат. :)&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;Итак. Долго не мог понять почему у меня firefox застревает на открытии страниц. Долго ломал голову. Пока сегодня случайно не вывел на панель Kima загрузку всех 4-х моих CPU (об этом чуть позже). И обнаружил что мой proxy-proxy клиент - ntlmaps, загрузил одно из CPU на 100%, в то время как я тщетно пытаюсь дождаться от firefox вменяемого ответа на свой запрос. ntlmaps - мне очень нужен, потому, что proxy сервер у нас конечно от MS, и авторизацию не принимает никак иначе кроме как через NTLM. Собственно для чего и был создан ntlmaps. Он берет на себя авторизацию на сервере, а все подключения пускает уже без авторизации, что позволяет ходить в интернет даже самыми отсталыми инструментами.&lt;br /&gt;&lt;br /&gt;Но firefox вроде бы не является отсталым, что он успешно доказал - авторизовавшись на проксе самостоятельно. И вот я здесь. Теперь надо будет разобраться что же такое не нравилось ntlmaps в запросах?, что он так напряженно об этом думал...&lt;br /&gt;&lt;br /&gt;Про практическую пользу дефайнов я наверное расскажу потом. А сейчас немного о том счастье, которое мне привалило на работе. Собственно попал под плановый апгрейд и получил в свое девелоперское распоряжение Intel Core 2 Quad с 4 гигами памяти. Я до сих пор никогда особо с EM64T дела не имел, да и с 4 гигами тоже. Я всегда хотел узнать насколько же 64 бита быстрее 32-х, но все это собственно ерунда, я даже исследования соответствующие проводить вряд ли буду. Потому, что 64-х битная система в отличии от 32-х битной видит все 4 гига памяти, в то время как 32-х битная видит только 3,2. 800мегабайт дополнительной памяти достаточно весомый аргумент в пользу 64-х бит.&lt;br /&gt;&lt;br /&gt;Своп я отключил сразу... Не знаю как в линуксе, но теоретически ядро должно сильно упрощаться, если не заставлять его парится на тему вытеснения страниц. :) Хотя вот &lt;a href="http://itblogs.ru/blogs/borkus/archive/2008/09/04/vista-x64.aspx"&gt;Vista на 4 гигах без свопа&lt;/a&gt; часто не справляется со своими функциями. Но моя 32-х битная система на данный момент юзает 900М с учетом всех кешей.&lt;br /&gt;&lt;br /&gt;64-х битная система, которая сейчас неспешно устанавливается, вероятно будет юзать побольше. Где то читал, что примерно на 150 мег. Но 3 гигабайта всеравно в резерве.&lt;br /&gt;&lt;br /&gt;На этом все. Надеюсь что теперь буду вылезать в блог почаще, завтра в любом случае надо отметить начало нового блогогода. :)&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-5329847388474839768?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/5329847388474839768/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=5329847388474839768' title='Комментарии: 5'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/5329847388474839768'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/5329847388474839768'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2008/09/blog-post.html' title='Последняя статья...'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-1222143491656160380</id><published>2008-08-15T20:32:00.003+04:00</published><updated>2008-08-15T20:48:51.437+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='мысли'/><title type='text'>Поворчу...</title><content type='html'>Я часто плююсь на Windows. Да и на Linux иногда тоже поплевываюсь. Не то, чтобы придираюсь, просто стараюсь быть объективным. И ведь не так уж плохо все делается, но почему-то все как-то через задницу.&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;Не далее как сегодня наткнулся на ерунду... Ради теста стоит у меня центр сертификации, и у него истек корневой сертификат, который ради теста имел минимальный срок службы - 2 дня. И вот я открываю 'Администрировани/Центр сертификации' и получаю жизнерадостную ошибку что дескать 'Не найден сетевой путь, ошибка 0x89423423'. Полчаса ушло на то, чтобы понять что причина находится в просроченном корневом сертификате, и еще час ушел на то, чтобы научиться выпускать новый корневой сертификат. Делается это, как оказалось, тривиально: &lt;code&gt;certutils -renewCert&lt;/code&gt;, но только с командной строки, специальной утилитой. Почему нельзя было сделать этого когда я открываю администрирование ЦС??? Ну или хотя бы сообщение об ошибке повменяемее? Я же не многого хочу! :) Хотя насчет ошибок - это вечная неиссякаемая тема.&lt;br /&gt;&lt;br /&gt;И еще одна очень странная ерунда. Наверное я что-то не понимаю в инфраструктуре PKI. Но помоему, если у центра сертификации новый сертификат с новым ключем, то он на старом сертификате/ключе уже не должен ничего выпускать. Ан нет, ЦС от Microsoft преспокойненько выпускает новые CRL как на новом сертификате, так и на старом. Хотя может быть в этом и есть смысл?&lt;br /&gt;&lt;br /&gt;И еще немного про Linux... mencoder у меня так и не научился кодировать видео в два прохода. Зато научился ffmpeg. Судя по всему разработчики задвинули mencoder в пользу нового и красивого ffmpeg. Хотя ИМХО всем этим программам не хватает одной очень полезной опции -quality, Ну почему я должен сам выбирать все эти усреднители и чередователи? Почему нельзя просто сказать - покачественнее или побыстрее???&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-1222143491656160380?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/1222143491656160380/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=1222143491656160380' title='Комментарии: 2'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/1222143491656160380'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/1222143491656160380'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2008/08/blog-post.html' title='Поворчу...'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-1659168065471678371</id><published>2008-08-15T13:51:00.011+04:00</published><updated>2008-08-15T20:31:37.685+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='мысли'/><title type='text'>entern int i;</title><content type='html'>Давно не писал что-то, а хочется. Уже накопилось несколько животрепещущих тем. Вот например про области видимости, но не переменных а строк. Ведь при детальном рассмотрении это практически одно и то же. Чем дальше от места использования мы опишем строку - тем более велика вероятность допустить ошибку.&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;Особенно это актуально при использовании разных форм &lt;code&gt;printf&lt;/code&gt;. Самый правильный путь - это указывать строку непосредственно в тексте. При этом в случае с &lt;code&gt;printf&lt;/code&gt; мы получаем возможность визуально установить соответствие аргументов и собственно строки без отрыва от данного участка кода. В других случаях это тоже может быть актуально, так как строка обычно содержит в себе какой-то смысл, который вряд ли может быть полноценно передан через какой либо идентификатор.&lt;br /&gt;&lt;br /&gt;Но тут есть одна проблема - интернационализация. Очень хочется все строки программы легким движением заменить на соответствующие фразы другого языка. И всеравно наиболее правильным мне кажется указание строки основного языка непосредственно в тексте, пусть в специальных скобках типа &lt;code&gt;QObject::tr()&lt;/code&gt;. В этом случае строка на основном языке видна явно, а соответствие интернациональным версиям - отдельная самостоятельная проблема, но самостоятельные проблемы решать проще, чем взаимосвязанные.&lt;br /&gt;&lt;br /&gt;И вот тут я буду плеваться на Windows. Хотя он и не виноват вовсе, я и на Linux иногда плююсь. :) Наверное мне просто везет на ужасные проекты, которых в нашей фирме великое множество. И мне постоянно приходится их сопровождать.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;LoadResourceString(IDS_STRING136,strTemp);&lt;br /&gt;wsprintfA(szTm, strTemp.c_str(), from.wDay, from.wMonth, from.wYear, to.wDay, to.wMonth, to.wYear);&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Мало того, что содержимое строки не видно. Но даже если мы перейдем к описанию &lt;code&gt;IDS_STRING136&lt;/code&gt;, то мы обнаружим всего лишь...&lt;br /&gt;&lt;br /&gt;&lt;code&gt;#define IDS_STRING136 136&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Даже если бы у этого идентификатора было бы осмысленное имя - это всеравно ничего не дает, потому что строки нету. Да, можно полезть в ресурсы и выискивать эту строку из сотен других. Не знаю сильно ли это облегчит задачу. Это почти то же самое что описать &lt;code&gt;int i&lt;/code&gt; в отдельном файле, может даже хуже. Могу себе представить какие сложности испытывают программисты многоязычных приложений.&lt;br /&gt;&lt;br /&gt;Проблема вся в том, что &lt;code&gt;IDS_STRING136&lt;/code&gt;, и собственно его числовое значение тоже - это два лишних звена между главноязычными и дополнительноязычными сообщениями. Вернее даже не совсем так. Мы почему-то пытаемся главноязычные сообщения подменить безликими малоговорящими идентификаторами. К тому же строки иногда меняются, и строка легко может перестать соответствовать тому участку кода, в который она подставляется.&lt;br /&gt;&lt;br /&gt;Похожую проблему видел в одной прошивке, но там это более менее можно понять. Всетаки экономия памяти, всякое разное. Но и там теоретически можно было сделать основной язык в тексте, а дополнительные языки - подставлять при компиляции к примеру. На *nix обеспечить такую подстановку - как два байта подменить. написал скриптик в пять строк и все дела. А проект, к сожалению, был под DOS, чтобы так легко все заменить пришлось бы писать специальную программу. Там сделано просто - файл с 'ресурсами' представлял из себя большой массив, в котором производилось сопоставление идентификатора и строки. Файл для нужного языка выбирался на этапе компиляции статически. Идентификаторы, само собой были отдельно, через enum.&lt;br /&gt;&lt;br /&gt;В обоих случаях это были конечно не самые основные проблемы. Но о других проблемах поддерживаемых мною программ - как нибудь в другой раз.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-1659168065471678371?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/1659168065471678371/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=1659168065471678371' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/1659168065471678371'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/1659168065471678371'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2008/08/entern-int-i.html' title='entern int i;'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-2570646334525114238</id><published>2008-07-31T13:24:00.003+04:00</published><updated>2008-07-31T14:02:28.852+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='gentoo'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='kde'/><title type='text'>Время менять корневые разделы...</title><content type='html'>Переодически, обычно в связи с выходом нового релиза, я переставляю свою систему (моя система - это Gentoo). С одной стороны это полезно для того, чтобы не забыть как это делается. А с другой стороны постоянные обновления всетаки замусоривают систему постепенно. А с третьей стороны - установка системы с нуля, это повод попробовать что нибудь новое.&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;Система как всегда устанавливается без особых вопросов. Я конечно проделывал это неоднократно, и в хендбук смотрю только для того, чтобы не забыть что нибудь важное. При этом в процесс инсталляции вносятся элементы творчества.&lt;br /&gt;&lt;br /&gt;Разбиение дисков у меня особенное. Я честно говоря никогда не видел необходимости отделять boot, usr и var от рута. Их содержимое во многом предсказуемо и на десктопе все они прекрасно размещаются на одном разделе. Эксплуатируя gentoo я вывел для себя следующую схему:&lt;br /&gt;&lt;br /&gt;Раздел подкачки располагается у меня в начале диска, ходили слухи, что начало диска работает быстрее. Хотя я думаю что более оптимально располагать раздел подкачки в середине диска, а остальные партиции приближать к разделу подкачки в меру востребованности. Это просто оптимизирует перемещение головок.&lt;br /&gt;&lt;br /&gt;Корневых разделов у меня два. Один из них активный, на котором располагается собственно текущая система, второй - резервный. На нем может располагаться либо старая система, временно на него можно установить еще какую нибудь систему, если понадобиться, и ее же я использую для инсталляции новой.&lt;br /&gt;&lt;br /&gt;Сравнительно небольшую партицию - 4-6 гиг я выделяю для /usr/portage. Это позволяет ему не раздуваться, а заодно позволяет использовать его из разных gentoo-систем.&lt;br /&gt;&lt;br /&gt;И оставшееся место диска я обычно отвожу на один большой раздел, который монтирую в свой домашний каталог и использую для хранения всякого барахла.&lt;br /&gt;&lt;br /&gt;Диск у меня небольшой. В этом плане я придерживаюсь такого мнения, что любой объем всеравно когда нибудь кончится, и его придется разгребать. И при выборе диска руководствуюсь больше единовременными потребностями. Мой диск имеет размер 80гиг.&lt;br /&gt;&lt;br /&gt;Итак, во второй корневой раздел я залил новую систему. И решил побаловаться с программами мониторинга под KDE. До сих пор я пользовался ksensors, но он помоему древний как KDE1. Я не надеялся что найду что-то идеальное, но к идеалу надо хотя бы стремиться. Программ мониторинга под KDE не много. Помимо указанного выше ksensors можно упомянуть ksim, ksysguard (правда меня мучают сомнения, что ksysguard умеет мониторить датчики lm_sensors) и &lt;a href="http://kima.sourceforge.net/"&gt;kima&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Kima - это апплет для панели задач KDE. Умеет мониторить датчики lm_sensors, умеет получать информацию от демона hddtemp и еще среди фич есть мониторинг Thermal Zone CPU. Надо порыть что это за зверь и где собственно стоит. :) Инфрмацию kima отображает непосредственно в панели, во всплывающем окне информации может быть больше.&lt;br /&gt;&lt;br /&gt;Хотя конечно на полноценный мониторинг это не тянет, просто информирование пользователя, но выглядит поприятнее чем ksensors. Мониторинг ИМХО должен еще как-то по времени все это отслеживать, тенденции всякие. И вообще, компьютер должен работать.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-2570646334525114238?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/2570646334525114238/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=2570646334525114238' title='Комментарии: 3'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/2570646334525114238'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/2570646334525114238'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2008/07/blog-post_31.html' title='Время менять корневые разделы...'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-581524681904122938</id><published>2008-07-24T16:32:00.005+04:00</published><updated>2008-07-24T17:18:29.116+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='мысли'/><title type='text'>Многоблирование информации...</title><content type='html'>Копипастинг зло... все это знают. Грамотные программисты никогда не копируют код просто так. Но даже без явного копипастинга нас окружают многочисленные дублирования информации.&lt;br /&gt;&lt;br /&gt;Где-то у меня была прикольная закладочка.. а, вот она - &lt;a href="http://pmd.sourceforge.net/cpd.html"&gt;Copy/Paste detector&lt;/a&gt;. Но я хотел написать немного о другом.&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;Начну с того, что мне очень не нравится то, что прототипы функций необходимо выносить в  include-файл. По большому счету это просто переписывание. Вполне можно было бы в пределах одного файла разрулить функции на локальные или экспортируемые и вообще отказаться от инклюдов. Во многих языках так и делается. Можно сделать наверное и в си, только тогда это будет уже не си.&lt;br /&gt;&lt;br /&gt;Но даже если инклюдить сишники достаточно бессмысленно, то можно генерировать инклюды на основе сишников. :) Логика генерации нужна конечно достаточно наворочанная, но ведь компьютеры и должны работать. Вообще при постановке задачи не стоит думать о технических сложностях с реализацией. Это мешает и ограничивает воображение.&lt;br /&gt;&lt;br /&gt;Когда-то файлы библиотек создавались с таким расчетом, чтобы в одном объектном модуле была одна функция. При связывании выполняемого модуля из библиотеки извлекается исключительно то, что необходимо. Но ведь никому не охота для каждой мизерной функции писать отдельный си-файл. Да и не удобно это. Поэтому библиотеки стали набиваться гигазами объектников, неоптимально это. Я тут вынашиваю мысли на тему делить большие сишники на маленькие, компилировать и пихать в библиотеку. Естественно все это должно производиться в автоматическом режиме в процессе сборки. И тестировать модули индивидуально удобнее. Глобальное тестирование неизбежно натыкается на ограничения областей видимости и тд. Но я хотел написать не об этом...&lt;br /&gt;&lt;br /&gt;Ковыряюсь тут с одним старым проектом, ошибки исправляю. Хотя весь этот проект представляет из себя одну большую ошибку, которая собирается полтора часа, а функциональности в ней и на 5 минут не наберется. Хотя то, о чем я хочу написать свойственно многим проектам MSVC. Одна из ошибок очень явно это высветила - в одном месте указан старый телефон компании. Начал выяснять где... Для этого пришлось поставить InstallShield, ибо данная информация хранилась в инсталляторе. Телефон больше нигде не хранился, а вот название компании, версия продукта помимо инсталлятора хранится еще и в ресурсах каждого модуля (как я не люблю ресурсы), в диалогах в виде статического текста, иногда в самом тексте программ. Не удивительно что версии везде указаны разные, а название компании в разных формах.&lt;br /&gt;&lt;br /&gt;Любую информацию необходимо указывать единожды. Правда я с трудом представляю как это можно сделать в условиях MSVC.&lt;br /&gt;&lt;br /&gt;Вот собственно и все, о чем хотел написать.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3179964835593137794-581524681904122938?l=mdf-i.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mdf-i.blogspot.com/feeds/581524681904122938/comments/default' title='Комментарии к сообщению'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3179964835593137794&amp;postID=581524681904122938' title='Комментарии: 1'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/581524681904122938'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3179964835593137794/posts/default/581524681904122938'/><link rel='alternate' type='text/html' href='http://mdf-i.blogspot.com/2008/07/blog-post_24.html' title='Многоблирование информации...'/><author><name>Андрей Валяев</name><uri>http://www.blogger.com/profile/11584397745995226795</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://bp1.blogger.com/_eOHzlCMDZZM/R4ujrE-UmhI/AAAAAAAAAAw/9S9RlP-2uj4/S220/blogavatar1.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3179964835593137794.post-1692867497670404624</id><published>2008-07-22T16:05:00.007+04:00</published><updated>2008-07-22T16:49:03.661+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='бесшумный компьютер'/><title type='text'>Абсолютно бесшумный компьютер...</title><content type='html'>Ну вот и свершилось, на день рождения выпросил в подарок FSP ZEN-400. И последний вентилятор вместе с блоком питания отправился в историю...&lt;br /&gt;&lt;span id="fullpost"&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_eOHzlCMDZZM/SIXQqKHKOZI/AAAAAAAAAB4/vmf4WJ3Qy7k/s1600-h/IMG_3395.jpg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;" src="http://bp1.blogger.com/_eOHzlCMDZZM/SIXQqKHKOZI/AAAAAAAAAB4/vmf4WJ3Qy7k/s320/IMG_3395.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5225812365320796562" /&gt;&lt;/a&gt;Комплект производит очень хорошее впечатление, ну он и стоит 150 баксов :)... Разъемы питания снабжены отжимниками, в комплекте идут липучки для связывание проводов, красота...&lt;br /&gt;&lt;br /&gt;Только вот с установкой пришлось повозиться, в корпусе что-то тесно. Чтобы отключить все разъемы мне необходимо выкрутить БП и двигать его туда-сюда. Но старый БП и так необходимо снимать. Хуже оказалось то, что отключиться то он отключился, но вот вытаскиваться абсолютно не захотел, радиатор мешает. Пришлось открутить материнскую плату и двигать туда-сюда ее. Не снимать же радиатор. Пусть даже я поставил его кверхногами и теперь надпись Scythe в нормальном положении системного блока перевернута, о ужас!&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_eOHzlCMDZZM/SIXSIQRXOjI/AAAAAAAAACA/fFXiz04tnmQ/s1600-h/IMG_3396.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://bp3.blogger.com/_eOHzlCMDZZM/SIXSIQRXOjI/AAAAAAAAACA/fFXiz04tnmQ/s320/IMG_3396.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5225813981881907762" /&gt;&lt;/a&gt;Но результат того стоил... Шума вообще никакого не осталось. Винчестер шумит настолько тихо, что даже с открытым корпусом я его слышу только приблизив ухо к месторасположению винта.&lt;br /&gt;&lt;br /&gt;Вот интересно, как померять децибелы? микрофоном записывать такой незначительный шум вряд ли получится... Ну да не важно.&lt;br /&gt;&lt;br /&gt;А всетаки ksensors - отстойная программа. Оказывается у меня в системе перепутались два температурных датчика, и до сих пор я предполагал что первый датчик показывает температуру CPU, но сопоставив показания ksensors с показаниями sensors из комплекта lm_sensors обнаружил странное расхождение, которое вынудило меня зарыться в /etc/sensors.conf и выяснить что CPU temp - это второй датчик. Но раньше то я не обращал на него особого внимания, и предполагаю что он показывал нечто, болшее 40 градусов... Сейчас он показывает порядка 55-56 под нагрузкой.&lt;br /&gt;&lt;br /&gt;И вот еще подумал, существуют ли отдельные комплекты мониторинга состояния компьютера? а то мне явно не хватает датчиков. Мне нужен датчик на БП и на винт желательно тоже... Но пока продолжаю наблюдать за поведением системы. Погода распо
