<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="http://wiki.linuxformat.ru/wiki/skins/common/feed.css?303"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://wiki.linuxformat.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Lockal</id>
		<title>Linuxformat - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://wiki.linuxformat.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Lockal"/>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:Contributions/Lockal"/>
		<updated>2026-05-13T17:38:16Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.19.20+dfsg-0+deb7u3</generator>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF74-75:%D0%92_%D0%BE%D0%B6%D0%B8%D0%B4%D0%B0%D0%BD%D0%B8%D0%B8_%D0%9B%D0%B0%D1%80%D1%80%D0%B8</id>
		<title>LXF74-75:В ожидании Ларри</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF74-75:%D0%92_%D0%BE%D0%B6%D0%B8%D0%B4%D0%B0%D0%BD%D0%B8%D0%B8_%D0%9B%D0%B0%D1%80%D1%80%D0%B8"/>
				<updated>2008-07-11T15:45:40Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: Новая: {{Врезка|Ширина=300px |Заголовок=Визитка LXF |Содержание=;Ларри Уолл (Larry Wall) Лингвист по образованию, Ларри ...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Врезка|Ширина=300px&lt;br /&gt;
|Заголовок=Визитка LXF&lt;br /&gt;
|Содержание=;Ларри Уолл (Larry Wall)&lt;br /&gt;
Лингвист по образованию, Ларри &lt;br /&gt;
Уолл создал язык Perl в 1987 году. &lt;br /&gt;
В 90-е Ларри работал в O’Reilly администратором сервера, однако сейчас он трудится над Perl 6.&lt;br /&gt;
*Возраст:  44 (6 собачьих лет)&lt;br /&gt;
*Национальность:   Штатник &lt;br /&gt;
*Использует UNIX:  22 года&lt;br /&gt;
*Языков программирования:  35&lt;br /&gt;
*Количество ПК:   10 &lt;br /&gt;
*Дневная норма кофе:  1 кофейник&lt;br /&gt;
*Пар сандалий:   1&lt;br /&gt;
*Прямая речь: «Нам не особо интересно сообщать людям, чего они не могут сделать».}}&lt;br /&gt;
[[Изображение:LXF74-75-Larry-1.jpg|thumb|300px|Пол демонстрирует смертельный захват, который он собирается применить, если Perl 6 не будет готов в ближайшее время.]]&lt;br /&gt;
[[Изображение:LXF74-75-Larry-2.jpg|thumb|300px|Программа номер 6: Пол ни на минуту не прекращает сурово допрашивать Ларри…]]&lt;br /&gt;
[[Изображение:LXF74-75-Larry-3.jpg|thumb|300px|Эти Уоллы просто без ума от своих узорчиков… (Слева направо) Льюис, Арон, Женева, Глория и Ларри.]]&lt;br /&gt;
''Perl 6 разрабатывается уже несколько лет, и кажется, выпуска мы дождемся еще не скоро. Пол Хадсон (Paul Hudson) загнал Ларри Уолла (Larry Wall) в угол и спросил его, сколько это может продолжаться…''&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;br /&gt;
само понятие «Open Source».&lt;br /&gt;
Однако работа над его последним&lt;br /&gt;
проектом (речь, конечно, идет о&lt;br /&gt;
Perl 6), кажется, никогда не завершится. Гвидо ван Россум (Guido van&lt;br /&gt;
Rossum), создатель языка Python,&lt;br /&gt;
уже нарек релиз Perl 6 «тяжким крестом Perl». И правда, команда Уолла&lt;br /&gt;
планирует серьезные перемены&lt;br /&gt;
в языке. Мы встретились с Ларри и&lt;br /&gt;
его семьей, чтобы разобраться в&lt;br /&gt;
причинах задержки и понять, чего&lt;br /&gt;
можно ожидать от Perl 6. И в конце&lt;br /&gt;
концов он все-таки открыл нам дату&lt;br /&gt;
выпуска шестой версии Perl…&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;'''LXF:''' Организация Perl Foundation&lt;br /&gt;
финансировала некоторых разработчиков Perl, выделяя им гранты на&lt;br /&gt;
годовую или полугодовую работу, а кое-кто — включая Вас — написал&lt;br /&gt;
несколько отличных книг о Perl для&lt;br /&gt;
издательства O’Reilly. Как Вы считаете, это достаточный вклад в развитие Perl?&lt;br /&gt;
&amp;lt;br /&amp;gt;'''ЛУ:''' Проблема в том, что разработка&lt;br /&gt;
Perl 6 — это в первую очередь большая исследовательская работа, а&lt;br /&gt;
финансовый климат в последние&lt;br /&gt;
несколько лет не шибко способствовал подобным исследованиям. Никто&lt;br /&gt;
не хочет выкраивать на них деньги из&lt;br /&gt;
достаточно жесткого бюджета. Я сам&lt;br /&gt;
фактически был безработным около&lt;br /&gt;
пяти лет. Денег никогда не бывает&lt;br /&gt;
достаточно.&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;'''LXF:''' Я так понимаю, что когда Вы&lt;br /&gt;
занимаетесь консультированием, Вы&lt;br /&gt;
не занимаетесь разработкой Perl 6,&lt;br /&gt;
так же как и основной разработчик, Демиан Конвей (Damian Conway). Эта&lt;br /&gt;
работа ведь отдаляет нас от долгожданного релиза?&lt;br /&gt;
&amp;lt;br /&amp;gt;'''ЛУ:''' Да, и я, и Демиан занимаемся&lt;br /&gt;
консультациями, чтобы хоть как-то&lt;br /&gt;
сводить концы с концами. И это действительно мешает разработке Perl 6.&lt;br /&gt;
Мой участок работы — эмуляция&lt;br /&gt;
Perl 5 на Perl 6, но последнее время&lt;br /&gt;
мне некогда было этим заниматься.&lt;br /&gt;
Солидную помощь по развитию&lt;br /&gt;
инфраструктуры мы получили от Perl&lt;br /&gt;
Foundation и издательства O’Reilly.&lt;br /&gt;
O’Reilly, например, обеспечивает&lt;br /&gt;
наши еженедельные&lt;br /&gt;
телеконференции.&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;'''LXF:''' Вы покинули O’Reilly после краха дот-комов, когда люди перестали&lt;br /&gt;
покупать ваши книги?&lt;br /&gt;
&amp;lt;br /&amp;gt;'''ЛУ:''' Да, у O’Reilly тогда были серьезные проблемы, продажи падали -&lt;br /&gt;
еще до теракта 11 сентября, но&lt;br /&gt;
теракт здорово ухудшил ситуацию. Я&lt;br /&gt;
понимал, что был тогда одним из&lt;br /&gt;
самых бесполезных сотрудников&lt;br /&gt;
O’Reilly, поэтому ничуть не удивился&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;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;'''LXF:''' Все эти события происходили&lt;br /&gt;
около пяти лет назад, как раз когда&lt;br /&gt;
Вы начали работу над Perl 6?&lt;br /&gt;
&amp;lt;br /&amp;gt;'''ЛУ:''' Я принялся за Perl 6 за несколько&lt;br /&gt;
месяцев до того, но мое расставание&lt;br /&gt;
с O’Reilly тут ни при чем.&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;'''LXF:''' Тем не менее работа над Perl 6&lt;br /&gt;
замедлилась?&lt;br /&gt;
&amp;lt;br /&amp;gt;'''ЛУ:''' Да, но мы были терпеливы — проектирование требовало много времени. В индустрии программного обеспечения есть хорошее высказывание:&lt;br /&gt;
«Хороший. Быстрый. Дешевый.&lt;br /&gt;
Любой продукт может обладать только двумя из этих трех качеств». Наш&lt;br /&gt;
проект — с открытым исходным&lt;br /&gt;
кодом, он «дешевый» по определению. Высказывание, значит, упростилось до «Либо хороший, либо быстрый. Выбирайте». Мы выбрали&lt;br /&gt;
«хороший», поэтому быстрая разработка исключалась.&lt;br /&gt;
Наш неофициальный девиз -&lt;br /&gt;
«Perl 6: синдром второй версии в&lt;br /&gt;
хорошем смысле». [&amp;quot;Синдром второй&lt;br /&gt;
версии&amp;quot; — это ситуация, когда разработчики программного продукта из кожи вон&lt;br /&gt;
лезут, чтоб версия 2.0 намного превзошла версию 1.0, а в итоге просто нашпиговывают ее избыточными функциями,&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;
Perl 6 на рынок. Наша цель — оставить все существующие скриптовые&lt;br /&gt;
языки далеко позади.&lt;br /&gt;
Вот какие у нас планы. Вроде они&lt;br /&gt;
работают, хотя мы, признаться, не&lt;br /&gt;
ожидали, что начальная фаза разработки займет целых 5 лет.&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;'''LXF:''' Так это только начальная фаза?!&lt;br /&gt;
&amp;lt;br /&amp;gt;'''ЛУ:''' Да, на данный момент мы завершили 80 % проектирования. Сейчас&lt;br /&gt;
работаем над остальными 80 %!&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;'''LXF:''' Касательно «синдрома второй&lt;br /&gt;
версии»: мудрые люди утверждают,&lt;br /&gt;
что при разработке крупного программного продукта одна из версий&lt;br /&gt;
обязательно отправляется в мусорную корзину. Вы уверены, что Perl 6&lt;br /&gt;
не окажется неудачной версией?&lt;br /&gt;
&amp;lt;br /&amp;gt;'''ЛУ:''' Ну, вообще-то мы надеемся, что&lt;br /&gt;
«неудачной версией» был Perl 5;&lt;br /&gt;
потому что я проектировал и разрабатывал его практически в одиночку.&lt;br /&gt;
То есть эта версия ограничена моим&lt;br /&gt;
видением того, каким должен быть&lt;br /&gt;
язык программирования. Конечно,&lt;br /&gt;
привлечение большего числа разработчиков способствует появлению&lt;br /&gt;
«разбухшей версии», но зато помогает более широкому видению&lt;br /&gt;
предмета.&lt;br /&gt;
Чтобы не потерять это преимущество, мы решились реструктурировать переработку Perl 6, но не бросать на проект дополнительных программистов просто потому, что время поджимает.&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;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;'''LXF:''' Тогда Вы должны быть&lt;br /&gt;
жестким…&lt;br /&gt;
&amp;lt;br /&amp;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;br /&gt;
думаю, это хороший признак.&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;'''LXF:''' Один человек недавно сказал&lt;br /&gt;
мне — по-моему, это был Ваш исполнительный секретарь: «У Ларри не все&lt;br /&gt;
хорошо со временем и датами, это&lt;br /&gt;
легко видеть на примере Perl 6».&lt;br /&gt;
Думали ли Вы пять лет назад, что до&lt;br /&gt;
сих пор будете разрабатывать эту&lt;br /&gt;
версию Perl? Может быть, Вы надеялись управиться к 2003-му году?&lt;br /&gt;
&amp;lt;br /&amp;gt;'''ЛУ:''' Выпуская Perl 5, мы думали&lt;br /&gt;
о том, что получим штук 20 запросов&lt;br /&gt;
с советами, как исправить Perl 5.&lt;br /&gt;
Оказалось, что их в 15 раз больше.&lt;br /&gt;
Через пару месяцев стало ясно, что&lt;br /&gt;
переделок будет либо гораздо меньше, либо гораздо больше, чем мы&lt;br /&gt;
рассчитывали, и мы приняли решение заняться большой перестройкой.&lt;br /&gt;
Я просто на ушах стоял, пытаясь&lt;br /&gt;
переварить полученные 361&lt;br /&gt;
замечание.&lt;br /&gt;
ГЛОРИЯ УОЛЛ (Gloria Wall): Ты на&lt;br /&gt;
несколько месяцев был буквально&lt;br /&gt;
парализован.&lt;br /&gt;
&amp;lt;br /&amp;gt;'''ЛУ:''' Но я метался в поисках решения.&lt;br /&gt;
Причем каждый из авторов подобных&lt;br /&gt;
запросов предлагал исправить что-то&lt;br /&gt;
свое, а некоторые предложения были&lt;br /&gt;
противоречивы или несовместимы.&lt;br /&gt;
Никто не мог представить Perl 6&lt;br /&gt;
в целом, все сфокусировались на&lt;br /&gt;
каких-то частностях. Мне пришлось&lt;br /&gt;
изобретать способы разгрести все эти&lt;br /&gt;
запросы. В конечном итоге я их классифицировал по принципу, изложенному в моей [ставшей классической]&lt;br /&gt;
книге о Perl: от мелкого к крупному. Я&lt;br /&gt;
осознал, что описание языка и его&lt;br /&gt;
перестройка требуют одинакового&lt;br /&gt;
порядка действий. Пришлось немало&lt;br /&gt;
потрудиться, но проект в общих чертах следовал данному принципу.&lt;br /&gt;
ГУ: К тому же Ларри не ожидал, что&lt;br /&gt;
заболеет. Год был из проекта вынут.&lt;br /&gt;
&amp;lt;br /&amp;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;br /&gt;
плана…&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;'''LXF:''' Вы сказали, что ожидали снижения доли Perl на рынке скриптовых&lt;br /&gt;
языков, учитывая промежуток времени между Perl 5 и Perl 6. Но лично&lt;br /&gt;
я никакого снижения не вижу, Perl&lt;br /&gt;
сейчас популярен как никогда. Вас&lt;br /&gt;
это ободряет?&lt;br /&gt;
&amp;lt;br /&amp;gt;'''ЛУ:''' Да, ободряет. Продажа книг&lt;br /&gt;
о Perl немного уменьшилась, хотя я&lt;br /&gt;
не знаю, насколько это показательно.&lt;br /&gt;
Сейчас начинается новый раунд&lt;br /&gt;
выпуска книг о Perl 5, и пока неизвестно, как их примут.&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;'''LXF:''' По-моему, Тим говорил, что продажи книг о Perl увеличились за&lt;br /&gt;
последние месяцы на 19 %, благодаря новой книге «Learning Perl»&lt;br /&gt;
(«Изучаем Perl»).&lt;br /&gt;
ГУ: Вы знаете, проценты как раз снизились, зато абсолютные числа продолжают расти.&lt;br /&gt;
&amp;lt;br /&amp;gt;'''ЛУ:''' Даже если продажи книг падают,&lt;br /&gt;
причиной может быть просто хорошая документация. Это ведь open&lt;br /&gt;
source, и многое не поддается учету.&lt;br /&gt;
Если вы занимаетесь маркетингом&lt;br /&gt;
и фиксируете каждую продажу, то&lt;br /&gt;
можно посчитать, сколько народу&lt;br /&gt;
приобрело ваш продукт — кроме&lt;br /&gt;
пиратов, конечно…&lt;br /&gt;
В open source никого не назовешь&lt;br /&gt;
«пиратом», разве что в опереточнолитературном смысле этого слова,&lt;br /&gt;
но здесь гораздо сложнее проследить, кто чем пользуется.&lt;br /&gt;
Я вижу намного больше поддержки, особенно когда мы стали работать над компилятором Perl 6 (написанном, кстати, на Haskell). Я вижу&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;
Perl 6, короче, ждать осталось&lt;br /&gt;
недолго.&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;'''LXF:''' Звучит неплохо…&lt;br /&gt;
&amp;lt;br /&amp;gt;'''ЛУ:''' Не могу предсказать, что через&lt;br /&gt;
год мы получим окончательную реализацию, но точно будем запускаться на множестве платформ, одна из&lt;br /&gt;
которых — Parrot (та самая виртуальная машина). Уже можно работать поверх JavaScript, Parrot, и есть&lt;br /&gt;
даже реализация Perl 6 на движке&lt;br /&gt;
от Perl 5. Выглядит это, конечно,&lt;br /&gt;
безумно, и я не думаю, что это очень&lt;br /&gt;
эффективное решение, но оно имеет&lt;br /&gt;
право на существование, хотя бы для&lt;br /&gt;
разнообразия.&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;'''LXF:''' Мне нравятся многие вещи в&lt;br /&gt;
Perl 6. Мне нравится суммарная суперпозиция, мне нравятся операторы свертки — это просто чудо.&lt;br /&gt;
&amp;lt;br /&amp;gt;'''ЛУ:''' Эти вещи взяты из языка APL, но&lt;br /&gt;
в отличие APL, мы попытались оптимизировать их для удобного чтения.&lt;br /&gt;
Посмотрите на APL, и вы поймете, что если надо разобраться в&lt;br /&gt;
чужой программе, вы должны четко&lt;br /&gt;
представлять себе, что делает каждый отдельно взятый оператор.&lt;br /&gt;
Посмотрите на Perl 6, и вы удивитесь, насколько он проще и логичнее.&lt;br /&gt;
Сразу понятно, зачем нужны квадратные скобки, и что они делают со списками, и куда прилагается оператор&lt;br /&gt;
посередке, утверждение глотается&lt;br /&gt;
запросто, как пилюля. Я — сторонник&lt;br /&gt;
читаемого кода, потому что даже&lt;br /&gt;
если он выполняет сложные вещи,&lt;br /&gt;
но описывает их наглядно, программистам это нравится. Мы гордимся&lt;br /&gt;
синтаксисом нашего продукта.&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;'''LXF:''' Чем Вас особенно радует Perl 6?&lt;br /&gt;
Кроме мысли, что он почти готов,&lt;br /&gt;
конечно.&lt;br /&gt;
&amp;lt;br /&amp;gt;'''ЛУ:''' Я думаю, что в нем будут части,&lt;br /&gt;
развивающиеся быстрее, чем Perl 5.&lt;br /&gt;
Язык Perl всегда был расширяемым.&lt;br /&gt;
По этой причине мы добавили символы-префиксы для обозначения&lt;br /&gt;
переменных. Perl 5 тоже предусматривает расширяемость, и он все еще&lt;br /&gt;
развивается, благодаря архиву исходных текстов и модулей CPAN,&lt;br /&gt;
которым мы можем гордиться до&lt;br /&gt;
сих пор.&lt;br /&gt;
Однако есть множество причин,&lt;br /&gt;
по которым пятая версия Perl уже&lt;br /&gt;
изжила себя. У нас есть способы&lt;br /&gt;
изменения синтаксиса языка, но они&lt;br /&gt;
очень примитивны. У нас есть механизм, называемый source-фильтром,&lt;br /&gt;
но с ним тоже далеко не все&lt;br /&gt;
благополучно.&lt;br /&gt;
В Perl 6 мы фактически даем программисту полный контроль над синтаксисом, так что вы сможете варьировать «грамматику» языка, как&lt;br /&gt;
угодно изменять язык и экспериментировать, подчиняя язык новой семантике. Тогда путем «естественного отбора» мы сможем определить, в каком направлении развивать&lt;br /&gt;
Perl 6.&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;'''LXF:''' Наверное, в ориентации на&lt;br /&gt;
обычного пользователя?&lt;br /&gt;
&amp;lt;br /&amp;gt;'''ЛУ:''' Отчасти развитие состоит в обеспечении взаимодействия независимых версий, например, если вы&lt;br /&gt;
используете какие-нибудь два модуля, которые требуют разные версии&lt;br /&gt;
другого модуля — мы должны позволить им сосуществовать. Если,&lt;br /&gt;
конечно, эти два модуля не потребуют доступа к каким-нибудь закрытым&lt;br /&gt;
ресурсам.&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;'''LXF:''' Вы сказали, что разработка шестой версии — Ваш единственный шанс&lt;br /&gt;
разрушить обратную совместимость.&lt;br /&gt;
Не думаете ли Вы, что совместимость&lt;br /&gt;
нарушит, скажем, Perl 9?&lt;br /&gt;
ГУ: Никакой девятой версии не будет.&lt;br /&gt;
&amp;lt;br /&amp;gt;'''ЛУ:''' Я надеюсь, что мы сделаем достаточно гибкий язык, чтобы все&lt;br /&gt;
последующие версии использовали&lt;br /&gt;
эту гибкость. Может быть, его переименуют в Perl 7, 8 или 9, но разве&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;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;'''LXF:''' Вы ведь можете оставить&lt;br /&gt;
людей, использующих Perl 5.8,&lt;br /&gt;
ни с чем.&lt;br /&gt;
&amp;lt;br /&amp;gt;'''ЛУ:''' Не совсем так. Perl 5 — это open&lt;br /&gt;
source, и он никуда не денется. Пока&lt;br /&gt;
он кому-нибудь нужен, его будут&lt;br /&gt;
поддерживать. Это одна из причин,&lt;br /&gt;
по которым мы затеяли столь масштабную переработку. Поскольку&lt;br /&gt;
Perl 5 является довольно стабильной&lt;br /&gt;
базой, многие им пользуются. В нем нелегко отыскать ошибки, поэтому&lt;br /&gt;
он не подвержен быстрым изменениям. На примере тех, кто до сих пор&lt;br /&gt;
работает на Perl 4, мы можем с уверенностью утверждать, что Perl 5&lt;br /&gt;
будет актуален еще лет пять после&lt;br /&gt;
выхода Perl 6. Нам не особо интересно сообщать людям, чего они не&lt;br /&gt;
могут сделать.&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;'''LXF:''' Вас не беспокоит, что могут найтись люди, которые отпочкуют версию Perl 5.8, добавив в него парутройку новых функций, и в конце&lt;br /&gt;
концов превратят его в реального&lt;br /&gt;
конкурента Perl 6?&lt;br /&gt;
&amp;lt;br /&amp;gt;'''ЛУ:''' Я бы не рассматривал это как&lt;br /&gt;
почкование. Нет проблем, пусть&lt;br /&gt;
делают. Perl 6 как раз и пытается&lt;br /&gt;
облегчить создание индивидуальных&lt;br /&gt;
версий по личному вкусу. Не думаю,&lt;br /&gt;
что кому-то сильно захочется страдать над расширением Perl 5.&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;'''LXF:''' И последнее: когда же мы увидим финальную версию Perl 6?&lt;br /&gt;
Назовите точную дату!&lt;br /&gt;
&amp;lt;br /&amp;gt;'''ЛУ:''' Посмотрим… 30-го июля.&lt;br /&gt;
&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;'''LXF:''' Какого года?&lt;br /&gt;
&amp;lt;br /&amp;gt;'''ЛУ:''' Не скажу! LXF&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF74-75:%D0%AD%D0%BD%D0%B4%D1%80%D1%8E_%D0%9C%D0%BE%D1%80%D1%82%D0%BE%D0%BD</id>
		<title>LXF74-75:Эндрю Мортон</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF74-75:%D0%AD%D0%BD%D0%B4%D1%80%D1%8E_%D0%9C%D0%BE%D1%80%D1%82%D0%BE%D0%BD"/>
				<updated>2008-07-11T15:19:09Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: Новая: == «Мне жаль, что Линус не использовал CVS с первого дня» ==  ''Официальный maintainer — хранитель ядра — расс...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== «Мне жаль, что Линус не использовал CVS с первого дня» ==&lt;br /&gt;
&lt;br /&gt;
''Официальный maintainer — хранитель ядра — рассказывает о процессе разработки и о необходимости улучшения контроля качества.''&lt;br /&gt;
{{Врезка|Ширина=300px&lt;br /&gt;
|Заголовок=Визитка LXF&lt;br /&gt;
|Содержание=;Эндрю Мортон&lt;br /&gt;
Официальный хранитель &lt;br /&gt;
ядра Linux версии 2.6 и &lt;br /&gt;
постоянный сотрудник OSDL &lt;br /&gt;
ядра, Эндрю уже давно &lt;br /&gt;
входит в узкий круг главных &lt;br /&gt;
разработчиков ядра.&lt;br /&gt;
*Возраст: 0x2E&lt;br /&gt;
*Национальность:  Австралиец&lt;br /&gt;
*Использует Linux:  10 лет&lt;br /&gt;
*Языки программирования:  Молчит&lt;br /&gt;
*Количество ПК:   20 &lt;br /&gt;
*Дневная норма кофе: 4 чашки&lt;br /&gt;
*Пар сандалий:   0&lt;br /&gt;
Прямая речь: «Модель разработки с выпуском крупных релизов каждые 2-3 года просто не работоспособна.»}}&lt;br /&gt;
&lt;br /&gt;
Мы встретились с&lt;br /&gt;
главным разработчиком ядра 2.6,&lt;br /&gt;
усадили его в&lt;br /&gt;
большое надувное&lt;br /&gt;
кресло и попросили ответить на наши вопросы.&lt;br /&gt;
Фактически, Эндрю Мортон является&lt;br /&gt;
вторым человеком (после Линуса&lt;br /&gt;
Торвальдса, конечно), на котором держится весь процесс разработки ядра&lt;br /&gt;
Linux, так что он оказал нам бесценную помощь в проникновении на&lt;br /&gt;
главную кухню разработчиков. Мы&lt;br /&gt;
увидели его на OSCon 2005 и поговорили о переходе с BitKeeper, исправлении ошибок и необходимости увеличения скорости работы ядер Linux.&lt;br /&gt;
&lt;br /&gt;
;LXF&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt; Переход на BitKeeper раздражал многих людей, особенно из FSF. Потом был переход на Git… Не окажется ли Git всего лишь временным решением?&lt;br /&gt;
'''ЭМ:''' Нет, я думаю, что Git останется надолго.&lt;br /&gt;
&lt;br /&gt;
;LXF&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt; Значит, Вы считаете, что Git практически вечен?&lt;br /&gt;
'''ЭМ:''' Я предполагаю, что да. Дело в&lt;br /&gt;
том, что цена подобного перехода&lt;br /&gt;
слишком высока и с лихвой перекрывает все возможные выгоды.&lt;br /&gt;
&lt;br /&gt;
;LXF&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt; Не думаете ли Вы, что Git должен был появиться раньше, или что с самого начала следовало бы использовать CVS?&lt;br /&gt;
'''ЭМ:''' Ну, мы никогда не использовали&lt;br /&gt;
CVS. Вернее, до BitKeeper мы вообще&lt;br /&gt;
не пользовались подобными инструментами — просто была куча заплаток, которые хранились у Линуса на&lt;br /&gt;
жестком диске, и иногда он включал&lt;br /&gt;
их в ядро. Мы вообще никак не могли проследить, что туда попало. Помоему, это как-то не очень вежливо,&lt;br /&gt;
и мне жаль, что Линус не использовал CVS с самого начала. Он ненавидит CVS, потому что имел с ним проблемы, однако я считаю, что для&lt;br /&gt;
простой линейной модели развития&lt;br /&gt;
использование CVS было оправдано,&lt;br /&gt;
да и появилась бы история&lt;br /&gt;
изменений.&lt;br /&gt;
&lt;br /&gt;
Я думаю, главная заслуга&lt;br /&gt;
BitKeeper — в том, что Линус вообще&lt;br /&gt;
стал хоть чем-то пользоваться. При&lt;br /&gt;
любой другой свободной системе&lt;br /&gt;
контроля версий мы все равно прошли бы 90 % пути. Просто BitKeeper&lt;br /&gt;
был тогда лучшей подобной системой&lt;br /&gt;
и подходил под наш процесс разработки. Я и сам чувствовал себя некомфортно, используя BitKeeper — естественно, из-за его проприетарности, но&lt;br /&gt;
с этим жить можно. В конце концов,&lt;br /&gt;
моя главная задача — улучшение ядра,&lt;br /&gt;
а не… э-э… религиозный фанатизм.&lt;br /&gt;
Я всегда ждал, что конец будет&lt;br /&gt;
плачевным и BitKeeper откинет колеса.&lt;br /&gt;
Переход оказался более резким, чем&lt;br /&gt;
я рассчитывал, но мы довольно легко&lt;br /&gt;
вышли из неприятной ситуации.&lt;br /&gt;
&lt;br /&gt;
;LXF&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt; Показал ли BitKeeper широкой общественности, как надо работать? Ведь благодаря ему Вы и перешли на Git, вместо того, чтобы вернуться к старой модели получения заплаток по электронной почте. Правда, что он создал такие преимущества, без которых люди теперь не могут обойтись?&lt;br /&gt;
'''ЭМ:''' Да, конечно, мы теперь не сможем жить без системы контроля версий и ни за что не вернемся к старой&lt;br /&gt;
модели разработки, которая существовала до BitKeeper. Все очень оценили его удобства.&lt;br /&gt;
&lt;br /&gt;
;LXF&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt; Наверняка ускорилось внедрение исправлений.&lt;br /&gt;
'''ЭМ:''' Так говорят… Скорее, это облегчило работу Линусу — система контроля версий позволяет ему доверять&lt;br /&gt;
людям. Например, если Грег КроаХартман (Greg Kroah-Hartman) вышлет&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;br /&gt;
&lt;br /&gt;
;LXF&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt; Вы сказали, что число разработчиков постоянно растет. Однако создается впечатление, что и журнал изменений в каждой новой версии все больше. Я просмотрел 2.6.2 (287К), 2.6.4 (322К), 2.6.6 (487К), 2.6.8 (883К), 2.6.10 (1.5МБ)…&lt;br /&gt;
'''ЭМ:''' Каждый новый журнал включает&lt;br /&gt;
в себя все старые, но в общем это&lt;br /&gt;
действительно так.&lt;br /&gt;
;LXF&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt; Это отражает повышение скорости разработки?&lt;br /&gt;
'''ЭМ:''' В некоторой степени да. Раньше&lt;br /&gt;
выпуски появлялись один за другим,&lt;br /&gt;
а в последнее время мы несколько&lt;br /&gt;
снизили частоту. Но сама разработка&lt;br /&gt;
медленнее не стала.&lt;br /&gt;
;LXF&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt; Я заметил, что в журнале изменений есть позиция «Signed off by» — «Подписано таким-то». Зачем это нужно?&lt;br /&gt;
'''ЭМ:''' Это своеобразный способ избавиться от «глупостей» SCO. Люди&lt;br /&gt;
хотели иметь возможность разобраться, откуда взялись конкретные участки кода. Нам и самим, независимо от&lt;br /&gt;
них, казалось, что неплохо бы знать,&lt;br /&gt;
кто прислал «кривой» код. Таким&lt;br /&gt;
образом, мы приняли простое соглашение: каждый, кто предложил какуюто заплатку, должен подписать ее&lt;br /&gt;
своим прозвищем. «Подписано» значит, что автор читал «Сертификат об&lt;br /&gt;
источнике» (Developer’s Certificate of&lt;br /&gt;
Origin), который содержится в документации ядра, и согласен с ним.&lt;br /&gt;
;LXF&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt; Значит, эта надпись говорит не о качестве кода, а лишь сообщает, что&lt;br /&gt;
«я верю, они это сами написали»?&lt;br /&gt;
'''ЭМ:''' Да, так и есть. Эта надпись говорит «я написал этот код сам, я подтверждаю, что не стырил его из какой-нибудь UnixWare или другой системы».&lt;br /&gt;
И каждый, кто присылает заплатки,&lt;br /&gt;
обычно добавляет подобную подпись.&lt;br /&gt;
Есть еще гриф «Ackd by».&lt;br /&gt;
;LXF&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt; А это что значит?&lt;br /&gt;
'''ЭМ:''' Это значит «Одобрено», для случаев, когда кто-то просто проверил&lt;br /&gt;
чей-то код, но ничего в нем не менял.&lt;br /&gt;
Вообще-то это предназначено для&lt;br /&gt;
хранителей-maintainer’ов, которые&lt;br /&gt;
хотят подчеркнуть, что заплатка&lt;br /&gt;
проверена.&lt;br /&gt;
;LXF&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt; Видимо, модель разработки стабильных версий ядра 2.6 тоже изменится. В прошлом году нам показалось, что в ядро попадают и нестабильные куски кода, о которых должны позаботиться разработчики дистрибутивов.&lt;br /&gt;
'''ЭМ:''' Да, так оно и было.&lt;br /&gt;
LXF: Теперь же есть двухнедельное&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;
новую версию, все хранители подсистем, а их 50-70 человек, принимаются включать весь накопившийся&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;br /&gt;
раз, например, нам пришлось капитально обновлять аудиодрайвер спустя всего четыре недели после выпуска&lt;br /&gt;
2.6.12. И все из-за плохой синхронизации, потому что здоровенный кусок&lt;br /&gt;
кода куда-то потерялся за то время,&lt;br /&gt;
когда шла проверка стабильности.&lt;br /&gt;
Мы хотим, чтобы хранители подсистем работали в более тесной связке с&lt;br /&gt;
разработчиками ядра.&lt;br /&gt;
;LXF&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt; Вы сказали, что скорость разработки ядра постоянно растет, а по моим наблюдениям, промежуток времени между выходом новых версий ядра увеличивается. Может быть, развелось слишком много хранителей ядра, которые почем зря закидывают вас заплатками?&lt;br /&gt;
'''ЭМ:''' Главное, слишком много кода -&lt;br /&gt;
время уходит на его проверку, доработку, тестирование. Бывает, большие куски кода доходят с опозданием: если доработанная SCSI-подсистема попадает к нам на 5-й неделе,&lt;br /&gt;
мы не в состоянии выпустить устойчивое ядро со всеми изменениями,&lt;br /&gt;
уложившись в график. Нужно же все&lt;br /&gt;
«обкатать»!&lt;br /&gt;
;LXF&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt; У Вас существует плановая периодичность выпуска ядра?&lt;br /&gt;
'''ЭМ:''' Нет, мы их выпускаем, когда они&lt;br /&gt;
кажутся нам рабочими, хотя многим&lt;br /&gt;
хотелось бы видеть новые версии&lt;br /&gt;
почаще. Я думаю, нам по силам обеспечить периодичность в два — два с&lt;br /&gt;
половиной месяца. Возможно, комуто кажется, что это долго. Я не хотел&lt;br /&gt;
бы превышать двухмесячный период.&lt;br /&gt;
;LXF&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt; Когда Торвальдс объявил, что будет работать на PowerPC, он назвал Power 5 и ЭМD64 двумя самыми перспективными архитектурами. Вы согласны с этим заявлением?&lt;br /&gt;
'''ЭМ:''' Ну, в общем, x86 уже не тот, что&lt;br /&gt;
раньше; а вот c x86-64 все&lt;br /&gt;
хорошо. Люди просто принимают слишком близко к сердцу, какая именно машина&lt;br /&gt;
в данный момент у Линуса на&lt;br /&gt;
столе. Я не думаю, что это&lt;br /&gt;
так важно. У него хватает&lt;br /&gt;
компьютеров x86 для&lt;br /&gt;
тестирования.&lt;br /&gt;
;LXF&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt; Он теперь переехал в Портленд — наверное, тяжело жить так далеко от него, по сравнению с былыми днями?&lt;br /&gt;
'''ЭМ:''' Фактически, мы жили на расстоянии 20 минут: он — в Сан-Хосе, а я -&lt;br /&gt;
в Пало-Альто. А лично встречались&lt;br /&gt;
тогда всего два раза.&lt;br /&gt;
;LXF&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt; Если говорить о вещах, которые сейчас на слуху, вроде Xen или Inotify — Вы находите их интересными?&lt;br /&gt;
'''ЭМ:''' Ну, Xen, очевидно, очень нужен&lt;br /&gt;
многим. Я не склонен что-либо предусматривать только потому, что люди&lt;br /&gt;
нам это присылают. Принятие решения о нововведениях в ядро происходит коллегиально. Мы с Линусом не&lt;br /&gt;
бросаем клич вроде «Эй, нам нужны&lt;br /&gt;
x, y и z в третьем квартале 2006-го&lt;br /&gt;
года».&lt;br /&gt;
&lt;br /&gt;
Если какой-нибудь группе требуются специфические изменения&lt;br /&gt;
в ядре, они выпускают свою версию,&lt;br /&gt;
а не ждут, пока мы включим эти&lt;br /&gt;
заплатки в основную ветвь.&lt;br /&gt;
&lt;br /&gt;
А что в будущем? [напомним, интервью бралось на конференции OSCon осенью 2005 года, — прим.ред.] FUSE мы&lt;br /&gt;
скоро поместим, очень многим это&lt;br /&gt;
понравится. Кластерную файловую&lt;br /&gt;
систему OCFS планируем включить в&lt;br /&gt;
ядро 2.6.14. Кластеры — довольно&lt;br /&gt;
обширная тема, мы потратили на нее&lt;br /&gt;
много лет.&lt;br /&gt;
&lt;br /&gt;
Существует масса кластерных&lt;br /&gt;
проектов, но все они слишком разные,&lt;br /&gt;
и их разработчики никак не могут&lt;br /&gt;
найти точек соприкосновения и договориться. OCFS же выглядит готовым&lt;br /&gt;
решением, и нет никаких препятствий&lt;br /&gt;
включению его в ядро. Я отнюдь не&lt;br /&gt;
уверен, что со штуками вроде Red Hat&lt;br /&gt;
GFS будет так же легко.&lt;br /&gt;
Ну что еще.. не знаю, что вам сказать. Какие нам коды люди пришлют,&lt;br /&gt;
такие и будем внедрять.&lt;br /&gt;
;LXF&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt; Как долго код из Вашего mmдерева добирается до официальной версии ядра Линуса?&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;
Reiser4, это около 2-х мегабайт, и&lt;br /&gt;
несколько других интересных функций. Они не влияют на идеологию&lt;br /&gt;
ядра, просто добавляют какие-то&lt;br /&gt;
функции, но это большие куски кода.&lt;br /&gt;
;LXF&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt; Над чем лично вы сейчас работаете? Например, вы еще используете какой-нибудь DDE?&lt;br /&gt;
'''ЭМ:''' Боюсь, что да. Я давненько не&lt;br /&gt;
занимался пользовательским пространством, вожусь с дурацким&lt;br /&gt;
скриптом управления патчами.&lt;br /&gt;
;LXF&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt; Вы тратите 12-14 часов в сутки на работу с ядром?&lt;br /&gt;
'''ЭМ:''' Да, тестирую новые патчи,&lt;br /&gt;
исправляю ошибки и т. д. Связываюсь&lt;br /&gt;
с другими разработчиками. На борьбу&lt;br /&gt;
с ошибками уходит довольно много&lt;br /&gt;
времени.&lt;br /&gt;
;LXF&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt; На исправление ошибок?&lt;br /&gt;
'''ЭМ:''' Скорее, на выяснение информации об ошибке. Иногда отчеты об&lt;br /&gt;
ошибке (а это очень ценная вещь)&lt;br /&gt;
присылаются довольно бестолковые — приходится вступать в диалог с&lt;br /&gt;
отправителем, чтобы разобраться.&lt;br /&gt;
Причем я всегда стараюсь найти автора проблемного кода. Вот прямо сейчас мы работаем над rc5 ядра, где&lt;br /&gt;
ничего особенного добавлено не&lt;br /&gt;
было — сплошные исправления&lt;br /&gt;
ошибок.&lt;br /&gt;
;LXF&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt; Таким образом, это почти маркетинг ошибок, их пропаганда…&lt;br /&gt;
'''ЭМ:''' До известной степени да, равно&lt;br /&gt;
как и социальная инженерия.&lt;br /&gt;
;LXF&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;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;
;LXF&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt; Кроме ядра, есть ли другие проекты, которые Вам интересны и над которыми Вы хотели бы работать?&lt;br /&gt;
'''ЭМ:''' Я немного соскучился по&lt;br /&gt;
написанию кода; думаю, когда я&lt;br /&gt;
почувствую, что не справляюсь с&lt;br /&gt;
работой, я передам обязанности&lt;br /&gt;
кому-нибудь другому, а сам вернусь к поддержке своего конкретного кусочка ядра.&lt;br /&gt;
;LXF&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt; Вы сейчас на «острие прогресса» ядра. Когда появится версия 2.7, будете ли Вы продолжать развивать линейку 2.6, или передадите ее кому-нибудь другому, а сами будете готовить 2.8?&lt;br /&gt;
'''ЭМ:''' Поживем — увидим. Многое будет&lt;br /&gt;
зависеть от причин для выпуска 2.7; я&lt;br /&gt;
пока не представляю, какими они&lt;br /&gt;
будут. Одна из возможных причин -&lt;br /&gt;
неудовлетворенность качеством ядер&lt;br /&gt;
2.6. Но я думаю, что ветви 2.6 еще&lt;br /&gt;
есть куда расти.&lt;br /&gt;
;LXF&amp;lt;nowiki&amp;gt;:&amp;lt;/nowiki&amp;gt; Что Вы намерены делать дальше?&lt;br /&gt;
'''ЭМ:''' Вероятно, я в том или ином качестве буду работать над Linux — скорее&lt;br /&gt;
всего, до конца своей карьеры.&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF74-75:%D0%94%D0%B8%D1%81%D1%82%D1%80%D0%B8%D0%B1%D1%83%D1%82%D0%B8%D0%B2_%D1%81%D0%B2%D0%BE%D0%B8%D0%BC%D0%B8_%D1%80%D1%83%D0%BA%D0%B0%D0%BC%D0%B8</id>
		<title>LXF74-75:Дистрибутив своими руками</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF74-75:%D0%94%D0%B8%D1%81%D1%82%D1%80%D0%B8%D0%B1%D1%83%D1%82%D0%B8%D0%B2_%D1%81%D0%B2%D0%BE%D0%B8%D0%BC%D0%B8_%D1%80%D1%83%D0%BA%D0%B0%D0%BC%D0%B8"/>
				<updated>2008-07-11T15:00:17Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: оформление&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{TOCright}}&lt;br /&gt;
== Соберите свой собственный дистрибутив ==&lt;br /&gt;
{{Врезка|Ширина=300px&lt;br /&gt;
|Заголовок=Дистрибутив вашей мечты&lt;br /&gt;
|Содержание=Как мы сейчас увидим, не так уж и сложно изменить набор программ, включенных в дистрибутив, и &lt;br /&gt;
его внешний вид. Но что можно сделать? Вот несколько идей, чтобы включить ваше воображение:&lt;br /&gt;
* Музыкальная студия. Дистрибутив, ориентированный на создание и редактирование &lt;br /&gt;
музыкальных файлов. В этом случае основные изменения будут касаться выбора ПО, в частности, &lt;br /&gt;
можно удалить офисные пакеты и добавить Audacity, Freecycle и другие.&lt;br /&gt;
* Реклама. Дистрибутив, разработанный для распространения информации о вашей компании или &lt;br /&gt;
проекте. Вы можете оставить набор программ без изменения, но придать глянец вашему &lt;br /&gt;
дистрибутиву, разместив свои логотипы, изображения и фон.&lt;br /&gt;
* Минимализм. Вместо того чтобы использовать тяжеловесные пакеты наподобие KDE и &lt;br /&gt;
OpenOffice.org, вы можете остановиться на «тонких» альтернативах, таких как IceWM и Siag. Вы &lt;br /&gt;
можете создать предельно минималистский дистрибутив для использования на слабых машинах.&lt;br /&gt;
}}&lt;br /&gt;
''Создать собственный дистрибутив Linux проще, чем вы могли бы подумать, к тому же еще и интересно! Майк Сондерс (Mike Saunders) надевает свой комбинезон и каску, готовый показать вам, как это делается…''&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;
создание своего собственного дистрибутива Linux, довольно трудоемкое, как может&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;
Knoppix Live CD. Мы также получим множество других инструкций и подсказок, как&lt;br /&gt;
придать собственный оттенок любому Linux,&lt;br /&gt;
какому пожелаем.&lt;br /&gt;
&lt;br /&gt;
Учитывая огромное количество имеющихся дистрибутивов, вы можете удивиться: «что за нужда создавать еще один?».&lt;br /&gt;
* Выбор. Возможно, ни один из существующих дистрибутивов не удовлетворяет&lt;br /&gt;
полностью вашим потребностям. Вам нравится, например, Knoppix, но хочется удалить раздутую программу А, и заменить ее&lt;br /&gt;
легковесной программой Б, а также использовать в качестве фона изображение симпатичного пингвина. Вы можете создать дистрибутив из чего угодно, и где угодно.&lt;br /&gt;
* Изучение на практике. Понимание&lt;br /&gt;
того, как программы объединяются в дистрибутивы, что поставщики делают, чтобы&lt;br /&gt;
придать своим дистрибутивам индивидуальность и какие препятствия поджидают&lt;br /&gt;
на этом пути — ценные знания, особенно&lt;br /&gt;
если вы планируете когда-либо участвовать в проекте разработки дистрибутива.&lt;br /&gt;
* Пропаганда. Если вы продвигаете проект программного обеспечения, ориентированного на Linux, и хотели бы продемонстрировать его пользователям Windows, идеальным решением будет создание тематического Live CD, содержащего ваше приложение. Аналогично, если вы просто сторонник Linux вообще, вы можете построить&lt;br /&gt;
дистрибутив с акцентом на предоставляемые преимущества.&lt;br /&gt;
&lt;br /&gt;
=== Убеждены? ===&lt;br /&gt;
Мы начнем с рассмотрения того, как составные части дистрибутива объединяются в&lt;br /&gt;
единое целое, какие изменения вам следует&lt;br /&gt;
сделать, а затем тщательно рассмотрим все&lt;br /&gt;
это на примере Knoppix. Мы также взглянем&lt;br /&gt;
&lt;br /&gt;
{{break|45-46}}&lt;br /&gt;
&lt;br /&gt;
===Могу я изменить другой дистрибутив?===&lt;br /&gt;
[[изображение:LXF74-75-Otherdistro-1.jpg|thumb|Возьмите ISO-образ (1), смонтируйте его как loopback (2) и проверьте его содержимое (3).]]&lt;br /&gt;
Да! Практически любой дистрибутив можно изменить, &lt;br /&gt;
если вы знаете, как это сделать. Вы могли заметить, что &lt;br /&gt;
дистрибутивы, которые мы помещаем на нашем диске, &lt;br /&gt;
всегда слегка модифицируются: собственно дистрибутив &lt;br /&gt;
не подвергается изменениям, но мы изменяем структуру &lt;br /&gt;
каталогов, добавляя наши HTML-меню и дополнительные программы. Наиболее свежие дистрибутивы придерживаются разумного формата, так что изменять их не очень сложно.&lt;br /&gt;
&lt;br /&gt;
Ваш первый шаг – раздобыть ISO-образ диска (или &lt;br /&gt;
дисков) дистрибутива. К примеру, у вас есть образ &lt;br /&gt;
Ubuntu CD, либо загруженный, либо полученный с &lt;br /&gt;
реального диска следующей командой:&lt;br /&gt;
 dd if=/dev/cdrom of=discimage.iso&lt;br /&gt;
С помощью loopback-монтирования вы можете получить доступ к файлам на ISO-образе, как если бы он был настоящим CD, &lt;br /&gt;
вставленным в привод. Это достигается использованием &lt;br /&gt;
опции loop в команде монтирования:&lt;br /&gt;
 mount -o loop -t iso9660 discimage.iso /mnt/loop/&lt;br /&gt;
Теперь в /mnt/loop у вас будет содержимое диска, как будто вы просто записали образ на CD-R и подключили его, как обычно. &lt;br /&gt;
&lt;br /&gt;
Теперь вы можете скопировать целиком все содержимое &lt;br /&gt;
во временную папку, сделать все файлы доступными для записи:&lt;br /&gt;
 chmod -R +w *&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;
все обратно в образ диска с помощью mkisofs. Наиболее &lt;br /&gt;
важный момент, который следует рассмотреть – &lt;br /&gt;
изготовление диска, способного загружаться; &lt;br /&gt;
большинство дистрибутивов используют isolinux, так что &lt;br /&gt;
вам нужно использовать правильные опции:&lt;br /&gt;
 mkisofs -rdlJ -allow-leading-dots -hide-rr-moved -dir-mode 555 -p &amp;quot;preparer&amp;quot; -publisher &amp;quot;publisher&amp;quot; -A &amp;quot;Disc name&amp;quot; -V VOLNAME \&lt;br /&gt;
 -o output.iso -b isolinux/isolinux.bin -c isolinux/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table disc_contents/&lt;br /&gt;
В результате вы получите файл output.iso для записи &lt;br /&gt;
на диск, сгенерированный из файлов, содержащихся в &lt;br /&gt;
каталоге disc_contents. Для того чтобы диск был &lt;br /&gt;
загрузочным, имена файлов, следующих после опций -b &lt;br /&gt;
и -c, следует изменить в зависимости от того, какой &lt;br /&gt;
дистрибутив вы используете. Ознакомьтесь со страницей &lt;br /&gt;
справки для mkisofs (man mkisofs), чтобы получить &lt;br /&gt;
дополнительную информацию. Когда все будет сделано, &lt;br /&gt;
вы получите дистрибутив, подобный оригиналу, но с &lt;br /&gt;
вашими изменениями.&lt;br /&gt;
&lt;br /&gt;
== Соберите инструменты для вашего дистрибутива ==&lt;br /&gt;
[[изображение:LXF74-75-Knoppix-0.jpg|thumb|Рабочий стол Knoppix, используемый по умолчанию – если вам он не нравится, вы можете его изменить.]]&lt;br /&gt;
''Каждый хороший рабочий скажет вам, что самая важная часть любой работы — это подготовка. Заварите себе чашечку чая (с четырьмя ложками сахара), и приступим к работе! ''&lt;br /&gt;
&lt;br /&gt;
В этом руководстве мы сосредоточимся в&lt;br /&gt;
основном на Knoppix, поскольку это один из&lt;br /&gt;
лучших дистрибутивов для модификации.&lt;br /&gt;
Мы будем использовать его, чтобы создать&lt;br /&gt;
наш собственный LXF-дистрибутив, с&lt;br /&gt;
выбранными нами программами, собственным названием и другими специфическими&lt;br /&gt;
особенностями. Когда вы будете делать&lt;br /&gt;
свой, то обнаружите: раз это Live CD, можно&lt;br /&gt;
сразу же контролировать результат, и позже&lt;br /&gt;
вы всегда сумеете установить его на ваш&lt;br /&gt;
жесткий диск. Впрочем, большая часть этой&lt;br /&gt;
информации применима и к другим дистрибутивам, и мы дадим несколько советов,&lt;br /&gt;
полезных, даже если вы предпочтете пойти&lt;br /&gt;
другим путем.&lt;br /&gt;
&lt;br /&gt;
=== Как работает Knoppix? ===&lt;br /&gt;
{{Врезка&lt;br /&gt;
|Заголовок=Простая правка deb-пакетов&lt;br /&gt;
|Содержание=Knoppix и прочие основанные на Debian дистрибутивы используют в качестве пакетов ПО &lt;br /&gt;
файлы с расширением .deb. Как правило, они генерируются из исходного кода с помощью &lt;br /&gt;
сложного набора сценариев; тем не менее, вы можете быстро внести изменения в deb-файлы без &lt;br /&gt;
каких-либо проблем. Это позволяет вам редактировать содержимое (например, изменять &lt;br /&gt;
документацию или рисунки) в одно мгновение. Скажем, вы хотите изменить заставку для &lt;br /&gt;
программы FooBar на соответствующую вашей торговой марке. Запустите:&lt;br /&gt;
 ar x foobar_1.2.3_i386.deb&lt;br /&gt;
 tar xfvz data.tar.gz&lt;br /&gt;
Эти команды извлекут сжатое содержимое deb-пакета (data.tar.gz). В большинстве случаев оно &lt;br /&gt;
представляет собой знакомое дерево каталогов, содержащее /usr и, возможно, другие каталоги. &lt;br /&gt;
&lt;br /&gt;
Расположение файлов соответствует таковому в системе Debian. Войдите в полученные каталоги и &lt;br /&gt;
исправляйте их содержимое, редактируйте заставку в usr/share/foobar/splash.png, и так далее. &lt;br /&gt;
Когда закончите, выполните команды:&lt;br /&gt;
 tar cfvz data.tar.gz usr/&lt;br /&gt;
 ar r foobar_1.2.3_i386.deb data.tar.gz&lt;br /&gt;
Первая строка поместит все файлы данных пакета обратно в data.tar.gz – вам может &lt;br /&gt;
потребоваться указать, помимо /usr, и другие каталоги, если они имеются в распакованном вами &lt;br /&gt;
пакете. Вторая команда объединяет все обратно в deb-пакет, готовый для установки на ваш &lt;br /&gt;
собственный дистрибутив или для распространения.}}&lt;br /&gt;
&lt;br /&gt;
Knoppix представляет из себя Live CD: этот основанный на Debian дистрибутив запускается непосредственно в памяти компьютера.&lt;br /&gt;
На жестком диске не производится никаких&lt;br /&gt;
изменений, пока вы явно этого не потребуете. Knoppix версии 4.0 доступен также на&lt;br /&gt;
DVD — его вы могли видеть на диске, прилагавшемся к прошлому номера нашего&lt;br /&gt;
журнала.&lt;br /&gt;
&lt;br /&gt;
Последние улучшения Knoppix, такие&lt;br /&gt;
как способность сохранять персональные&lt;br /&gt;
файлы на USB-flash, переводят проект из&lt;br /&gt;
просто демонстрационного в полноценный&lt;br /&gt;
дистрибутив. Вот что приближает этот дистрибутив к графической настольной ОС:&lt;br /&gt;
* Загрузка&lt;br /&gt;
Knoppix запускается подобно любому другому дистрибутиву: появляется приглашение загрузчика, затем загружается ядро.&lt;br /&gt;
Вы можете передать некоторые опции в&lt;br /&gt;
приглашении загрузчика, чтобы выбрать&lt;br /&gt;
различные видеорежимы или оконные&lt;br /&gt;
менеджеры.&lt;br /&gt;
&lt;br /&gt;
Как только ядро получит управление,&lt;br /&gt;
начинают работать сценарии инициализации, и только здесь вы впервые заметите&lt;br /&gt;
отличие Knoppix от своего обычного дистрибутива, установленного на жестком&lt;br /&gt;
диске.&lt;br /&gt;
* Файловая система&lt;br /&gt;
В отличие от нормального дистрибутива,&lt;br /&gt;
который монтирует вашу файловую систему и выполняет загрузку программ с нее,&lt;br /&gt;
Knoppix использует сжатый loopback-файл.&lt;br /&gt;
Это отдельный файл, который содержит&lt;br /&gt;
целую файловую систему, включая /, /usr,&lt;br /&gt;
/etc и все прочие каталоги, которые можно&lt;br /&gt;
найти в обычной файловой системе, и&lt;br /&gt;
который располагается на CD/DVD под&lt;br /&gt;
именем «KNOPPIX». Он монтируется через&lt;br /&gt;
так называемый cloop (compressed loop),&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;
же, несмотря на то, что именно вы выбрали: HTML-страница, загружаемая по умолчанию, и фоновый рисунок. Изменение&lt;br /&gt;
этих двух элементов — простой способ&lt;br /&gt;
придать вашему дистрибутиву черты&lt;br /&gt;
вашей торговой марки — и в нашем обзоре мы покажем вам, как это сделать.&lt;br /&gt;
&lt;br /&gt;
=== Что мы можем изменить ===&lt;br /&gt;
Технически, мы можем настроить под&lt;br /&gt;
свои требования любую часть Knoppix, но&lt;br /&gt;
в одних случаях это делается проще, чем&lt;br /&gt;
в других. Наиболее полезный параметр -&lt;br /&gt;
набор предоставляемого ПО — можно&lt;br /&gt;
настроить сразу же, и без всяких ночных&lt;br /&gt;
кошмаров: все благодаря превосходному&lt;br /&gt;
репозитарию Debian, на базе которого&lt;br /&gt;
построен Knoppix. Вы можете удалять&lt;br /&gt;
пакеты, добавлять новые, изменять существующие — либо используя полное&lt;br /&gt;
построение пакета (для этого потребуется&lt;br /&gt;
система Debian), либо с помощью более&lt;br /&gt;
быстрого метода, подробно описанного во&lt;br /&gt;
врезке «Простая правка deb-пакетов»&lt;br /&gt;
слева. Инструменты для работы с пакетами Debian, такие как apt-get и другие,&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;br /&gt;
сценарии и параметры конфигурации.&lt;br /&gt;
&lt;br /&gt;
=== Подготовка ===&lt;br /&gt;
Прежде чем мы приступим собственно к&lt;br /&gt;
разработке, вам нужно будет кое-что подготовить. Наиболее важный элемент -&lt;br /&gt;
диск Knoppix, образ которого вы можете&lt;br /&gt;
загрузить с сайта проекта (http://www.knopper.net/knoppix/index-en.html). Там вы сможете найти ISO-образ Knoppix 4.0, подготовленный для записи на CD-R. Как и с любым дистрибутивом, вы не можете&lt;br /&gt;
просто скопировать файл ISO на CD — вам нужно записать его именно как образ&lt;br /&gt;
диска. Ваша любимая программа для&lt;br /&gt;
записи CD должна иметь эту опцию, а&lt;br /&gt;
если ее нет, вы можете воспользоваться&lt;br /&gt;
проверенной утилитой командной строки&lt;br /&gt;
cdrecord. Обратитесь к странице справки&lt;br /&gt;
(man cdrecord) для получения детальных&lt;br /&gt;
сведений о записи CD-дисков.&lt;br /&gt;
&lt;br /&gt;
Далее, вы должны обратить внимание&lt;br /&gt;
на оперативную память вашего компьютера. Ее у вас должно быть как минимум&lt;br /&gt;
128 Мб, но даже в этом случае некоторые этапы процесса сборки будут идти медленно. Это, конечно же, не смертельно; вы&lt;br /&gt;
можете оставить работающую машину на&lt;br /&gt;
ночь, если потребуется, но чем больше&lt;br /&gt;
ОЗУ у вас есть, тем лучше. Процесс пересборки на самом деле требует 1 Гб памяти,&lt;br /&gt;
но вы можете достичь этого значения,&lt;br /&gt;
добавив виртуальной памяти (swap) к объему вашего ОЗУ. Следует также заметить,&lt;br /&gt;
что вы можете использовать и Knoppix DVD с нашего диска, но требования к&lt;br /&gt;
памяти для редактирования при этом достигнут 5 Гб — нереальное значение для&lt;br /&gt;
большинства из нас.&lt;br /&gt;
&lt;br /&gt;
Наконец, вам потребуется свободное&lt;br /&gt;
место на вашем Linux-разделе на жестком диске. Это может быть специально отформатированный раздел, либо один из тех,&lt;br /&gt;
которые вы уже используете, например, /&lt;br /&gt;
или /home. Для CD вам потребуется 3 Гб&lt;br /&gt;
свободного пространства, а для DVD -&lt;br /&gt;
колоссальный объем в 15 Гб. Итак, если у&lt;br /&gt;
вас есть компакт-диск, необходимый объем оперативной памяти и достаточно места&lt;br /&gt;
на вашем жестком диске — вы готовы к&lt;br /&gt;
дальнейшей работе. Начиная со следующей страницы, мы шаг за шагом погрузимся в процесс переделки, приводя точные&lt;br /&gt;
команды, которые должны будут вводиться, от начала и до конца. Говоря словами Марио — «let’s-a go!»&lt;br /&gt;
&lt;br /&gt;
== Семь шагов для переделки дистрибутива ==&lt;br /&gt;
''Начиная с этого момента, вы должны определиться, на кого будет рассчитан ваш дистрибутив, какое ПО вы хотите на нем разместить и как он должен выглядеть — далее мы поговорим о том, как все это сделать.''&lt;br /&gt;
&lt;br /&gt;
=== 1. Запустите Knoppix ===&lt;br /&gt;
[[изображение:LXF74-75-Knoppix-1.jpg|thumb|Если на вашем жестком диске нет свободного Linux-раздела, используйте cfdisk и mke2fs, чтобы создать его.]]&lt;br /&gt;
Вставьте ваш CD с Knoppix 4.0 в привод, перезагрузите компьютер и установите загрузку с CD. Как правило, для этого нужно нажать [F1], [F2] или [Del] в начале загрузки вашего ПК, затем изменить порядок загрузки в настройках BIOS. После загрузки вам&lt;br /&gt;
нужно будет войти в рабочее окружение KDE. Вы сможете выбрать другой рабочий стол&lt;br /&gt;
или оконный менеджер — это хорошая идея для машин с небольшим объемом оперативной памяти. Откройте окно терминала («K Menu &amp;gt; KNOPPIX &amp;gt; Root Shell»).&lt;br /&gt;
&lt;br /&gt;
Сперва вам нужно убедиться, что компьютер подключен к Интернету. Вы можете&lt;br /&gt;
настроить сеть, как с помощью традиционных инструментов командной строки, так и из&lt;br /&gt;
«K Menu &amp;gt; KNOPPIX &amp;gt; Network/Internet». Выполнив это, подключите раздел жесткого диска, который вы подготовили ранее, и убедитесь, что на нем есть 3 Гб свободного места, и создайте временный рабочий каталог на нем следующими командами:&lt;br /&gt;
 mkdir /mnt/drive&lt;br /&gt;
 mount -rw /dev/hda1 /mnt/drive&lt;br /&gt;
 mkdir /mnt/drive/knoppix-tmp&lt;br /&gt;
&lt;br /&gt;
Замечание: вам может потребоваться изменить hda1 во второй строке на hda2 или тот&lt;br /&gt;
номер, который соответствует подготовленному&lt;br /&gt;
вами разделу.&lt;br /&gt;
&lt;br /&gt;
Замечание 2: вы должны&lt;br /&gt;
смонтировать его в режиме чтения-записи (опция -rw). Также стоит ввести hdparam -d1 /dev/hda&lt;br /&gt;
для включения режима DMA и ускорения работы с диском.&lt;br /&gt;
&lt;br /&gt;
=== 2. Создайте swap и скопируйте файлы ===&lt;br /&gt;
[[изображение:LXF74-75-Knoppix-2.jpg|thumb|Вам может потребоваться добавить пространства под swap-файл, чтобы получить требуемый 1 Гб памяти.]]&lt;br /&gt;
Как уже упоминалось, вам потребуется 1 Гб памяти (реальной плюс виртуальной).&lt;br /&gt;
Если объем вашего ОЗУ меньше 1 Гб, создайте swap-файл, чтобы воспользоваться&lt;br /&gt;
виртуальной памятью. Следующие команды создадут swap-файл размером 750 Мб в&lt;br /&gt;
дополнение к вашим 256 Мб ОЗУ:&lt;br /&gt;
 cd /mnt/drive/knoppix-tmp&lt;br /&gt;
 dd if=/dev/zero of=swapfile bs=1M count=750&lt;br /&gt;
 mkswap swapfile&lt;br /&gt;
 swapon swapfile&lt;br /&gt;
Теперь создайте 2 каталога для исходных файлов Knoppix и вашего финального CD,&lt;br /&gt;
и в обоих создайте папку KNOPPIX. Скопируйте в них все файлы дистрибутива Knoppix,&lt;br /&gt;
готовя их к модификации (процесс копирования потребует некоторого времени):&lt;br /&gt;
 mkdir -p /mnt/drive/knoppix-tmp/master/KNOPPIX&lt;br /&gt;
 mkdir -p /mnt/drive/knoppix-tmp/source/KNOPPIX&lt;br /&gt;
 cd -Rp /KNOPPIX/* /mnt/drive/knoppix-tmp/source/KNOPPIX&lt;br /&gt;
 cd -ap /cdrom/boot /mnt/drive/knoppix-tmp/master/boot&lt;br /&gt;
 cp /cdrom/imdex.html /mnt/drive/knoppix-tmp/master/&lt;br /&gt;
 cd /cdrom &amp;amp;&amp;amp; find . -size -10000k -type f -exec cp -p --parents '{}' /mnt/drive/knoppixtmp/master/ \;&lt;br /&gt;
Обратите внимание на последнюю строку: для DVDверсии вам следует использовать размер 15000k и копировать каталог KNOPPIX2 с помощью команды&lt;br /&gt;
 cp /cdrom/KNOPPIX KNOPPIX2 /mnt/drive/knoppix-tmp/master/KNOPPIX&lt;br /&gt;
&lt;br /&gt;
=== 3. Откройте сессию chroot ===&lt;br /&gt;
[[изображение:LXF74-75-Knoppix-3.jpg|thumb|Теперь мы в chroot-каталоге, который выглядит и ведет себя как отдельный дистрибутив Linux.]]&lt;br /&gt;
Итак, вы скопировали ПО, входящее в состав Knoppix, в source/KNOPPIX, и дополнительно вспомогательные файлы для изготовления дистрибутива в master/. А теперь&lt;br /&gt;
начнется веселье! Используя программу chroot, вы можете создать сессию внутри копии&lt;br /&gt;
Knoppix — другими словами, начать использовать ее, как отдельный дистрибутив.&lt;br /&gt;
«Chroot» означает «change root» (сменить корень), и устанавливает ваш корневой каталог / туда, куда вы укажете. Итак, поменяем корневой каталог на тот, где хранится наша&lt;br /&gt;
копия Knoppix, что позволит нам использовать и модифицировать ее, как будто мы ее&lt;br /&gt;
уже запустили:&lt;br /&gt;
 chroot /mnt/drive/knoppix-tmp/source/KNOPPIX&lt;br /&gt;
Теперь любые изменения будут отражаться на создаваемом дистрибутиве. То, что&lt;br /&gt;
вы увидите в каталоге /, находясь в chroot, на самом деле будет /mnt/drive/knoppix-tmpsource/KNOPPIX. Если вы хотите добавить ПО из репозитария Debian, вам потребуется&lt;br /&gt;
настроить сеть:&lt;br /&gt;
 mount -t proc /proc proc&lt;br /&gt;
Затем откройте второе окно терминала, чтобы вы временно оказались вне chroot-окружения, и введите приведенную ниже команду (это нельзя сделать из&lt;br /&gt;
chroot-окружения):&lt;br /&gt;
 cp /etc/dhcpc/resolv.conf /mnt/drive/knoppix-tmp/source/KNOPPIX/etc/dhcpc/resolv.conf&lt;br /&gt;
&lt;br /&gt;
=== 4. Выберите ваше новое ПО ===&lt;br /&gt;
Теперь можно добавлять и удалять софт, используя отличный инструмент Debian -&lt;br /&gt;
apt-get. Прежде всего, введите apt-get update (НЕ upgrade!), чтобы обновить список&lt;br /&gt;
пакетов. Затем наберите dpkg-query -l — получите список установленных пакетов.&lt;br /&gt;
Для удобства можно перенаправить вывод на программу постраничного просмотра:&lt;br /&gt;
dpkg-query -l | less. Чтобы удалить пакет, введите apt-get remove -purge &amp;lt;имя_&lt;br /&gt;
пакета&amp;gt;. Чтобы установить новый пакет из Интернета, наберите apt-get install&lt;br /&gt;
&amp;lt;имя_программы&amp;gt;. Репозитарий программного обеспечения Debian просто огромен: вы сможете переделать ваш дистрибутив, как только пожелаете. Например, чтобы удалить редактор Zile и установить Nano, мы выполним следующие команды:&lt;br /&gt;
 apt-get remove --purge zile&lt;br /&gt;
 apt-get install nano&lt;br /&gt;
Как только вы закончите, введите apt-get clean, чтобы удалить загруженные&lt;br /&gt;
файлы, оставшиеся в кэше.&lt;br /&gt;
&lt;br /&gt;
Замечание: есть пакеты, которые вы не можете удалить, например, ядро, libc и&lt;br /&gt;
сценарии инициализации. Если вы сомневаетесь, можно ли что-то удалять, оставьте&lt;br /&gt;
все, как есть. Если же пакет слишком велик, и вам хочется сэкономить место, зайдите&lt;br /&gt;
на Linux-форум и спросите, насколько он важен для работы системы.&lt;br /&gt;
&lt;br /&gt;
=== 5. Измените поведение ===&lt;br /&gt;
[[изображение:LXF74-75-Knoppix-4.jpg|thumb|Сделать более замысловатый фоновый рисунок совсем не сложно…]]&lt;br /&gt;
Покончив с сортировкой программ, самое время покопаться в системе и изменить&lt;br /&gt;
другие параметры. В /etc/skel вы сможете найти файлы конфигурации, используемые по умолчанию для новых пользователей (введите ls -a, чтобы увидеть их все).&lt;br /&gt;
&lt;br /&gt;
В /etc/init.d вы найдете стартовые сценарии для программ, которые могут быть&lt;br /&gt;
запущены на этапе загрузки системы. Вы можете добавить другие сценарии в /etc/&lt;br /&gt;
rc5.d, чтобы загружать программы до того как будет запущена графическая оболочка. И, конечно же, сам /etc — это место расположения всевозможных конфигурационных файлов, которые вы можете настроить по своему усмотрению — однако, если&lt;br /&gt;
сомневаетесь, лучше не изменяйте их. Поскольку вы находитесь в chroot-окружении,&lt;br /&gt;
вы можете тестировать ваши графические приложения, введя export&lt;br /&gt;
DISPLAY=localhost:0 и уже потом запустив саму программу. Это позволит вашей&lt;br /&gt;
программе подсоединиться и использовать уже существующий экран, вместо того&lt;br /&gt;
чтобы пытаться найти запущенный X-сервер в chroot-окружении. Некоторые изменения производятся за пределами chroot; например, мы можем придать фоновому&lt;br /&gt;
рисунку, используемому по умолчанию, собственные оттенки. Откройте отдельную&lt;br /&gt;
оболочку с правами root, и введите:&lt;br /&gt;
 chmod +w /mnt/drive/knoppix-tmp/master/KNOPPIX/background.jpg&lt;br /&gt;
 gimp /mnt/drive/knoppix-tmp/master/KNOPPIX/background.jpg&lt;br /&gt;
&lt;br /&gt;
Теперь вы можете отредактировать фоновое изображение, добавив ваш логотип&lt;br /&gt;
или элементы оформления. Конечно, вы можете полностью заменить этот файл.&lt;br /&gt;
Экран загрузчика (splash screen) размещается в /mnt/drive/knoppix-tmp/master/&lt;br /&gt;
boot/isolinux/logo.16 — вам потребуется пакет Syslinux, чтобы отредактировать его.&lt;br /&gt;
В отдельной оболочке измените формат, отредактируйте изображение и переконвертируйте в прежний формат:&lt;br /&gt;
 cd /mnt/drive/knoppix-tmp/knoppix-tmp/master/boot/isolinux; chmod +w logo.16&lt;br /&gt;
 lss16toppm &amp;lt; logo.16 &amp;gt; logo.ppm&lt;br /&gt;
 gimp logo.ppm (сохраните как indexed GIF с 14 цветами)&lt;br /&gt;
 giftoppm &amp;lt; logo.gif &amp;gt; logo.ppm&lt;br /&gt;
 ppmtolss16 &amp;lt; logo.ppm &amp;gt; logo.16&lt;br /&gt;
Наконец, вы можете изменить&lt;br /&gt;
файл помощи, который выводится,&lt;br /&gt;
когда запускается какой-либо оконный менеджер (например, KDE,&lt;br /&gt;
используемый по умолчанию). Его&lt;br /&gt;
можно найти в файле /mnt/drive/knoppix-tmp/master/index.html.&lt;br /&gt;
&lt;br /&gt;
=== 6. Пересоздайте сжатый образ ===&lt;br /&gt;
[[изображение:LXF74-75-Knoppix-5.jpg|thumb|mkisofs обеспечивает отличную обратную связь, так что обнаружить любую проблему достаточно легко.]]&lt;br /&gt;
Когда вы внесете все желаемые изменения, выйдите из chroot, введя umount /proc и&lt;br /&gt;
нажав [Ctrl]+[D]. Chroot-сессия будет завершена. Осмотрите каталоги, в которых вы&lt;br /&gt;
работали, чтобы удалить временные файлы. Теперь перейдем к предпоследнему из&lt;br /&gt;
важных шагов — созданию сжатого образа файловой системы. На странице 46 мы&lt;br /&gt;
видели, что Live CD использует сжатый файл, представляющий собой файловую систему с сохраненным ПО, так что нам нужно создать его заново:&lt;br /&gt;
 mkisofs -R -U -V &amp;quot;filesystem&amp;quot; -publisher &amp;quot;MyName www.myurl.com&amp;quot; -hide-rr-moved cache-inodes -no-bak \&lt;br /&gt;
 /mnt/drive/knoppix-tmp/source/KNOPPIX | /usr/bin/create_compressed_fs - 65536 &amp;gt; /mnt/drive/knoppix-tmp/master/KNOPPIX/KNOPPIX&lt;br /&gt;
На этом этапе вы можете изменить имя издателя и адрес сайта (опция publisher),&lt;br /&gt;
но в остальном эта команда&lt;br /&gt;
должна быть набрана с точностью до буквы. В зависимости&lt;br /&gt;
от скорости вашего компьютера, ей потребуется некоторое&lt;br /&gt;
время, чтобы завершить работу.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 7. Постройте финальный ISO-образ ===&lt;br /&gt;
[[изображение:LXF74-75-Knoppix-6.jpg|thumb|Итоговый результат: LFX-дистрибутив с милым пингвином.]]&lt;br /&gt;
Настает важный момент: создание финального образа диска. Мы создадим ISO-образ&lt;br /&gt;
собранного нами Knoppix, готового для использования или распространения. Прежде&lt;br /&gt;
всего, нужно будет вычислить MD5-сумму для диска, которая очень важна для проверки&lt;br /&gt;
целостности (она позволяет убедиться, что вы раздаете неиспорченные диски).&lt;br /&gt;
 cd /mnt/drive/knoppix-tmp/master&lt;br /&gt;
 find -type f -not-name md5sums -not-name boot.cat -not-name isolinux.bin -exec &lt;br /&gt;
 md5sum '{}' \; &amp;gt; KNOPPIX/md5sums&lt;br /&gt;
Далее следует еще одна большая команда, самая последняя команда, так что не&lt;br /&gt;
пугайтесь. Эта команда создает собственно файл ISO. Когда она завершится, файл&lt;br /&gt;
будет готов для записи на диск. Она использует инструмент mkisofs, чтобы взять наши&lt;br /&gt;
только что измененные файлы Knoppix, объединить их с загрузочными данными и&lt;br /&gt;
получить образ диска.&lt;br /&gt;
 cd /mnt/drive/knoppix-tmp/master&lt;br /&gt;
 mkisofs -pad -l -r -J -v -V “MYDISTRO” -no-emul-boot -boot-load-size 4 -boot-info-table b boot/isolinux/isolinux.bin \&lt;br /&gt;
 -c boot/isolinux/boot.cat -hide-rr-moved -o /mnt/drive/knoppix-tmp/mydistro.iso /mnt/drive/knoppix-tmp/master&lt;br /&gt;
Когда работа завершится, вы получите сияющий новизной ISO-образ вашего дистрибутива в /mnt/drive/knoppix-tmp/mydistro.iso. Вы можете протестировать его,&lt;br /&gt;
записав на CD-R в вашем обычном дистрибутиве, или воспользовавшись быстрым&lt;br /&gt;
запуском в эмуляторе, например,&lt;br /&gt;
VMWare или Qemu.&lt;br /&gt;
&lt;br /&gt;
Если все работает правильно, вы можете теперь выложить куда-нибудь ваш ISO-образ, и поделиться результатами вашей тяжелой работы.&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;
какие проводит Debian — в конце концов,&lt;br /&gt;
вы используете в качестве основы уже&lt;br /&gt;
хорошо зарекомендовавший себя дистрибутив. Тем не менее, стоит проверить, что&lt;br /&gt;
все основные программы, которые вы устанавливали, работают правильно, и что&lt;br /&gt;
любые изменения, которые вы выполняли&lt;br /&gt;
в низкоуровневых компонентах (таких как&lt;br /&gt;
сценарии инициализации), не повлекли за&lt;br /&gt;
собой каких-либо проблем. Если вы выпускаете CD «для всех», например, для продвижения Linux, вы вряд ли хотите стать в&lt;br /&gt;
итоге командой технической поддержки,&lt;br /&gt;
работающей в режиме «24х7»?&lt;br /&gt;
&lt;br /&gt;
Что делать, если что-то не работает? К&lt;br /&gt;
счастью, вам не нужно повторять всю процедуру еще раз. Если вы еще не удалили&lt;br /&gt;
рабочие файлы с вашего жесткого диска,&lt;br /&gt;
вы можете запустить Knoppix, подключить&lt;br /&gt;
диск (шаг 1), добавить swap-файл (шаг 2)&lt;br /&gt;
и войти в chroot (шаг 3). После устранения&lt;br /&gt;
проблемы вы можете пересобрать ISOобраз, как показано в шагах 6 и 7, скрестив&lt;br /&gt;
пальцы. Если у вас возникла проблема,&lt;br /&gt;
специфическая для Knoppix, есть замечательный форум, который может помочь&lt;br /&gt;
вам при переделке Knoppix, находящийся&lt;br /&gt;
по адресу: http://www.knoppix.net/forum/viewforum.php?f=2. Объясните, что вы&lt;br /&gt;
пытаетесь сделать и что не получается, и&lt;br /&gt;
кто-нибудь вам поможет.&lt;br /&gt;
&lt;br /&gt;
Надеемся, что теперь вы сформировали свой собственный дистрибутив, и попутно получили некоторые полезные знания в&lt;br /&gt;
области Linux. Тем не менее, есть много&lt;br /&gt;
путей для дальнейшего движения — вы&lt;br /&gt;
можете попробовать Linux From Scratch&lt;br /&gt;
(смотрите справа врезку «Утоление жажды&lt;br /&gt;
творчества») или присоединитесь к другому проекту разработки дистрибутива.&lt;br /&gt;
Учитывая организацию и политику Debian&lt;br /&gt;
или, скажем, Fedora, довольно сложно сделать большие изменения в этих дистрибутивах, но меньшие проекты более приспособлены для этого и готовы к испытанию&lt;br /&gt;
новых идей. Посетите сайт Ладислава&lt;br /&gt;
Боднара (Ladislav Bodnar) — http://www.distrowatch.com - чтобы узнать, какой&lt;br /&gt;
из дистрибутивов Linux находится на вершине популярности.&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;
== Альтернатива: Morphix ==&lt;br /&gt;
;Построение дистрибутивов, основанное на графическом интерфейсе&lt;br /&gt;
&lt;br /&gt;
[[изображение:LXF74-75-Morphix-1.jpg|thumb|IBuild может работать и с Knoppix, хотя Morphix предпочтительнее.]]&lt;br /&gt;
Morphix — это Live CD, основанный на Knoppix (то есть,&lt;br /&gt;
фактически, на Debian), который щеголяет довольно элегантной системой построения дистрибутива с использованием графического интерфейса. Все еще требуется&lt;br /&gt;
кое-что делать из командной строки, но большинство&lt;br /&gt;
операций по настройке можно выполнять в графическом&lt;br /&gt;
интерфейсе. Эта программа называется IntelliBuild, и&lt;br /&gt;
доступна по адресу http://ibuild.livecd.net. Мы включили основные файлы Morphix в наш диск, чтобы сэкономить время и трафик, которые вы потратили бы на загрузку.&lt;br /&gt;
&lt;br /&gt;
IBuild использует шаблоны, которые позволяют вам&lt;br /&gt;
выбирать пакеты из репозитариев Debian, и изменять&lt;br /&gt;
другие элементы дистрибутива, такие как экран заставки&lt;br /&gt;
и стартовые сценарии. Чтобы запустить его, вам нужно&lt;br /&gt;
иметь последние версии chroot, cloop-utils, Python,&lt;br /&gt;
PyGTK, python-vte и mkisofs. Как и в случае с Knoppix,&lt;br /&gt;
вам потребуется 3 Гб свободного места на диске и 1 Гб&lt;br /&gt;
оперативной памяти (включая объем swap-файла).&lt;br /&gt;
Сначала смонтируйте прилагаемый диск и из-под пользователя root выполните следующие команды:&lt;br /&gt;
 cd ~; mkdir ibuild; cd ibuild&lt;br /&gt;
 mkdir -p prebuilt/mainmod; cd prebuilt/mainmod&lt;br /&gt;
 cp /mnt/cdrom/Magazine/BuildDistro/BareX.mod.iso.bz2 .&lt;br /&gt;
 bunzip2 BareX.mod.iso.bz2&lt;br /&gt;
Теперь вам нужно создать кое-какие рабочие каталоги и&lt;br /&gt;
скопировать в них файлы с образа Mophix Base. Как обычно, замените /mnt/cdrom правильным местоположением&lt;br /&gt;
вашего CD/DVD-диска (в некоторых дистрибутивах это&lt;br /&gt;
может быть /cdrom):&lt;br /&gt;
 mkdir -p ~/ibuild/prebuilt/base/temp&lt;br /&gt;
 mkdir -p ~/ibuild/prebuilt/base/0.5-pre5&lt;br /&gt;
 cd ~/ibuild/prebuilt/base&lt;br /&gt;
 mount -o loop /mnt/cdrom/Magazine/BuildDistro/MorphixBase-0.5-pre.iso temp&lt;br /&gt;
 cp -a temp/* 0.5-pre5/&lt;br /&gt;
 umount /temp&lt;br /&gt;
Установите пакет IBuild, либо собрав из&lt;br /&gt;
исходных кодов, либо инсталлировав&lt;br /&gt;
deb-пакет (если вы получите сообщения&lt;br /&gt;
об ошибке, вам может потребоваться скопировать файлы из src/iGui/ в /usr/lib/ibuild или в другое место, куда вы выполняете установку).&lt;br /&gt;
&lt;br /&gt;
Теперь, когда основные файлы Morphix&lt;br /&gt;
на месте и IBuild установлен, вы можете&lt;br /&gt;
запустить ibuild.py приступить к работе.&lt;br /&gt;
Здесь вы найдете шаблоны, которые&lt;br /&gt;
можете изменить под свои требования,&lt;br /&gt;
такие как fireflux.xml в /usr/share/ibuild/config (или в /usr/local/share/ibuild/config). Они предопределяют набор пакетов и косметические особенности.&lt;br /&gt;
Когда вы будете готовы, нажмите кнопку Build, которая&lt;br /&gt;
должна быть в нижнем правом углу. Вы найдете полученный ISO-образ в каталоге ~ /ibuild/release/. За&lt;br /&gt;
дополнительной информацией обращайтесь по адресу http://wiki.livecd.net/livecd/ibuildHowto&lt;br /&gt;
&lt;br /&gt;
== Утоление жажды творчества ==&lt;br /&gt;
[[изображение:LXF74-75-LFS-1.jpg|thumb|LFS понятно изложен, информативен и хорошо написан — превосходное средство.]]&lt;br /&gt;
Хотя Knoppix и предоставляет простой и легкий путь для&lt;br /&gt;
переделки дистрибутива, существует масса других&lt;br /&gt;
возможностей, если вам хочется копнуть поглубже. Одна&lt;br /&gt;
из них — Linux From Scratch (LFS), своеобразный метадистрибутив — это не установочная система Linux, а&lt;br /&gt;
рабочая среда и руководство, предназначенные для&lt;br /&gt;
создания своей собственной системы. Она предоставляет&lt;br /&gt;
огромное пространство для модификаций и переделок,&lt;br /&gt;
но ценой бОльших затрат времени и усилий. И все же,&lt;br /&gt;
делая все с самого начала, вы досконально изучите&lt;br /&gt;
работу Linux и это даст вам возможность еще более&lt;br /&gt;
глубоких изменений. Многие из нынешних&lt;br /&gt;
разработчиков Linux-дистрибутивов начинали с LFS, что&lt;br /&gt;
вызывало у них интерес и желание присоединиться к&lt;br /&gt;
какому-либо проекту.&lt;br /&gt;
&lt;br /&gt;
LFS поставляется как набор архивов с исходными&lt;br /&gt;
кодами, дополненный исчерпывающим онлайн-руководством. Вы начинаете с создания голого скелета&lt;br /&gt;
дистрибутива Linux из вашего текущего, добавляя один&lt;br /&gt;
за другим необходимые компоненты, позволяющие ему&lt;br /&gt;
запускаться и работать (то есть полный инструментарий&lt;br /&gt;
разработчика). Аккуратно поделенное на секции&lt;br /&gt;
руководство объясняет вам, как компилировать каждую&lt;br /&gt;
программу, и предоставляет множество возможностей&lt;br /&gt;
для внесения собственных настроек. Также имеется BLFS&lt;br /&gt;
(Beyond Linux From Scratch), который освещает более&lt;br /&gt;
продвинутые темы, такие как компиляция огромного&lt;br /&gt;
рабочего стола Gnome. Узнать больше об LFS вы можете,&lt;br /&gt;
посетив сайт http://www.linuxfromscratch.org&lt;br /&gt;
&lt;br /&gt;
== Пять «популярных» ошибок ==&lt;br /&gt;
''Остерегайтесь их, когда создаете дистрибутив…''&lt;br /&gt;
# Плохое название. Хотя «Joe’s Hyper Plasma Spatula Orgasmix LiGNUx 0.54C3a1» может звучать достаточно круто, это практически не произносимо. Используйте что-нибудь краткое и запоминающееся, такое как «Plasma Linux 1.0»&lt;br /&gt;
# Запутанный набор приложений. Вместо того чтобы завалить пользователя уймой текстовых редакторов, попробуйте выбрать один хороший пример из всех программ. Другими словами, Nano.&lt;br /&gt;
# Противоречивость. Если возможно, привяжите все к одному инструментарию, скажем, GTK или Qt. При одновременном использовании нескольких инструментариев у вас будет не рабочий стол, а бардак.&lt;br /&gt;
# Безвкусица. Бесконечно яркие цвета могут быть хороши в цирке, но не на рабочем столе пользователя. Выбирайте приятную для глаз тему рабочего стола, а не вызывающий головную боль аналог шапито.&lt;br /&gt;
# Недостаточная ширина канала. Найдите хороший хостинг, или присоединитесь к BitTorrent. Ничто не обижает заинтересованного потенциального пользователя больше, чем необходимость тратить жизнь на скачивание со скоростью 5 килобит в секунду.&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF74-75:%D0%94%D0%B8%D1%81%D1%82%D1%80%D0%B8%D0%B1%D1%83%D1%82%D0%B8%D0%B2_%D1%81%D0%B2%D0%BE%D0%B8%D0%BC%D0%B8_%D1%80%D1%83%D0%BA%D0%B0%D0%BC%D0%B8</id>
		<title>LXF74-75:Дистрибутив своими руками</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF74-75:%D0%94%D0%B8%D1%81%D1%82%D1%80%D0%B8%D0%B1%D1%83%D1%82%D0%B8%D0%B2_%D1%81%D0%B2%D0%BE%D0%B8%D0%BC%D0%B8_%D1%80%D1%83%D0%BA%D0%B0%D0%BC%D0%B8"/>
				<updated>2008-07-11T14:59:39Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: Новая: {{TOCright}} == Соберите свой собственный дистрибутив == {{Врезка|Ширина=300px |Заголовок=Дистрибутив вашей меч...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{TOCright}}&lt;br /&gt;
== Соберите свой собственный дистрибутив ==&lt;br /&gt;
{{Врезка|Ширина=300px&lt;br /&gt;
|Заголовок=Дистрибутив вашей мечты&lt;br /&gt;
|Содержание=Как мы сейчас увидим, не так уж и сложно изменить набор программ, включенных в дистрибутив, и &lt;br /&gt;
его внешний вид. Но что можно сделать? Вот несколько идей, чтобы включить ваше воображение:&lt;br /&gt;
* Музыкальная студия. Дистрибутив, ориентированный на создание и редактирование &lt;br /&gt;
музыкальных файлов. В этом случае основные изменения будут касаться выбора ПО, в частности, &lt;br /&gt;
можно удалить офисные пакеты и добавить Audacity, Freecycle и другие.&lt;br /&gt;
* Реклама. Дистрибутив, разработанный для распространения информации о вашей компании или &lt;br /&gt;
проекте. Вы можете оставить набор программ без изменения, но придать глянец вашему &lt;br /&gt;
дистрибутиву, разместив свои логотипы, изображения и фон.&lt;br /&gt;
* Минимализм. Вместо того чтобы использовать тяжеловесные пакеты наподобие KDE и &lt;br /&gt;
OpenOffice.org, вы можете остановиться на «тонких» альтернативах, таких как IceWM и Siag. Вы &lt;br /&gt;
можете создать предельно минималистский дистрибутив для использования на слабых машинах.&lt;br /&gt;
}}&lt;br /&gt;
''Создать собственный дистрибутив Linux проще, чем вы могли бы подумать, к тому же еще и&lt;br /&gt;
интересно! Майк Сондерс (Mike Saunders) надевает свой комбинезон и каску, готовый показать вам, как это делается…''&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;
создание своего собственного дистрибутива Linux, довольно трудоемкое, как может&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;
Knoppix Live CD. Мы также получим множество других инструкций и подсказок, как&lt;br /&gt;
придать собственный оттенок любому Linux,&lt;br /&gt;
какому пожелаем.&lt;br /&gt;
&lt;br /&gt;
Учитывая огромное количество имеющихся дистрибутивов, вы можете удивиться: «что за нужда создавать еще один?».&lt;br /&gt;
* Выбор. Возможно, ни один из существующих дистрибутивов не удовлетворяет&lt;br /&gt;
полностью вашим потребностям. Вам нравится, например, Knoppix, но хочется удалить раздутую программу А, и заменить ее&lt;br /&gt;
легковесной программой Б, а также использовать в качестве фона изображение симпатичного пингвина. Вы можете создать дистрибутив из чего угодно, и где угодно.&lt;br /&gt;
* Изучение на практике. Понимание&lt;br /&gt;
того, как программы объединяются в дистрибутивы, что поставщики делают, чтобы&lt;br /&gt;
придать своим дистрибутивам индивидуальность и какие препятствия поджидают&lt;br /&gt;
на этом пути — ценные знания, особенно&lt;br /&gt;
если вы планируете когда-либо участвовать в проекте разработки дистрибутива.&lt;br /&gt;
* Пропаганда. Если вы продвигаете проект программного обеспечения, ориентированного на Linux, и хотели бы продемонстрировать его пользователям Windows, идеальным решением будет создание тематического Live CD, содержащего ваше приложение. Аналогично, если вы просто сторонник Linux вообще, вы можете построить&lt;br /&gt;
дистрибутив с акцентом на предоставляемые преимущества.&lt;br /&gt;
&lt;br /&gt;
=== Убеждены? ===&lt;br /&gt;
Мы начнем с рассмотрения того, как составные части дистрибутива объединяются в&lt;br /&gt;
единое целое, какие изменения вам следует&lt;br /&gt;
сделать, а затем тщательно рассмотрим все&lt;br /&gt;
это на примере Knoppix. Мы также взглянем&lt;br /&gt;
&lt;br /&gt;
{{break|45-46}}&lt;br /&gt;
&lt;br /&gt;
===Могу я изменить другой дистрибутив?===&lt;br /&gt;
[[изображение:LXF74-75-Otherdistro-1.jpg|thumb|Возьмите ISO-образ (1), смонтируйте его как loopback (2) и проверьте его содержимое (3).]]&lt;br /&gt;
Да! Практически любой дистрибутив можно изменить, &lt;br /&gt;
если вы знаете, как это сделать. Вы могли заметить, что &lt;br /&gt;
дистрибутивы, которые мы помещаем на нашем диске, &lt;br /&gt;
всегда слегка модифицируются: собственно дистрибутив &lt;br /&gt;
не подвергается изменениям, но мы изменяем структуру &lt;br /&gt;
каталогов, добавляя наши HTML-меню и дополнительные программы. Наиболее свежие дистрибутивы придерживаются разумного формата, так что изменять их не очень сложно.&lt;br /&gt;
&lt;br /&gt;
Ваш первый шаг – раздобыть ISO-образ диска (или &lt;br /&gt;
дисков) дистрибутива. К примеру, у вас есть образ &lt;br /&gt;
Ubuntu CD, либо загруженный, либо полученный с &lt;br /&gt;
реального диска следующей командой:&lt;br /&gt;
 dd if=/dev/cdrom of=discimage.iso&lt;br /&gt;
С помощью loopback-монтирования вы можете получить доступ к файлам на ISO-образе, как если бы он был настоящим CD, &lt;br /&gt;
вставленным в привод. Это достигается использованием &lt;br /&gt;
опции loop в команде монтирования:&lt;br /&gt;
 mount -o loop -t iso9660 discimage.iso /mnt/loop/&lt;br /&gt;
Теперь в /mnt/loop у вас будет содержимое диска, как будто вы просто записали образ на CD-R и подключили его, как обычно. &lt;br /&gt;
&lt;br /&gt;
Теперь вы можете скопировать целиком все содержимое &lt;br /&gt;
во временную папку, сделать все файлы доступными для записи:&lt;br /&gt;
 chmod -R +w *&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;
все обратно в образ диска с помощью mkisofs. Наиболее &lt;br /&gt;
важный момент, который следует рассмотреть – &lt;br /&gt;
изготовление диска, способного загружаться; &lt;br /&gt;
большинство дистрибутивов используют isolinux, так что &lt;br /&gt;
вам нужно использовать правильные опции:&lt;br /&gt;
 mkisofs -rdlJ -allow-leading-dots -hide-rr-moved -dir-mode 555 -p &amp;quot;preparer&amp;quot; -publisher &amp;quot;publisher&amp;quot; -A &amp;quot;Disc name&amp;quot; -V VOLNAME \&lt;br /&gt;
 -o output.iso -b isolinux/isolinux.bin -c isolinux/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table disc_contents/&lt;br /&gt;
В результате вы получите файл output.iso для записи &lt;br /&gt;
на диск, сгенерированный из файлов, содержащихся в &lt;br /&gt;
каталоге disc_contents. Для того чтобы диск был &lt;br /&gt;
загрузочным, имена файлов, следующих после опций -b &lt;br /&gt;
и -c, следует изменить в зависимости от того, какой &lt;br /&gt;
дистрибутив вы используете. Ознакомьтесь со страницей &lt;br /&gt;
справки для mkisofs (man mkisofs), чтобы получить &lt;br /&gt;
дополнительную информацию. Когда все будет сделано, &lt;br /&gt;
вы получите дистрибутив, подобный оригиналу, но с &lt;br /&gt;
вашими изменениями.&lt;br /&gt;
&lt;br /&gt;
== Соберите инструменты для вашего дистрибутива ==&lt;br /&gt;
[[изображение:LXF74-75-Knoppix-0.jpg|thumb|Рабочий стол Knoppix, используемый по умолчанию – если вам он не нравится, вы можете его изменить.]]&lt;br /&gt;
''Каждый хороший рабочий скажет вам, что самая важная часть любой работы — это подготовка. Заварите себе чашечку чая (с четырьмя ложками сахара), и приступим к работе! ''&lt;br /&gt;
&lt;br /&gt;
В этом руководстве мы сосредоточимся в&lt;br /&gt;
основном на Knoppix, поскольку это один из&lt;br /&gt;
лучших дистрибутивов для модификации.&lt;br /&gt;
Мы будем использовать его, чтобы создать&lt;br /&gt;
наш собственный LXF-дистрибутив, с&lt;br /&gt;
выбранными нами программами, собственным названием и другими специфическими&lt;br /&gt;
особенностями. Когда вы будете делать&lt;br /&gt;
свой, то обнаружите: раз это Live CD, можно&lt;br /&gt;
сразу же контролировать результат, и позже&lt;br /&gt;
вы всегда сумеете установить его на ваш&lt;br /&gt;
жесткий диск. Впрочем, большая часть этой&lt;br /&gt;
информации применима и к другим дистрибутивам, и мы дадим несколько советов,&lt;br /&gt;
полезных, даже если вы предпочтете пойти&lt;br /&gt;
другим путем.&lt;br /&gt;
&lt;br /&gt;
=== Как работает Knoppix? ===&lt;br /&gt;
{{Врезка&lt;br /&gt;
|Заголовок=Простая правка deb-пакетов&lt;br /&gt;
|Содержание=Knoppix и прочие основанные на Debian дистрибутивы используют в качестве пакетов ПО &lt;br /&gt;
файлы с расширением .deb. Как правило, они генерируются из исходного кода с помощью &lt;br /&gt;
сложного набора сценариев; тем не менее, вы можете быстро внести изменения в deb-файлы без &lt;br /&gt;
каких-либо проблем. Это позволяет вам редактировать содержимое (например, изменять &lt;br /&gt;
документацию или рисунки) в одно мгновение. Скажем, вы хотите изменить заставку для &lt;br /&gt;
программы FooBar на соответствующую вашей торговой марке. Запустите:&lt;br /&gt;
 ar x foobar_1.2.3_i386.deb&lt;br /&gt;
 tar xfvz data.tar.gz&lt;br /&gt;
Эти команды извлекут сжатое содержимое deb-пакета (data.tar.gz). В большинстве случаев оно &lt;br /&gt;
представляет собой знакомое дерево каталогов, содержащее /usr и, возможно, другие каталоги. &lt;br /&gt;
&lt;br /&gt;
Расположение файлов соответствует таковому в системе Debian. Войдите в полученные каталоги и &lt;br /&gt;
исправляйте их содержимое, редактируйте заставку в usr/share/foobar/splash.png, и так далее. &lt;br /&gt;
Когда закончите, выполните команды:&lt;br /&gt;
 tar cfvz data.tar.gz usr/&lt;br /&gt;
 ar r foobar_1.2.3_i386.deb data.tar.gz&lt;br /&gt;
Первая строка поместит все файлы данных пакета обратно в data.tar.gz – вам может &lt;br /&gt;
потребоваться указать, помимо /usr, и другие каталоги, если они имеются в распакованном вами &lt;br /&gt;
пакете. Вторая команда объединяет все обратно в deb-пакет, готовый для установки на ваш &lt;br /&gt;
собственный дистрибутив или для распространения.}}&lt;br /&gt;
&lt;br /&gt;
Knoppix представляет из себя Live CD: этот основанный на Debian дистрибутив запускается непосредственно в памяти компьютера.&lt;br /&gt;
На жестком диске не производится никаких&lt;br /&gt;
изменений, пока вы явно этого не потребуете. Knoppix версии 4.0 доступен также на&lt;br /&gt;
DVD — его вы могли видеть на диске, прилагавшемся к прошлому номера нашего&lt;br /&gt;
журнала.&lt;br /&gt;
&lt;br /&gt;
Последние улучшения Knoppix, такие&lt;br /&gt;
как способность сохранять персональные&lt;br /&gt;
файлы на USB-flash, переводят проект из&lt;br /&gt;
просто демонстрационного в полноценный&lt;br /&gt;
дистрибутив. Вот что приближает этот дистрибутив к графической настольной ОС:&lt;br /&gt;
* Загрузка&lt;br /&gt;
Knoppix запускается подобно любому другому дистрибутиву: появляется приглашение загрузчика, затем загружается ядро.&lt;br /&gt;
Вы можете передать некоторые опции в&lt;br /&gt;
приглашении загрузчика, чтобы выбрать&lt;br /&gt;
различные видеорежимы или оконные&lt;br /&gt;
менеджеры.&lt;br /&gt;
&lt;br /&gt;
Как только ядро получит управление,&lt;br /&gt;
начинают работать сценарии инициализации, и только здесь вы впервые заметите&lt;br /&gt;
отличие Knoppix от своего обычного дистрибутива, установленного на жестком&lt;br /&gt;
диске.&lt;br /&gt;
* Файловая система&lt;br /&gt;
В отличие от нормального дистрибутива,&lt;br /&gt;
который монтирует вашу файловую систему и выполняет загрузку программ с нее,&lt;br /&gt;
Knoppix использует сжатый loopback-файл.&lt;br /&gt;
Это отдельный файл, который содержит&lt;br /&gt;
целую файловую систему, включая /, /usr,&lt;br /&gt;
/etc и все прочие каталоги, которые можно&lt;br /&gt;
найти в обычной файловой системе, и&lt;br /&gt;
который располагается на CD/DVD под&lt;br /&gt;
именем «KNOPPIX». Он монтируется через&lt;br /&gt;
так называемый cloop (compressed loop),&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;
же, несмотря на то, что именно вы выбрали: HTML-страница, загружаемая по умолчанию, и фоновый рисунок. Изменение&lt;br /&gt;
этих двух элементов — простой способ&lt;br /&gt;
придать вашему дистрибутиву черты&lt;br /&gt;
вашей торговой марки — и в нашем обзоре мы покажем вам, как это сделать.&lt;br /&gt;
&lt;br /&gt;
=== Что мы можем изменить ===&lt;br /&gt;
Технически, мы можем настроить под&lt;br /&gt;
свои требования любую часть Knoppix, но&lt;br /&gt;
в одних случаях это делается проще, чем&lt;br /&gt;
в других. Наиболее полезный параметр -&lt;br /&gt;
набор предоставляемого ПО — можно&lt;br /&gt;
настроить сразу же, и без всяких ночных&lt;br /&gt;
кошмаров: все благодаря превосходному&lt;br /&gt;
репозитарию Debian, на базе которого&lt;br /&gt;
построен Knoppix. Вы можете удалять&lt;br /&gt;
пакеты, добавлять новые, изменять существующие — либо используя полное&lt;br /&gt;
построение пакета (для этого потребуется&lt;br /&gt;
система Debian), либо с помощью более&lt;br /&gt;
быстрого метода, подробно описанного во&lt;br /&gt;
врезке «Простая правка deb-пакетов»&lt;br /&gt;
слева. Инструменты для работы с пакетами Debian, такие как apt-get и другие,&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;br /&gt;
сценарии и параметры конфигурации.&lt;br /&gt;
&lt;br /&gt;
=== Подготовка ===&lt;br /&gt;
Прежде чем мы приступим собственно к&lt;br /&gt;
разработке, вам нужно будет кое-что подготовить. Наиболее важный элемент -&lt;br /&gt;
диск Knoppix, образ которого вы можете&lt;br /&gt;
загрузить с сайта проекта (http://www.knopper.net/knoppix/index-en.html). Там вы сможете найти ISO-образ Knoppix 4.0, подготовленный для записи на CD-R. Как и с любым дистрибутивом, вы не можете&lt;br /&gt;
просто скопировать файл ISO на CD — вам нужно записать его именно как образ&lt;br /&gt;
диска. Ваша любимая программа для&lt;br /&gt;
записи CD должна иметь эту опцию, а&lt;br /&gt;
если ее нет, вы можете воспользоваться&lt;br /&gt;
проверенной утилитой командной строки&lt;br /&gt;
cdrecord. Обратитесь к странице справки&lt;br /&gt;
(man cdrecord) для получения детальных&lt;br /&gt;
сведений о записи CD-дисков.&lt;br /&gt;
&lt;br /&gt;
Далее, вы должны обратить внимание&lt;br /&gt;
на оперативную память вашего компьютера. Ее у вас должно быть как минимум&lt;br /&gt;
128 Мб, но даже в этом случае некоторые этапы процесса сборки будут идти медленно. Это, конечно же, не смертельно; вы&lt;br /&gt;
можете оставить работающую машину на&lt;br /&gt;
ночь, если потребуется, но чем больше&lt;br /&gt;
ОЗУ у вас есть, тем лучше. Процесс пересборки на самом деле требует 1 Гб памяти,&lt;br /&gt;
но вы можете достичь этого значения,&lt;br /&gt;
добавив виртуальной памяти (swap) к объему вашего ОЗУ. Следует также заметить,&lt;br /&gt;
что вы можете использовать и Knoppix DVD с нашего диска, но требования к&lt;br /&gt;
памяти для редактирования при этом достигнут 5 Гб — нереальное значение для&lt;br /&gt;
большинства из нас.&lt;br /&gt;
&lt;br /&gt;
Наконец, вам потребуется свободное&lt;br /&gt;
место на вашем Linux-разделе на жестком диске. Это может быть специально отформатированный раздел, либо один из тех,&lt;br /&gt;
которые вы уже используете, например, /&lt;br /&gt;
или /home. Для CD вам потребуется 3 Гб&lt;br /&gt;
свободного пространства, а для DVD -&lt;br /&gt;
колоссальный объем в 15 Гб. Итак, если у&lt;br /&gt;
вас есть компакт-диск, необходимый объем оперативной памяти и достаточно места&lt;br /&gt;
на вашем жестком диске — вы готовы к&lt;br /&gt;
дальнейшей работе. Начиная со следующей страницы, мы шаг за шагом погрузимся в процесс переделки, приводя точные&lt;br /&gt;
команды, которые должны будут вводиться, от начала и до конца. Говоря словами Марио — «let’s-a go!»&lt;br /&gt;
&lt;br /&gt;
== Семь шагов для переделки дистрибутива ==&lt;br /&gt;
''Начиная с этого момента, вы должны определиться, на кого будет рассчитан ваш дистрибутив, какое ПО вы хотите на нем разместить и как он должен выглядеть — далее мы поговорим о том, как все это сделать.''&lt;br /&gt;
&lt;br /&gt;
=== 1. Запустите Knoppix ===&lt;br /&gt;
[[изображение:LXF74-75-Knoppix-1.jpg|thumb|Если на вашем жестком диске нет свободного Linux-раздела, используйте cfdisk и mke2fs, чтобы создать его.]]&lt;br /&gt;
Вставьте ваш CD с Knoppix 4.0 в привод, перезагрузите компьютер и установите загрузку с CD. Как правило, для этого нужно нажать [F1], [F2] или [Del] в начале загрузки вашего ПК, затем изменить порядок загрузки в настройках BIOS. После загрузки вам&lt;br /&gt;
нужно будет войти в рабочее окружение KDE. Вы сможете выбрать другой рабочий стол&lt;br /&gt;
или оконный менеджер — это хорошая идея для машин с небольшим объемом оперативной памяти. Откройте окно терминала («K Menu &amp;gt; KNOPPIX &amp;gt; Root Shell»).&lt;br /&gt;
&lt;br /&gt;
Сперва вам нужно убедиться, что компьютер подключен к Интернету. Вы можете&lt;br /&gt;
настроить сеть, как с помощью традиционных инструментов командной строки, так и из&lt;br /&gt;
«K Menu &amp;gt; KNOPPIX &amp;gt; Network/Internet». Выполнив это, подключите раздел жесткого диска, который вы подготовили ранее, и убедитесь, что на нем есть 3 Гб свободного места, и создайте временный рабочий каталог на нем следующими командами:&lt;br /&gt;
 mkdir /mnt/drive&lt;br /&gt;
 mount -rw /dev/hda1 /mnt/drive&lt;br /&gt;
 mkdir /mnt/drive/knoppix-tmp&lt;br /&gt;
&lt;br /&gt;
Замечание: вам может потребоваться изменить hda1 во второй строке на hda2 или тот&lt;br /&gt;
номер, который соответствует подготовленному&lt;br /&gt;
вами разделу.&lt;br /&gt;
&lt;br /&gt;
Замечание 2: вы должны&lt;br /&gt;
смонтировать его в режиме чтения-записи (опция -rw). Также стоит ввести hdparam -d1 /dev/hda&lt;br /&gt;
для включения режима DMA и ускорения работы с диском.&lt;br /&gt;
&lt;br /&gt;
=== 2. Создайте swap и скопируйте файлы ===&lt;br /&gt;
[[изображение:LXF74-75-Knoppix-2.jpg|thumb|Вам может потребоваться добавить пространства под swap-файл, чтобы получить требуемый 1 Гб памяти.]]&lt;br /&gt;
Как уже упоминалось, вам потребуется 1 Гб памяти (реальной плюс виртуальной).&lt;br /&gt;
Если объем вашего ОЗУ меньше 1 Гб, создайте swap-файл, чтобы воспользоваться&lt;br /&gt;
виртуальной памятью. Следующие команды создадут swap-файл размером 750 Мб в&lt;br /&gt;
дополнение к вашим 256 Мб ОЗУ:&lt;br /&gt;
 cd /mnt/drive/knoppix-tmp&lt;br /&gt;
 dd if=/dev/zero of=swapfile bs=1M count=750&lt;br /&gt;
 mkswap swapfile&lt;br /&gt;
 swapon swapfile&lt;br /&gt;
Теперь создайте 2 каталога для исходных файлов Knoppix и вашего финального CD,&lt;br /&gt;
и в обоих создайте папку KNOPPIX. Скопируйте в них все файлы дистрибутива Knoppix,&lt;br /&gt;
готовя их к модификации (процесс копирования потребует некоторого времени):&lt;br /&gt;
 mkdir -p /mnt/drive/knoppix-tmp/master/KNOPPIX&lt;br /&gt;
 mkdir -p /mnt/drive/knoppix-tmp/source/KNOPPIX&lt;br /&gt;
 cd -Rp /KNOPPIX/* /mnt/drive/knoppix-tmp/source/KNOPPIX&lt;br /&gt;
 cd -ap /cdrom/boot /mnt/drive/knoppix-tmp/master/boot&lt;br /&gt;
 cp /cdrom/imdex.html /mnt/drive/knoppix-tmp/master/&lt;br /&gt;
 cd /cdrom &amp;amp;&amp;amp; find . -size -10000k -type f -exec cp -p --parents '{}' /mnt/drive/knoppixtmp/master/ \;&lt;br /&gt;
Обратите внимание на последнюю строку: для DVDверсии вам следует использовать размер 15000k и копировать каталог KNOPPIX2 с помощью команды&lt;br /&gt;
 cp /cdrom/KNOPPIX KNOPPIX2 /mnt/drive/knoppix-tmp/master/KNOPPIX&lt;br /&gt;
&lt;br /&gt;
=== 3. Откройте сессию chroot ===&lt;br /&gt;
[[изображение:LXF74-75-Knoppix-3.jpg|thumb|Теперь мы в chroot-каталоге, который выглядит и ведет себя как отдельный дистрибутив Linux.]]&lt;br /&gt;
Итак, вы скопировали ПО, входящее в состав Knoppix, в source/KNOPPIX, и дополнительно вспомогательные файлы для изготовления дистрибутива в master/. А теперь&lt;br /&gt;
начнется веселье! Используя программу chroot, вы можете создать сессию внутри копии&lt;br /&gt;
Knoppix — другими словами, начать использовать ее, как отдельный дистрибутив.&lt;br /&gt;
«Chroot» означает «change root» (сменить корень), и устанавливает ваш корневой каталог / туда, куда вы укажете. Итак, поменяем корневой каталог на тот, где хранится наша&lt;br /&gt;
копия Knoppix, что позволит нам использовать и модифицировать ее, как будто мы ее&lt;br /&gt;
уже запустили:&lt;br /&gt;
 chroot /mnt/drive/knoppix-tmp/source/KNOPPIX&lt;br /&gt;
Теперь любые изменения будут отражаться на создаваемом дистрибутиве. То, что&lt;br /&gt;
вы увидите в каталоге /, находясь в chroot, на самом деле будет /mnt/drive/knoppix-tmpsource/KNOPPIX. Если вы хотите добавить ПО из репозитария Debian, вам потребуется&lt;br /&gt;
настроить сеть:&lt;br /&gt;
 mount -t proc /proc proc&lt;br /&gt;
Затем откройте второе окно терминала, чтобы вы временно оказались вне chroot-окружения, и введите приведенную ниже команду (это нельзя сделать из&lt;br /&gt;
chroot-окружения):&lt;br /&gt;
 cp /etc/dhcpc/resolv.conf /mnt/drive/knoppix-tmp/source/KNOPPIX/etc/dhcpc/resolv.conf&lt;br /&gt;
&lt;br /&gt;
=== 4. Выберите ваше новое ПО ===&lt;br /&gt;
Теперь можно добавлять и удалять софт, используя отличный инструмент Debian -&lt;br /&gt;
apt-get. Прежде всего, введите apt-get update (НЕ upgrade!), чтобы обновить список&lt;br /&gt;
пакетов. Затем наберите dpkg-query -l — получите список установленных пакетов.&lt;br /&gt;
Для удобства можно перенаправить вывод на программу постраничного просмотра:&lt;br /&gt;
dpkg-query -l | less. Чтобы удалить пакет, введите apt-get remove -purge &amp;lt;имя_&lt;br /&gt;
пакета&amp;gt;. Чтобы установить новый пакет из Интернета, наберите apt-get install&lt;br /&gt;
&amp;lt;имя_программы&amp;gt;. Репозитарий программного обеспечения Debian просто огромен: вы сможете переделать ваш дистрибутив, как только пожелаете. Например, чтобы удалить редактор Zile и установить Nano, мы выполним следующие команды:&lt;br /&gt;
 apt-get remove --purge zile&lt;br /&gt;
 apt-get install nano&lt;br /&gt;
Как только вы закончите, введите apt-get clean, чтобы удалить загруженные&lt;br /&gt;
файлы, оставшиеся в кэше.&lt;br /&gt;
&lt;br /&gt;
Замечание: есть пакеты, которые вы не можете удалить, например, ядро, libc и&lt;br /&gt;
сценарии инициализации. Если вы сомневаетесь, можно ли что-то удалять, оставьте&lt;br /&gt;
все, как есть. Если же пакет слишком велик, и вам хочется сэкономить место, зайдите&lt;br /&gt;
на Linux-форум и спросите, насколько он важен для работы системы.&lt;br /&gt;
&lt;br /&gt;
=== 5. Измените поведение ===&lt;br /&gt;
[[изображение:LXF74-75-Knoppix-4.jpg|thumb|Сделать более замысловатый фоновый рисунок совсем не сложно…]]&lt;br /&gt;
Покончив с сортировкой программ, самое время покопаться в системе и изменить&lt;br /&gt;
другие параметры. В /etc/skel вы сможете найти файлы конфигурации, используемые по умолчанию для новых пользователей (введите ls -a, чтобы увидеть их все).&lt;br /&gt;
&lt;br /&gt;
В /etc/init.d вы найдете стартовые сценарии для программ, которые могут быть&lt;br /&gt;
запущены на этапе загрузки системы. Вы можете добавить другие сценарии в /etc/&lt;br /&gt;
rc5.d, чтобы загружать программы до того как будет запущена графическая оболочка. И, конечно же, сам /etc — это место расположения всевозможных конфигурационных файлов, которые вы можете настроить по своему усмотрению — однако, если&lt;br /&gt;
сомневаетесь, лучше не изменяйте их. Поскольку вы находитесь в chroot-окружении,&lt;br /&gt;
вы можете тестировать ваши графические приложения, введя export&lt;br /&gt;
DISPLAY=localhost:0 и уже потом запустив саму программу. Это позволит вашей&lt;br /&gt;
программе подсоединиться и использовать уже существующий экран, вместо того&lt;br /&gt;
чтобы пытаться найти запущенный X-сервер в chroot-окружении. Некоторые изменения производятся за пределами chroot; например, мы можем придать фоновому&lt;br /&gt;
рисунку, используемому по умолчанию, собственные оттенки. Откройте отдельную&lt;br /&gt;
оболочку с правами root, и введите:&lt;br /&gt;
 chmod +w /mnt/drive/knoppix-tmp/master/KNOPPIX/background.jpg&lt;br /&gt;
 gimp /mnt/drive/knoppix-tmp/master/KNOPPIX/background.jpg&lt;br /&gt;
&lt;br /&gt;
Теперь вы можете отредактировать фоновое изображение, добавив ваш логотип&lt;br /&gt;
или элементы оформления. Конечно, вы можете полностью заменить этот файл.&lt;br /&gt;
Экран загрузчика (splash screen) размещается в /mnt/drive/knoppix-tmp/master/&lt;br /&gt;
boot/isolinux/logo.16 — вам потребуется пакет Syslinux, чтобы отредактировать его.&lt;br /&gt;
В отдельной оболочке измените формат, отредактируйте изображение и переконвертируйте в прежний формат:&lt;br /&gt;
 cd /mnt/drive/knoppix-tmp/knoppix-tmp/master/boot/isolinux; chmod +w logo.16&lt;br /&gt;
 lss16toppm &amp;lt; logo.16 &amp;gt; logo.ppm&lt;br /&gt;
 gimp logo.ppm (сохраните как indexed GIF с 14 цветами)&lt;br /&gt;
 giftoppm &amp;lt; logo.gif &amp;gt; logo.ppm&lt;br /&gt;
 ppmtolss16 &amp;lt; logo.ppm &amp;gt; logo.16&lt;br /&gt;
Наконец, вы можете изменить&lt;br /&gt;
файл помощи, который выводится,&lt;br /&gt;
когда запускается какой-либо оконный менеджер (например, KDE,&lt;br /&gt;
используемый по умолчанию). Его&lt;br /&gt;
можно найти в файле /mnt/drive/knoppix-tmp/master/index.html.&lt;br /&gt;
&lt;br /&gt;
=== 6. Пересоздайте сжатый образ ===&lt;br /&gt;
[[изображение:LXF74-75-Knoppix-5.jpg|thumb|mkisofs обеспечивает отличную обратную связь, так что обнаружить любую проблему достаточно легко.]]&lt;br /&gt;
Когда вы внесете все желаемые изменения, выйдите из chroot, введя umount /proc и&lt;br /&gt;
нажав [Ctrl]+[D]. Chroot-сессия будет завершена. Осмотрите каталоги, в которых вы&lt;br /&gt;
работали, чтобы удалить временные файлы. Теперь перейдем к предпоследнему из&lt;br /&gt;
важных шагов — созданию сжатого образа файловой системы. На странице 46 мы&lt;br /&gt;
видели, что Live CD использует сжатый файл, представляющий собой файловую систему с сохраненным ПО, так что нам нужно создать его заново:&lt;br /&gt;
 mkisofs -R -U -V &amp;quot;filesystem&amp;quot; -publisher &amp;quot;MyName www.myurl.com&amp;quot; -hide-rr-moved cache-inodes -no-bak \&lt;br /&gt;
 /mnt/drive/knoppix-tmp/source/KNOPPIX | /usr/bin/create_compressed_fs - 65536 &amp;gt; /mnt/drive/knoppix-tmp/master/KNOPPIX/KNOPPIX&lt;br /&gt;
На этом этапе вы можете изменить имя издателя и адрес сайта (опция publisher),&lt;br /&gt;
но в остальном эта команда&lt;br /&gt;
должна быть набрана с точностью до буквы. В зависимости&lt;br /&gt;
от скорости вашего компьютера, ей потребуется некоторое&lt;br /&gt;
время, чтобы завершить работу.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 7. Постройте финальный ISO-образ ===&lt;br /&gt;
[[изображение:LXF74-75-Knoppix-6.jpg|thumb|Итоговый результат: LFX-дистрибутив с милым пингвином.]]&lt;br /&gt;
Настает важный момент: создание финального образа диска. Мы создадим ISO-образ&lt;br /&gt;
собранного нами Knoppix, готового для использования или распространения. Прежде&lt;br /&gt;
всего, нужно будет вычислить MD5-сумму для диска, которая очень важна для проверки&lt;br /&gt;
целостности (она позволяет убедиться, что вы раздаете неиспорченные диски).&lt;br /&gt;
 cd /mnt/drive/knoppix-tmp/master&lt;br /&gt;
 find -type f -not-name md5sums -not-name boot.cat -not-name isolinux.bin -exec &lt;br /&gt;
 md5sum '{}' \; &amp;gt; KNOPPIX/md5sums&lt;br /&gt;
Далее следует еще одна большая команда, самая последняя команда, так что не&lt;br /&gt;
пугайтесь. Эта команда создает собственно файл ISO. Когда она завершится, файл&lt;br /&gt;
будет готов для записи на диск. Она использует инструмент mkisofs, чтобы взять наши&lt;br /&gt;
только что измененные файлы Knoppix, объединить их с загрузочными данными и&lt;br /&gt;
получить образ диска.&lt;br /&gt;
 cd /mnt/drive/knoppix-tmp/master&lt;br /&gt;
 mkisofs -pad -l -r -J -v -V “MYDISTRO” -no-emul-boot -boot-load-size 4 -boot-info-table b boot/isolinux/isolinux.bin \&lt;br /&gt;
 -c boot/isolinux/boot.cat -hide-rr-moved -o /mnt/drive/knoppix-tmp/mydistro.iso /mnt/drive/knoppix-tmp/master&lt;br /&gt;
Когда работа завершится, вы получите сияющий новизной ISO-образ вашего дистрибутива в /mnt/drive/knoppix-tmp/mydistro.iso. Вы можете протестировать его,&lt;br /&gt;
записав на CD-R в вашем обычном дистрибутиве, или воспользовавшись быстрым&lt;br /&gt;
запуском в эмуляторе, например,&lt;br /&gt;
VMWare или Qemu.&lt;br /&gt;
&lt;br /&gt;
Если все работает правильно, вы можете теперь выложить куда-нибудь ваш ISO-образ, и поделиться результатами вашей тяжелой работы.&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;
какие проводит Debian — в конце концов,&lt;br /&gt;
вы используете в качестве основы уже&lt;br /&gt;
хорошо зарекомендовавший себя дистрибутив. Тем не менее, стоит проверить, что&lt;br /&gt;
все основные программы, которые вы устанавливали, работают правильно, и что&lt;br /&gt;
любые изменения, которые вы выполняли&lt;br /&gt;
в низкоуровневых компонентах (таких как&lt;br /&gt;
сценарии инициализации), не повлекли за&lt;br /&gt;
собой каких-либо проблем. Если вы выпускаете CD «для всех», например, для продвижения Linux, вы вряд ли хотите стать в&lt;br /&gt;
итоге командой технической поддержки,&lt;br /&gt;
работающей в режиме «24х7»?&lt;br /&gt;
&lt;br /&gt;
Что делать, если что-то не работает? К&lt;br /&gt;
счастью, вам не нужно повторять всю процедуру еще раз. Если вы еще не удалили&lt;br /&gt;
рабочие файлы с вашего жесткого диска,&lt;br /&gt;
вы можете запустить Knoppix, подключить&lt;br /&gt;
диск (шаг 1), добавить swap-файл (шаг 2)&lt;br /&gt;
и войти в chroot (шаг 3). После устранения&lt;br /&gt;
проблемы вы можете пересобрать ISOобраз, как показано в шагах 6 и 7, скрестив&lt;br /&gt;
пальцы. Если у вас возникла проблема,&lt;br /&gt;
специфическая для Knoppix, есть замечательный форум, который может помочь&lt;br /&gt;
вам при переделке Knoppix, находящийся&lt;br /&gt;
по адресу: http://www.knoppix.net/forum/viewforum.php?f=2. Объясните, что вы&lt;br /&gt;
пытаетесь сделать и что не получается, и&lt;br /&gt;
кто-нибудь вам поможет.&lt;br /&gt;
&lt;br /&gt;
Надеемся, что теперь вы сформировали свой собственный дистрибутив, и попутно получили некоторые полезные знания в&lt;br /&gt;
области Linux. Тем не менее, есть много&lt;br /&gt;
путей для дальнейшего движения — вы&lt;br /&gt;
можете попробовать Linux From Scratch&lt;br /&gt;
(смотрите справа врезку «Утоление жажды&lt;br /&gt;
творчества») или присоединитесь к другому проекту разработки дистрибутива.&lt;br /&gt;
Учитывая организацию и политику Debian&lt;br /&gt;
или, скажем, Fedora, довольно сложно сделать большие изменения в этих дистрибутивах, но меньшие проекты более приспособлены для этого и готовы к испытанию&lt;br /&gt;
новых идей. Посетите сайт Ладислава&lt;br /&gt;
Боднара (Ladislav Bodnar) — http://www.distrowatch.com - чтобы узнать, какой&lt;br /&gt;
из дистрибутивов Linux находится на вершине популярности.&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;
== Альтернатива: Morphix ==&lt;br /&gt;
;Построение дистрибутивов, основанное на графическом интерфейсе&lt;br /&gt;
&lt;br /&gt;
[[изображение:LXF74-75-Morphix-1.jpg|thumb|IBuild может работать и с Knoppix, хотя Morphix предпочтительнее.]]&lt;br /&gt;
Morphix — это Live CD, основанный на Knoppix (то есть,&lt;br /&gt;
фактически, на Debian), который щеголяет довольно элегантной системой построения дистрибутива с использованием графического интерфейса. Все еще требуется&lt;br /&gt;
кое-что делать из командной строки, но большинство&lt;br /&gt;
операций по настройке можно выполнять в графическом&lt;br /&gt;
интерфейсе. Эта программа называется IntelliBuild, и&lt;br /&gt;
доступна по адресу http://ibuild.livecd.net. Мы включили основные файлы Morphix в наш диск, чтобы сэкономить время и трафик, которые вы потратили бы на загрузку.&lt;br /&gt;
&lt;br /&gt;
IBuild использует шаблоны, которые позволяют вам&lt;br /&gt;
выбирать пакеты из репозитариев Debian, и изменять&lt;br /&gt;
другие элементы дистрибутива, такие как экран заставки&lt;br /&gt;
и стартовые сценарии. Чтобы запустить его, вам нужно&lt;br /&gt;
иметь последние версии chroot, cloop-utils, Python,&lt;br /&gt;
PyGTK, python-vte и mkisofs. Как и в случае с Knoppix,&lt;br /&gt;
вам потребуется 3 Гб свободного места на диске и 1 Гб&lt;br /&gt;
оперативной памяти (включая объем swap-файла).&lt;br /&gt;
Сначала смонтируйте прилагаемый диск и из-под пользователя root выполните следующие команды:&lt;br /&gt;
 cd ~; mkdir ibuild; cd ibuild&lt;br /&gt;
 mkdir -p prebuilt/mainmod; cd prebuilt/mainmod&lt;br /&gt;
 cp /mnt/cdrom/Magazine/BuildDistro/BareX.mod.iso.bz2 .&lt;br /&gt;
 bunzip2 BareX.mod.iso.bz2&lt;br /&gt;
Теперь вам нужно создать кое-какие рабочие каталоги и&lt;br /&gt;
скопировать в них файлы с образа Mophix Base. Как обычно, замените /mnt/cdrom правильным местоположением&lt;br /&gt;
вашего CD/DVD-диска (в некоторых дистрибутивах это&lt;br /&gt;
может быть /cdrom):&lt;br /&gt;
 mkdir -p ~/ibuild/prebuilt/base/temp&lt;br /&gt;
 mkdir -p ~/ibuild/prebuilt/base/0.5-pre5&lt;br /&gt;
 cd ~/ibuild/prebuilt/base&lt;br /&gt;
 mount -o loop /mnt/cdrom/Magazine/BuildDistro/MorphixBase-0.5-pre.iso temp&lt;br /&gt;
 cp -a temp/* 0.5-pre5/&lt;br /&gt;
 umount /temp&lt;br /&gt;
Установите пакет IBuild, либо собрав из&lt;br /&gt;
исходных кодов, либо инсталлировав&lt;br /&gt;
deb-пакет (если вы получите сообщения&lt;br /&gt;
об ошибке, вам может потребоваться скопировать файлы из src/iGui/ в /usr/lib/ibuild или в другое место, куда вы выполняете установку).&lt;br /&gt;
&lt;br /&gt;
Теперь, когда основные файлы Morphix&lt;br /&gt;
на месте и IBuild установлен, вы можете&lt;br /&gt;
запустить ibuild.py приступить к работе.&lt;br /&gt;
Здесь вы найдете шаблоны, которые&lt;br /&gt;
можете изменить под свои требования,&lt;br /&gt;
такие как fireflux.xml в /usr/share/ibuild/config (или в /usr/local/share/ibuild/config). Они предопределяют набор пакетов и косметические особенности.&lt;br /&gt;
Когда вы будете готовы, нажмите кнопку Build, которая&lt;br /&gt;
должна быть в нижнем правом углу. Вы найдете полученный ISO-образ в каталоге ~ /ibuild/release/. За&lt;br /&gt;
дополнительной информацией обращайтесь по адресу http://wiki.livecd.net/livecd/ibuildHowto&lt;br /&gt;
&lt;br /&gt;
== Утоление жажды творчества ==&lt;br /&gt;
[[изображение:LXF74-75-LFS-1.jpg|thumb|LFS понятно изложен, информативен и хорошо написан — превосходное средство.]]&lt;br /&gt;
Хотя Knoppix и предоставляет простой и легкий путь для&lt;br /&gt;
переделки дистрибутива, существует масса других&lt;br /&gt;
возможностей, если вам хочется копнуть поглубже. Одна&lt;br /&gt;
из них — Linux From Scratch (LFS), своеобразный метадистрибутив — это не установочная система Linux, а&lt;br /&gt;
рабочая среда и руководство, предназначенные для&lt;br /&gt;
создания своей собственной системы. Она предоставляет&lt;br /&gt;
огромное пространство для модификаций и переделок,&lt;br /&gt;
но ценой бОльших затрат времени и усилий. И все же,&lt;br /&gt;
делая все с самого начала, вы досконально изучите&lt;br /&gt;
работу Linux и это даст вам возможность еще более&lt;br /&gt;
глубоких изменений. Многие из нынешних&lt;br /&gt;
разработчиков Linux-дистрибутивов начинали с LFS, что&lt;br /&gt;
вызывало у них интерес и желание присоединиться к&lt;br /&gt;
какому-либо проекту.&lt;br /&gt;
&lt;br /&gt;
LFS поставляется как набор архивов с исходными&lt;br /&gt;
кодами, дополненный исчерпывающим онлайн-руководством. Вы начинаете с создания голого скелета&lt;br /&gt;
дистрибутива Linux из вашего текущего, добавляя один&lt;br /&gt;
за другим необходимые компоненты, позволяющие ему&lt;br /&gt;
запускаться и работать (то есть полный инструментарий&lt;br /&gt;
разработчика). Аккуратно поделенное на секции&lt;br /&gt;
руководство объясняет вам, как компилировать каждую&lt;br /&gt;
программу, и предоставляет множество возможностей&lt;br /&gt;
для внесения собственных настроек. Также имеется BLFS&lt;br /&gt;
(Beyond Linux From Scratch), который освещает более&lt;br /&gt;
продвинутые темы, такие как компиляция огромного&lt;br /&gt;
рабочего стола Gnome. Узнать больше об LFS вы можете,&lt;br /&gt;
посетив сайт http://www.linuxfromscratch.org&lt;br /&gt;
&lt;br /&gt;
== Пять «популярных» ошибок ==&lt;br /&gt;
''Остерегайтесь их, когда создаете дистрибутив…''&lt;br /&gt;
# Плохое название. Хотя «Joe’s Hyper Plasma Spatula Orgasmix LiGNUx 0.54C3a1» может звучать достаточно круто, это практически не произносимо. Используйте что-нибудь краткое и запоминающееся, такое как «Plasma Linux 1.0»&lt;br /&gt;
# Запутанный набор приложений. Вместо того чтобы завалить пользователя уймой текстовых редакторов, попробуйте выбрать один хороший пример из всех программ. Другими словами, Nano.&lt;br /&gt;
# Противоречивость. Если возможно, привяжите все к одному инструментарию, скажем, GTK или Qt. При одновременном использовании нескольких инструментариев у вас будет не рабочий стол, а бардак.&lt;br /&gt;
# Безвкусица. Бесконечно яркие цвета могут быть хороши в цирке, но не на рабочем столе пользователя. Выбирайте приятную для глаз тему рабочего стола, а не вызывающий головную боль аналог шапито.&lt;br /&gt;
# Недостаточная ширина канала. Найдите хороший хостинг, или присоединитесь к BitTorrent. Ничто не обижает заинтересованного потенциального пользователя больше, чем необходимость тратить жизнь на скачивание со скоростью 5 килобит в секунду.&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF74-75:%D0%A7%D1%82%D0%BE_%D0%B7%D0%B0_%D1%88%D1%82%D1%83%D0%BA%D0%B0...</id>
		<title>LXF74-75:Что за штука...</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF74-75:%D0%A7%D1%82%D0%BE_%D0%B7%D0%B0_%D1%88%D1%82%D1%83%D0%BA%D0%B0..."/>
				<updated>2008-07-11T14:00:34Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: Новая: ''Хотите сэкономить время на кодировании запросов к базе данных? Скотт Дуглас (Scott Douglass) подскажет, как ...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;''Хотите сэкономить время на кодировании запросов к базе данных? Скотт Дуглас (Scott Douglass) подскажет, как это сделать.''&lt;br /&gt;
&lt;br /&gt;
;&amp;gt;&amp;gt; Hibernate… то есть спячка… это не то, чем зимой занимаются медведи?&lt;br /&gt;
Так и есть, но вместо долгих часов зимней спячки&lt;br /&gt;
они в это время изобретают новый способ сохранения объектов Java в базе данных.&lt;br /&gt;
;&amp;gt;&amp;gt; Разве в базах данных хранятся объекты, а не данные?&lt;br /&gt;
Да, обычно вы храните свои данные в базе и получаете доступ к ним с помощью специального API. А&lt;br /&gt;
используя объектно-ориентированный язык Java,&lt;br /&gt;
вы бы считывали данные в Java-объект при помощи SQL-запросов. Объектом можно как угодно&lt;br /&gt;
манипулировать, а потом записать данные обратно&lt;br /&gt;
в базу, опять-таки при помощи SQL и JDBC API&lt;br /&gt;
(JDBC — Java Database Connectivity).&lt;br /&gt;
Однако если выключить компьютер, не сохранив&lt;br /&gt;
данные из объекта, то они будут потеряны. Объекты&lt;br /&gt;
Java могут существовать только в виртуальной&lt;br /&gt;
машине Java — Sun не проектировал Java для записи&lt;br /&gt;
на жесткий диск; поэтому объекты не переходят из&lt;br /&gt;
сессии в сессию. Многие люди задумались: а что&lt;br /&gt;
если сохранять Java-объект непосредственно в базе&lt;br /&gt;
данных, без нудных SQL-запросов и кода JDBC? Вот&lt;br /&gt;
тут и нужен Hibernate — он обеспечивает объектно-&lt;br /&gt;
реляционное отображение (ORM — Object&lt;br /&gt;
Relational Mapping) между объектом и БД.&lt;br /&gt;
;&amp;gt;&amp;gt; Отлично. А он написан медведями-гризли или бурыми медведями?&lt;br /&gt;
Пожалуй, надо прояснить ситуацию с медведями…&lt;br /&gt;
&lt;br /&gt;
На самом деле проект разрабатывается замечательными ребятами из JBoss, и лицензирован по&lt;br /&gt;
LGPL.&lt;br /&gt;
;&amp;gt;&amp;gt; Постоянное хранение объектов, хм-м, а разве не для этого предназначалась технология Enterprise Java Beans?&lt;br /&gt;
Enterprise Java Beans (EJBs) — это серверные объекты, которые живут в контейнере в сервере приложений. Hibernate предоставляет ряд преимуществ по сравнению с EJBs, точнее, с их разновидностью, называемой entity beans. Интересной особенностью этих «бобов» является наличие у них&lt;br /&gt;
сохраняемого состояния. Существует два способа&lt;br /&gt;
его сохранения: сохранение, управляемое контейнером (CMP — container managed persistence), при&lt;br /&gt;
котором состоянием бина распоряжается контейнер J2EE (Java 2, Enterprise Edition), и сохранение,&lt;br /&gt;
управляемое бином (BMP — Bean Managed&lt;br /&gt;
Persistence), при котором бин сам контролирует&lt;br /&gt;
свое состояние.&lt;br /&gt;
В отличие от CMP, Hibernate позволяет отображать несколько таблиц на один Java-объект или&lt;br /&gt;
описывать несколько Java-объектов одной таблицей. Аналогичный результат можно получить и&lt;br /&gt;
через BMP, но тогда потребуется самим написать&lt;br /&gt;
всю JDBC-логику внутри бина.&lt;br /&gt;
;&amp;gt;&amp;gt; То есть Java-объекты должны быть записаны особым образом? А не могу я просто сохранить любой объект?&lt;br /&gt;
В Hibernate — можете. Он позволяет сохранять&lt;br /&gt;
практически любой Java-класс, разработанный с&lt;br /&gt;
помощью стандартных объектно-ориентированных&lt;br /&gt;
методов, благодаря чему &amp;quot;срабатывают все сильные стороны Java: наследование (когда один класс&lt;br /&gt;
выводится из другого), композиция (включение&lt;br /&gt;
новых членов) и даже группировка классов в «коллекции». По сути, вы можете разрабатывать Java-приложения, почти не заботясь о том, каким образом Hibernate сохранит ваши объекты.&lt;br /&gt;
;&amp;gt;&amp;gt; И мне не придется писать большой объём тупого JDBC кода?&lt;br /&gt;
Нет — как только вы создадите свой Java-объект&lt;br /&gt;
и определите его отображение, код, который вам&lt;br /&gt;
нужно будет написать для сохранения или восстановления объекта, будет минимальным, по сравнению с JDBC-вызовами и связанной с ними обработкой ошибок.&lt;br /&gt;
;&amp;gt;&amp;gt; Что такое отображение?&lt;br /&gt;
Хороший вопрос. Hibernate должен знать,&lt;br /&gt;
какие таблицы относятся к каким объектам, и для&lt;br /&gt;
этого он использует карту в формате XML. Вы,&lt;br /&gt;
конечно, можете создать один большой XML-файл, содержащий отображение всех ваших объектов, но Hibernate позволяет завести отдельный&lt;br /&gt;
файл для каждого объекта. В этом случае у вас&lt;br /&gt;
будет набор небольших файлов, имеющих чёткое&lt;br /&gt;
назначение.&lt;br /&gt;
;&amp;gt;&amp;gt; Переписать все мои таблицы в формате XML — мороки не меньше, чем наготовить те же JDBC-вызовы…&lt;br /&gt;
Если у вас всего лишь один-два объекта, которые&lt;br /&gt;
вы хотите использовать с Hibernate, то написать&lt;br /&gt;
XML — невеликий труд: формат весьма прост. Для&lt;br /&gt;
случая, когда у вас множество объектов, Hibernate&lt;br /&gt;
позаботился о механизмах автоматической генерации соответствующих файлов.&lt;br /&gt;
;&amp;gt;&amp;gt; Ого! Он может сам создавать свои конфигурационные файлы?&lt;br /&gt;
Может, но вам придётся следовать некоторым правилам при проектировании своих объектов. Ничего&lt;br /&gt;
особо революционного: просто надо предусмотреть&lt;br /&gt;
конструктор по умолчанию и методы доступа&lt;br /&gt;
к полям (get/set). На самом деле Hibernate поставляется с утилитой генерации схемы базы данных&lt;br /&gt;
или шаблона из вашего файла с отображением.&lt;br /&gt;
Это означает (в теории), что если вы создали Javaобъект, который хотите сохранить с помощью&lt;br /&gt;
Hibernate, вы можете воспользоваться утилитами&lt;br /&gt;
для генерации файла отображения и последующей&lt;br /&gt;
генерации из него схемы базы данных.&lt;br /&gt;
;&amp;gt;&amp;gt; Но мне по прежнему нужен какой-нибудь контейнер, так?&lt;br /&gt;
На самом деле нет. В отличие от EJB, которым требуется сервер приложений J2EE (например, JBoss),&lt;br /&gt;
Hibernate не требует никакого специального окружения. Это делает его гораздо более легковесным,&lt;br /&gt;
чем EJBs, и пригодным для автономных&lt;br /&gt;
приложений.&lt;br /&gt;
;&amp;gt;&amp;gt; Не приводит ли к потере производительности то, что Hibernate не использует контейнер?&lt;br /&gt;
Видимо, нет. Печально известно, что EJB работают&lt;br /&gt;
медленно, несмотря на то, что живут внутри своего&lt;br /&gt;
контейнера. Hibernate, хотя и запускается немного&lt;br /&gt;
подольше, считается очень быстрым. Разработчики&lt;br /&gt;
Hibernate утверждают, что он может быть даже быстрее решения с использованием SQL/JDBC, поскольку сгенерированные Hibernate запросы могут содержать кэширование данных и другие оптимизации.&lt;br /&gt;
;&amp;gt;&amp;gt; А если я хочу сделать со своими данными что-нибудь похитрее, но у меня нет первичного ключа для объекта, который надо вытащить?&lt;br /&gt;
Под первичным ключом вы, конечно, понимаете&lt;br /&gt;
индивидуальный идентификатор, заданный для&lt;br /&gt;
каждой записи таблицы. Что ж, как это ни удивительно, но вместо написания SQL запросов и&lt;br /&gt;
выполнения их с помощью JDBC&lt;br /&gt;
вы можете воспользоваться&lt;br /&gt;
собственным объектным языком Hibernate — HQL (Hibernate Query Language).&lt;br /&gt;
На этом языке можно напрямую делать запросы к&lt;br /&gt;
объектам и их свойствам. Запросы выходят более&lt;br /&gt;
компактными, чем их эквивалент в SQL, поскольку&lt;br /&gt;
HQL учитывает отношения, заданные в отображении, и их не надо указывать в самом запросе.&lt;br /&gt;
Hibernate также допускает использование канонического SQL, но разработчики не рекомендуют этого делать.&lt;br /&gt;
;&amp;gt;&amp;gt; Выглядит неплохо, но разве не то же&lt;br /&gt;
самое обещано в новом стандарте EJB3?&lt;br /&gt;
Зачем нам Hibernate, когда Sun скоро будет&lt;br /&gt;
иметь кое-что получше?&lt;br /&gt;
Текущий стандарт EJB не позволяет организовывать объектно-реляционное соответствие, но следующее воплощение стандарта (EJB3) будет включать и стандарт на ORM. Определённо парни из Sun&lt;br /&gt;
знают, что делают, поэтому они и позволили разработчикам Hibernate участвовать в создании стандарта. Hibernate оказал заметное влияние на&lt;br /&gt;
дизайн EJB3.&lt;br /&gt;
&lt;br /&gt;
На самом деле, поскольку Hibernate предполагает&lt;br /&gt;
тот же набор требований к коду, что и entity beans,&lt;br /&gt;
использующие прозрачное сохранение объектов,&lt;br /&gt;
вы сможете использовать Hibernate как управляющий компонент EJB-контейнера — другими словами,&lt;br /&gt;
как первичный интерфейс для взаимодействия с&lt;br /&gt;
бинами во время выполнения. Другой момент в&lt;br /&gt;
пользу Hibernate — то, что он есть уже сейчас, тогда&lt;br /&gt;
как EJB3 ещё предстоит пройти через процесс спецификации JSR (JSR — Java Specification Request).&lt;br /&gt;
Hibernate — образец зрелой технологии, он&lt;br /&gt;
хорошо протестирован и в&lt;br /&gt;
большей или меньшей&lt;br /&gt;
степени представляет собой промышленный стандарт.&lt;br /&gt;
&lt;br /&gt;
;&amp;gt;&amp;gt; Пожалуй, мне это нравится. Как я могу его опробовать?&lt;br /&gt;
Вы можете взять его с прилагаемого диска или&lt;br /&gt;
скачать последнюю версию с www.Hibernate.org.&lt;br /&gt;
Останется только распаковать архив и собрать его&lt;br /&gt;
с помощью Apache Ant (http://ant.apache.org — незаменимый инструмент сборки для Java-разработчика). На Web-сайте вы найдёте более подробные&lt;br /&gt;
инструкции.&lt;br /&gt;
;&amp;gt;&amp;gt; Что мне делать, если сама идея отображения мне подходит, а Hibernate — нет? Есть ли альтернативы?&lt;br /&gt;
Существует множество различных инструментов&lt;br /&gt;
объектно-реляционного отображения. Какой вы&lt;br /&gt;
выберете, будет зависеть от вашей ситуации.&lt;br /&gt;
Сравнение некоторых из них приведено здесь:&lt;br /&gt;
http://c2.com/cgi/wiki?ObjectRelationalToolComparison.&lt;br /&gt;
Другой популярный ORM-продукт — Object&lt;br /&gt;
Relational Bridge (OJB) из проекта Apache&lt;br /&gt;
(http://db.apache.org/ojb). Он несколько новее&lt;br /&gt;
Hibernate, но поскольку это продукт Apache, проблем со стабильностью и поддержкой быть не&lt;br /&gt;
должно. Он поддерживает несколько API сохранения объектов, так что вы можете выбрать наиболее&lt;br /&gt;
подходящий. Cтоит также взглянуть на инструмент&lt;br /&gt;
реляционного отображения TopLink от Oracle (www.&lt;br /&gt;
oracle.com/technology/products/ias/toplink/index.html).&lt;br /&gt;
Он доступен в составе Oracle Application Server или&lt;br /&gt;
отдельно (не бесплатно), и совместим с Oracle или&lt;br /&gt;
другими базами данных.&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF74-75:%D0%A1%D1%80%D0%B0%D0%B2%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5</id>
		<title>LXF74-75:Сравнение</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF74-75:%D0%A1%D1%80%D0%B0%D0%B2%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5"/>
				<updated>2008-05-18T18:46:19Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: /* Антивирусы */ оформление&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
&lt;br /&gt;
== Антивирусы ==&lt;br /&gt;
&lt;br /&gt;
''Грэм Моррисон (Graham Morrison) облачился в белый халат Linux Format для лабораторного иcследования мира быстроразвивающихся антивирусных программ.''&lt;br /&gt;
&lt;br /&gt;
Пользователям Linux всегда говорили, что им нечего волноваться из-за вирусов. Это утверждение считалось верным, поскольку Linux не привлекает хакеров, пишущих вирусы под Windows. Так-то оно так… но нет на свете способа, который остановит грамотно нацеленного «врага». В некоторых дистрибутивах, предоставляющих доступ к root для обычных нужд пользователя, деструктивные скрипты или пара переставленных строк в пользовательской программе могут причинить довольно серьезный ущерб.&lt;br /&gt;
&lt;br /&gt;
Само по себе желание встретить опасность в полной боевой готовности, однако, не объясняет того количества и качества высокоспециализированных антивирусных средств, что доступны для Linux, Дело в том, что изначально они создавались не столько для защиты самого Linux, сколько для других операционных систем. Благодаря повсеместному использованию на почтовых серверах, Linux — идеальная платформа для проверки почты на наличие вирусов перед ее отправкой другим, более уязвимым системам.&lt;br /&gt;
&lt;br /&gt;
По этой причине большинство рассматриваемых в данном обзоре программ стоят немалых денег, а фирмы, обычно упоминавшие Linux лишь походя (например, F-Secure или Kaspersky Lab), взялись за перевод сложных алгоритмов сканирования и управления базами данных на открытую ОС. Антивирусы, однако, не являются чисто коммерческой вотчиной. Единственный открытый пакет, который мы здесь рассмотрим — ClamAV — вполне способен отработать свой хлеб.&lt;br /&gt;
&lt;br /&gt;
Чтобы пакет удостоился места в данном Сравнении, он должен был обнаружить все вирусы, которые мы на него напустили. Функциональность у всех пакетов примерно одинаковая. У большинства из них — консольный интерфейс для управления сканированием и предоставлением отчета о найденных вирусах, практически все используют один и тот же модуль ядра, Dazuko, позволяющий производить сканирование в режиме реального времени. Итак, найти различия между ними будет довольно трудно. Все приложения имеют очень похожие вирусные базы, и чтобы выявить, какое же из них все-таки лучше, мы сконцентрировались на индивидуальных преимуществах, будь то эффективность эвристического анализа или наличие удобного графического интерфейса.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;toc&amp;quot;&lt;br /&gt;
!Наши конкурсанты&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
* [[#AVG Anti-Virus|AVG Anti-Virus]]&lt;br /&gt;
* [[#BitDefender Linux Edition|BitDefender]]&lt;br /&gt;
* [[#ClamAV|ClamAV]]&lt;br /&gt;
* [[#F-Prot Anti-Virus|F-Prot Anti-Virus]]&lt;br /&gt;
* [[#F-Secure Anti-Virus Linux Workstation|F-Secure Anti Virus]]&lt;br /&gt;
* [[#InterScan VirusWall|InterScan VirusWall]]&lt;br /&gt;
* [[#Kaspersky Workstation|Kaspersky Workstation]]&lt;br /&gt;
|-&lt;br /&gt;
! [[#Вердикт|Вердикт]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== AVG Anti-Virus ==&lt;br /&gt;
[[Изображение:LXF74-75 AVG-1.png|thumb|AVG в Bash выглядит не особо эффектно.]]&lt;br /&gt;
''Хорошо известный кросс-платформенный антивирус.''&lt;br /&gt;
* Версия: 7.1&lt;br /&gt;
* Сайт: http://www.grisoft.com &lt;br /&gt;
* Цена: $40 на один сервер&lt;br /&gt;
&lt;br /&gt;
Grisoft хорошо известны в мире антивирусов благодаря бесплатной версии антивирусного ПО для платформы Windows. Бесплатная версия имеет ряд серьезных ограничений, поскольку предназначена для частного некоммерческого использования, но сам факт ее существования уже радует. На фоне мрачных пророчеств об ожидаемой эпидемии вирусов и почтовых червей, Grisoft недавно объявил о выпуске версии своего антивируса для платформы Linux, но предлагает также целый класс коммерческих решений, нацеленных на сканирование почты.&lt;br /&gt;
&lt;br /&gt;
Установка проста, благодаря RPM, и программа довольно удобна в использовании. В нее входит две небольших утилиты, одна для сканирования файлов, а другая для обновления вирусной базы. Их комбинация предоставляет максимально гибкое средство для написания своих собственных решений, и AVG является хорошим выбором для оперативного слежения за последними уязвимостями.&lt;br /&gt;
&lt;br /&gt;
Алгоритм сканирования довольно быстр, эффективен и имеет множество настроек. Сканирование на наличие вирусов включает в себя тот же самый эвристический алгоритм, что и другие программы Grisoft. Опасные участки кода запускаются на виртуальной машине, после чего AVG пытается определить, действительно ли код опасен. Преимущество этого метода — возможность идентифицировать новые вирусы до того, как они появятся в базе данных, но есть и недостаток — ограниченное число атак, которые распознаются эвристическим алгоритмом.&lt;br /&gt;
&lt;br /&gt;
AVG — неплохая программа, и, что немаловажно, умеет автоматически обновлять вирусные базы: достойное решение для малого или среднего бизнеса.&lt;br /&gt;
&lt;br /&gt;
Сильной стороной производителя является широкая линейка продуктов (Grisoft использует один и тот же алгоритм во всех своих антивирусах), а также наличие свободной версии для Linux.&lt;br /&gt;
&lt;br /&gt;
К тому же открытый подход к разработке ПО помогает добиться главного — доверия пользователя.&lt;br /&gt;
&lt;br /&gt;
=== Вердикт Linux Format ===&lt;br /&gt;
Стоит денег, но может оказаться полезен в определенной ситуации&lt;br /&gt;
: '''Рейтинг: 6/10'''&lt;br /&gt;
&lt;br /&gt;
== BitDefender Linux Edition ==&lt;br /&gt;
[[Изображение:LXF74-75 BitDefender-1.png|thumb|Красивое имя — BitDefender, но выглядит он довольно серенько.]]&lt;br /&gt;
''Хорошая поддержка, бесплатный продукт, красивое название.''&lt;br /&gt;
* Версия: 9&lt;br /&gt;
* Сайт: http://www.bitdefender.com &lt;br /&gt;
* Цена: Бесплатен для персонального использования&lt;br /&gt;
&lt;br /&gt;
BitDefender получил наши голоса за хорошее название. Оно звучит динамично, колоритно и волнующе. Подобно AVG, свободная версия является простой командной утилитой, которую можно вызывать из скриптов или запускать по запросу. В данном обзоре это самый простой антивирус, причем на качестве его простота не сказывается отрицательно.&lt;br /&gt;
&lt;br /&gt;
Установка программы элементарна, благодаря использованию RPM, но на процесс установки особо не повлияешь. Все, что вы получаете после установки — одну команду, прописанную в системных путях под названием bdc. Первым делом обновите вирусную базу — и удивитесь, потому как на команду bdc -update последует сообщение «Нет доступных обновлений». Вы, конечно, подумаете «вот какая у меня свежая вирусная база», но на самом деле вы просто подали команду, не имея нужных привилегий.&lt;br /&gt;
&lt;br /&gt;
Это пример некорректного сообщения об ошибке, которое может ввести в заблуждение, и BitDefender не мешало бы стать в этом плане более информативным. Попутно заметим, что команду следует набирать аккуратно и случайно не набрать bcd, которая выполняет абсолютно другие функции (вы будете смеяться, когда она преобразует стандартный ввод в код перфокарт ASCII).&lt;br /&gt;
&lt;br /&gt;
BitDefender — быстрый и эффективный сканер, хорошо поддерживаемый, легкий в использовании. Он без особых проблем вписывается в скрипты для проверки почты или передачи файлов, отчего заметно снижается вероятность заражения вирусами: не спешите с покупкой коммерческой версии программы, в которой фильтрация почты включена по умолчанию.&lt;br /&gt;
&lt;br /&gt;
BitDefender имеет право на существование, особенно если вы уже сталкивались с заражением вирусами, но в нем нет ни одной «вкусности», как в других антивирусах. Так или иначе, вирусные базы он обновляет хорошо (доказано на практике).&lt;br /&gt;
&lt;br /&gt;
=== Вердикт Linux Format ===&lt;br /&gt;
Бесплатный — и это отлично, но ничем «эдаким» не привлекает.&lt;br /&gt;
: '''Рейтинг: 4/10'''&lt;br /&gt;
&lt;br /&gt;
== ClamAV ==&lt;br /&gt;
[[Изображение:LXF74-75 ClamAV-1.png|thumb|Оболочка KlamAV для KDE — удобный интерфейс для проверки на вирусы.]]&lt;br /&gt;
''Оркестр, туш! Антивирус с открытыми исходниками!''&lt;br /&gt;
* Версия: 0.87.1&lt;br /&gt;
* Сайт: http://www.clamav.net&lt;br /&gt;
* Цена: Бесплатно, по лицензии GPL&lt;br /&gt;
ClamAV — самый известный из антивирусов (по крайней мере в open-source сообществе) в нашем Сравнении. Есть серьезные основания считать, что это единственная open-source альтернатива рассмотренным коммерческим или проприетарным продуктам. Есть, конечно, и другие проекты, но работы над ними постепенно прекращаются; а для создания хорошей защиты от вирусов надо идти в ногу со временем.&lt;br /&gt;
&lt;br /&gt;
Довольно легко понять, почему в мире open-source так мало антивирусных проектов. Проблема тут не столько в сложности написания такого рода ПО, сколько в необходимости должной поддержки после выпуска релиза, которая по силам только уж совсем фанатичным группам разработчиков. Антивирус, в котором нет своевременного обновления вирусных баз, вряд ли позволит пользователю жить спокойно.&lt;br /&gt;
&lt;br /&gt;
Хотя ClamAV — открытый проект, он преодолел все эти проблемы и поддерживается разработчиками и сообществом, которое вокруг него возникло, на должном уровне. Достаточно взглянуть на частоту обновления вирусной базы данных, чтобы понять: ClamAV действительно оперативно реагирует на современные вирусные угрозы. Каждый день в его списке появляется множество новых вирусов. Команда, отвечающая за обновление вирусной базы данных, реагирует на угрозу в течение часа после ее объявления. Такой оперативности не добились даже коммерческие антивирусы.&lt;br /&gt;
&lt;br /&gt;
В итоге — этому антивирусу доверилось множество народу. Почтовый сервер под защитой ClamAV работает в [http://SourceForge.net SourceForge.net], но список покоренных IT-фирм этим отнюдь не исчерпывается — среди них есть и достаточно мелкие, и провайдеры услуг Интернета, которые отвечают за чистоту сотен тысяч электронных писем в день.&lt;br /&gt;
&lt;br /&gt;
Немаловажное преимущество: в отличие от некоторых других исследованных нами антивирусов, ClamAV работоспособен как на рабочей станции, так и в виде компонента интегрированного корпоративного решения.&lt;br /&gt;
&lt;br /&gt;
=== Вирусная похлебка ===&lt;br /&gt;
[[Изображение:LXF74-75 ClamAV-2.png|thumb|KlamAV может автоматически настроить проверку вирусов для вашего почтового клиента]]&lt;br /&gt;
В сущности, ClamAV подобен любому из антивирусов, которые мы рассматриваем в этом обзоре. Для работы необходимо установить два пакета: один содержит несколько командных утилит для проверки файлов, другой — средства управления вирусной базой. Единственное требование ClamAV- в системе должны присутствовать инструменты работы с архивами. В принципе, они и так установлены на большинстве Linux-систем, за исключением разве что unzip и unrar. В идеале, следует завести отдельную учетную запись для демона, который запускается при обновлении базы данных утилитой Freshclam..&lt;br /&gt;
&lt;br /&gt;
Возможности программы оправдывают ожидания. Есть командная строка и сканирование по запросу, с целым букетом возможностей. Демон умеет сканировать и обновлять базу данных автоматически, что позволяет с легкостью интегрировать ClamAV и на сервер, и на рабочую станцию.&lt;br /&gt;
&lt;br /&gt;
ClamAV — убедительное свидетельство мощи модели открытых разработок: он инициировал написание огромного количества утилит на все случаи жизни, особенно жизни почтовых серверов. Множество приложений легко интегрируют ClamAV с популярными серверами — например, Postfix, Sendmail, Exim и Qmail. С другой стороны, его можно использовать для проверки на наличие вирусов в почтовых клиентах типа KMail или Evolution, просто фильтруя почту командой ClamAV.Антивирусы обычно выглядят не слишком эффектно, но открытость помогла ClamAV обрасти симпатичными графическими надстройками, включая KlamAV для KDE — с ней ClamAV смотрится не хуже коммерческого ПО.&lt;br /&gt;
&lt;br /&gt;
KlamAV позволяет манипулировать базой данных, производить сканирование на наличие вирусов и помещать сомнительные или инфицированные файлы в надежный карантин, спасая их от немедленной расправы.&lt;br /&gt;
&lt;br /&gt;
Есть и другие оболочки (для Gnome и даже Java) с аналогичной функциональностью. ClamAV — не просто open-source проект: с ним вы чувствуете себя членом сообщества. ClamAV помогает очищать Интернет от вирусов и наглядно демонстрирует, что сообщество open-source имеет в своем арсенале мощный антивирус мирового класса.&lt;br /&gt;
&lt;br /&gt;
=== Вердикт Linux Format ===&lt;br /&gt;
Продукт open source. Отличная поддержка и функциональность.&lt;br /&gt;
: '''Рейтинг: 8/10'''&lt;br /&gt;
&lt;br /&gt;
== F-Prot Anti-Virus ==&lt;br /&gt;
[[Изображение:LXF74-75 F-Prot-1.png|thumb|Термин «нейросеть» намекает на причастность к крутым разработкам.]]&lt;br /&gt;
''Очередной тяжеловес из мира Windows.''&lt;br /&gt;
* Версия: 4.6.2&lt;br /&gt;
* Сайт: http://www.f-prot.com&lt;br /&gt;
* Цена: Бесплатно для персонального использования&lt;br /&gt;
F-Prot — высококлассный и популярный антивирус, портированный для Linux и Unix платформ. Для личного применения его можно бесплатно загрузить с сайта разработчика. Сканирование вашей системы запускается из вашей любимой оболочки при помощи командной строки. Разработчики антивирусов явно поют по одним нотам, поскольку все приложения отличаются одинаковым подходом.&lt;br /&gt;
&lt;br /&gt;
F-Prot похож на всех остальных, но в нем есть серьезное упущение — вирусные базы не загружаются и не устанавливаются автоматически, целиком оставаясь на совести пользователя, который должен сам загружать вирусную базу и размещать в нужном месте системы.&lt;br /&gt;
&lt;br /&gt;
F-Prot в основном делает акцент на макровирусы и трояны. Для поиска деструктивных макросов даже предусмотрен специальный модуль. Очевидно, в вашей Linux-системе он ни к чему, если вы не используете ее как почтовый сервер для макросолюбивых приложений Windows.&lt;br /&gt;
&lt;br /&gt;
Хорошая особенность этого антивируса — алгоритм искусственного интеллекта на основе нейронной сети, очень полезный при поиске деструктивного кода. В документации о нем написано не слишком подробно, но заявлено, что алгоритм строит адаптивный образец для изучения и получения выводов.&lt;br /&gt;
&lt;br /&gt;
Сопутствующий эвристический анализ помогает отловить вирус до его появления в вирусной базе данных. F-Prot — ваш выбор, если вы опасаетесь атаки доселе неизвестных или уж очень хитрых вирусов. Можно еще кое к чему придраться. Например, при вызове списка команд для прокручивания списка надо нажимать клавишу — очевидный шаг назад к MS-DOS-версии этой программы. Выглядит несколько неестественно для людей, привыкших к перенаправлению вывода в less.&lt;br /&gt;
&lt;br /&gt;
Также выяснилось, что программа плохо работает с Linux-архивами, особенно с Bzip2 (с .tar и Zip файлами проблем нет) — еще одно указание, что F-Prot всего лишь дубль успешного продукта с другой платформы. В общем, его ниша — продвинутый анализ, в противоположность рутинной защите.&lt;br /&gt;
&lt;br /&gt;
=== Вердикт Linux Format ===&lt;br /&gt;
Скажите этак небрежно «нейросеть», — и все будут думать: «Вот это да!».&lt;br /&gt;
: '''Рейтинг: 6/10'''&lt;br /&gt;
&lt;br /&gt;
== F-Secure Anti-Virus Linux Workstation ==&lt;br /&gt;
[[Изображение:LXF74-75 F-Secure-1.png|thumb|Даже после базовой установки можно настраивать множество опций.]]&lt;br /&gt;
''Интересный интерфейс пользователя.''&lt;br /&gt;
* Версия: 4.52&lt;br /&gt;
* Сайт: http://www.f-secure.com &lt;br /&gt;
* Цена: $150&lt;br /&gt;
F-Secure отличается от соперников тем, что больше подходит для предприятий, чем для рабочей станции. Оболочка к антивирусу даже имеет соответствующее корпоративно-звучащее название — Policy Manager.&lt;br /&gt;
&lt;br /&gt;
Policy Manager состоит из клиента и сервера. Впервые запуская сервер, вы должны будете ответить на несколько вопросов о конфигурации, например, как часто обновлять вирусные базы (от «ежедневно» до «ежечасно»). После этого сервер будет работать в фоновом режиме.&lt;br /&gt;
&lt;br /&gt;
Работа ведется через Policy Manager Console — Java-интерфейс пользователя к антивирусу и всем связанным с F-Secure продуктам. Из консоли можно сканировать файлы, изменять политику сканирования и обновлять базу данных, да еще решать добрую сотню других задач, естественных для категории «антивирус». К счастью, предусмотрена упрощенная обзорная панель, оформленная как web-страница.&lt;br /&gt;
&lt;br /&gt;
Огромный плюс этой программы — наличие превосходной документации в PDF-формате. Этим часто пренебрегают другие производители антивирусов, особенно открытых. Руководство администратора успешно справилось с описанием главных угроз и дает подробные указания по правильной настройке программы.&lt;br /&gt;
&lt;br /&gt;
F-Secure в общем состоит из того же набора утилит, что и конкуренты (сканер, демон и менеджер обновлений), но выделяется на их фоне благодаря Policy Manager. Пожалуй, он больше подходит для крупных корпоративных сетей, чем для нескольких машин, так как для них будет чересчур сложен.&lt;br /&gt;
&lt;br /&gt;
=== Вердикт Linux Format ===&lt;br /&gt;
Для одиночной машины — перебор; зато это отличное решение для для маленьких сетей.&lt;br /&gt;
: '''Рейтинг: 7/10'''&lt;br /&gt;
&lt;br /&gt;
== InterScan VirusWall ==&lt;br /&gt;
[[Изображение:LXF74-75 F-VirusWall-1.png|thumb|VirusWall и его пользовательский web-интерфейс]]&lt;br /&gt;
''Удаленная web-утилита для тяжелой работы.''&lt;br /&gt;
* Версия: 3.81&lt;br /&gt;
* Сайт: http://www.trendmicro.com&lt;br /&gt;
* Цена: $30 за одиночную лицензию&lt;br /&gt;
По названию можно догадаться: продукт связан с программой VirusWall SMB (малый-средний бизнес). Решение SMB — это прокси-сервер для всего входящего и исходящего трафика, выполняющий намного больше функций, чем простое сканирование на наличие вирусов.&lt;br /&gt;
&lt;br /&gt;
Данная усеченная версия унаследовала множество функций своего большого брата. Она не только умеет сканировать локальные файлы, но может следить за FTP, HTTP и почтовым трафиком с файлами и вложениями, способными представлять угрозу для системы.&lt;br /&gt;
&lt;br /&gt;
У VirusWall тот же web-интерфейс, что и у SMB-версии: программа очень удобно управляется и настраивается всего на двух страницах. Забудьте возню с командными строками и собственными скриптами, гораздо проще организовать удаленное управление.&lt;br /&gt;
&lt;br /&gt;
Установка довольно мудреная — каждым компонентом приложения управляет скрипт оболочки, и иногда непонятно, что установлено, а что нет.&lt;br /&gt;
&lt;br /&gt;
В остальном — все как у всех. Можно задать расписание обновлений вирусной базы и проверки вашей файловой системы. Маловато опций, управляющих поисковым движком — например, отсутствует эвристический анализ; тем не менее VirusWall сумел определить все вирусы, которые мы ему подсунули.&lt;br /&gt;
&lt;br /&gt;
Несомненный плюс VirusWall — простота его применения в качестве прокси-сервера FTP или HTTP, который прозрачно проверяет трафик между сервером и клиентом. Если ваши потребности со временем возрастут, то его легко можно будет обновить до SMB-версии.&lt;br /&gt;
&lt;br /&gt;
Для одиночной машины данная программа слишком амбициозна. Конечно, отслеживать появление вирусов очень важно, но стоит ли из-за этого разоряться на содержание целого Web-сервера? Если у вас всего несколько машин, проще раз в день запускать обычное антивирусное приложение.&lt;br /&gt;
&lt;br /&gt;
=== Вердикт Linux Format ===&lt;br /&gt;
Неплохой выбор, если нужно удаленно управлять системой.&lt;br /&gt;
: '''Рейтинг: 6/10'''&lt;br /&gt;
&lt;br /&gt;
== Kaspersky Workstation ==&lt;br /&gt;
[[Изображение:LXF74-75 Kaspersky-1.png|thumb|Знакомый интерфейс Webmin завоюет много поклонников.]]&lt;br /&gt;
''Выдающийся антивирус из-под Окон.''&lt;br /&gt;
* Версия: 5.5&lt;br /&gt;
* Сайт: http://www.kaspersky.com&lt;br /&gt;
* Цена: $50 за одну лицензию&lt;br /&gt;
Лаборатория Касперского — известный поставщик решений для Windows — представляет Linux-версию своего антивируса. Kaspersky одним из первых обнародовал коммерческую версию антивирусного ПО для рабочих станций Linux. Workstation можно установить из RPM, tar- или Deb-архивов, затем выполнить скрипт загрузки новейших антивирусных баз, сконфигурировать «монитор», отслеживающий вредоносную активность, и — что лучше всего — обзавестись модулем Webmin.&lt;br /&gt;
&lt;br /&gt;
Webmin — популярная утилита администрирования, работающая со своим собственным Web-сервером. Она позволяет настраивать любые аспекты вашей системы: локально — при помощи Web-браузера, или удаленно — если вы разрешите, чтоб ее было видно через ваш брандмауэр. Это отличный подход к управлению антивирусным ПО, который намного приятнее и эффективнее использования командной строки.&lt;br /&gt;
&lt;br /&gt;
У Webmin имеется несколько подмодулей, для просмотра вирусов online, настройки антивируса, запуска или остановки сканирования и обновления вирусной базы данных.&lt;br /&gt;
&lt;br /&gt;
Конечно же, налицо весь джентльменский набор командных утилит, при помощи которых можно выполнить те же самые действия, что и через webmin, а также резидентный сканер и эвристический анализ. Kaspersky проверяет некоторые файлы немного медленнее, чем другие антивирусы, но при работе на одиночной машине это практически не заметно.&lt;br /&gt;
&lt;br /&gt;
Использование интерфейса Webmin весьма украшает антивирус Kaspersky. С ним удобно и просто работать (не утопаешь в море командных ключей), и он хорошо масштабируется под небольшие сети.&lt;br /&gt;
&lt;br /&gt;
Итак, еще одна солидная программа Windows весьма удачно перебралась под Linux — явное свидетельство того, что Kaspersky чувствует рынок куда лучше конкурентов.&lt;br /&gt;
&lt;br /&gt;
=== Вердикт Linux Format ===&lt;br /&gt;
Превосходная защита от вирусов с удобным интерфейсом.&lt;br /&gt;
: '''Рейтинг: 7/10'''&lt;br /&gt;
&lt;br /&gt;
== Вердикт ==&lt;br /&gt;
[[Изображение:LXF74-75 ClamAV-3.png|thumb|Победитель — ClamAV: универсальный, открытый и беспощадный к вирусам!]]&lt;br /&gt;
Из нашего обзора как минимум можно уяснить, что выбор решений очень широк. Если вам нужен простой антивирус, то любая из рассмотренных здесь программ вам более чем подойдет. Все они обнаружили наши тестовые вирусы и умеют обновлять свои вирусные базы.&lt;br /&gt;
&lt;br /&gt;
Если вас не устраивают рассмотренные программы — приглашайте эксперта. Существует множество других антивирусов, большинство из которых не хуже рассмотренных здесь, но годятся скорее для работы на крупных предприятиях.&lt;br /&gt;
&lt;br /&gt;
Мы ограничили наш обзор решениями для рабочих станций, которые легко масштабируются и хороши для использования в небольших сетях.&lt;br /&gt;
&lt;br /&gt;
Исходя из удобства рабочих станций, мы предпочитали антивирусы с графическим интерфейсом, не обязательно супер-элегантным — просто хочется иметь точные знания, а не пытаться понять смысл сообщений, отображаемых в командной строке. Поэтому нам понравился Kaspersky Workstation — он действительно проявил заботу о пользователях Linux своими модулями Webmin.&lt;br /&gt;
&lt;br /&gt;
Разработчиков коммерческих антивирусов часто обвиняют в использовании вирусных угроз для наживания денег. Эта ситуация вполне реальна и создает благоприятную почву для развития непредвзятых open-source проектов. Такой проект — ClamAV. По функциональности он в состоянии конкурировать с другими антивирусами и, что еще важнее, его вирусная база данных очень часто обновляется, чем не могут похвастаться многие коммерческие решения.&lt;br /&gt;
&lt;br /&gt;
Открытость данного приложения имеет множество других выгод, особенно когда мы имеем дело с хитрыми и безжалостными вирусописателями. Вы можете посмотреть код и свободно внести изменения в программу или, обнаружив новый вирус, записать его в вирусную базу данных ClamAV. Приложение работает, и это главное!&lt;br /&gt;
&lt;br /&gt;
== Сводная таблица ==&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;5&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
!Название||Демон||Старт по запросу||Эвристика||Нейросети||Удаленное управление||Карантин||Обновление баз||GUI||Бесплатный&lt;br /&gt;
|-&lt;br /&gt;
!Grisoft AVG&lt;br /&gt;
|{{ok}}||{{ok}}||{{ok}}|| || || ||{{ok}}|| ||&lt;br /&gt;
|-&lt;br /&gt;
!BitDefender&lt;br /&gt;
|{{ok}}||{{ok}}||{{ok}}||{{ok}}|| ||{{ok}}||{{ok}}|| ||{{ok}}&lt;br /&gt;
|-&lt;br /&gt;
!ClamAV&lt;br /&gt;
|{{ok}}||{{ok}}|| || || ||{{ok}}||{{ok}}||{{ok}}||{{ok}}&lt;br /&gt;
|-&lt;br /&gt;
!F-Prot&lt;br /&gt;
|{{ok}}||{{ok}}||{{ok}}|| || || || || ||{{ok}}&lt;br /&gt;
|-&lt;br /&gt;
!F-Secure&lt;br /&gt;
| ||{{ok}}||{{ok}}|| ||{{ok}}||{{ok}}||{{ok}}||{{ok}}||&lt;br /&gt;
|-&lt;br /&gt;
!Interscan VirusWall&lt;br /&gt;
| ||{{ok}}|| || ||{{ok}}||{{ok}}||{{ok}}||{{ok}}||&lt;br /&gt;
|-&lt;br /&gt;
!Kaspersky&lt;br /&gt;
|{{ok}}||{{ok}}||{{ok}}|| ||{{ok}}||{{ok}}||{{ok}}||{{ok}}||&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF74-75:%D0%A1%D1%80%D0%B0%D0%B2%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5</id>
		<title>LXF74-75:Сравнение</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF74-75:%D0%A1%D1%80%D0%B0%D0%B2%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5"/>
				<updated>2008-05-18T18:44:49Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: Новая: __NOTOC__  == Антивирусы ==  ''Грэм Моррисон (Graham Morrison) облачился в белый халат Linux Format для лабораторного иcсле...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
&lt;br /&gt;
== Антивирусы ==&lt;br /&gt;
&lt;br /&gt;
''Грэм Моррисон (Graham Morrison) облачился в белый халат Linux Format для лабораторного иcследования мира быстроразвивающихся антивирусных программ.''&lt;br /&gt;
&lt;br /&gt;
Пользователям Linux всегда говорили, что им нечего волноваться из-за вирусов. Это утверждение считалось верным, поскольку Linux не привлекает хакеров, пишущих вирусы под Windows. Так-то оно так… но нет на свете способа, который остановит грамотно нацеленного «врага». В некоторых дистрибутивах, предоставляющих доступ к root для обычных нужд пользователя, деструктивные скрипты или пара переставленных строк в пользовательской программе могут причинить довольно серьезный ущерб.&lt;br /&gt;
&lt;br /&gt;
Само по себе желание встретить опасность в полной боевой готовности, однако, не объясняет того количества и качества высокоспециализированных антивирусных средств, что доступны для Linux, Дело в том, что изначально они создавались не столько для защиты самого Linux, сколько для других операционных систем. Благодаря повсеместному использованию на почтовых серверах, Linux — идеальная платформа для проверки почты на наличие вирусов перед ее отправкой другим, более уязвимым системам.&lt;br /&gt;
&lt;br /&gt;
По этой причине большинство рассматриваемых в данном обзоре программ стоят немалых денег, а фирмы, обычно упоминавшие Linux лишь походя (например, F-Secure или Kaspersky Lab), взялись за перевод сложных алгоритмов сканирования и управления базами данных на открытую ОС. Антивирусы, однако, не являются чисто коммерческой вотчиной. Единственный открытый пакет, который мы здесь рассмотрим — ClamAV — вполне способен отработать свой хлеб.&lt;br /&gt;
&lt;br /&gt;
Чтобы пакет удостоился места в данном Сравнении, он должен был обнаружить все вирусы, которые мы на него напустили. Функциональность у всех пакетов примерно одинаковая. У большинства из них — консольный интерфейс для управления сканированием и предоставлением отчета о найденных вирусах, практически все используют один и тот же модуль ядра, Dazuko, позволяющий производить сканирование в режиме реального времени. Итак, найти различия между ними будет довольно трудно. Все приложения имеют очень похожие вирусные базы, и чтобы выявить, какое же из них все-таки лучше, мы сконцентрировались на индивидуальных преимуществах, будь то эффективность эвристического анализа или наличие удобного графического интерфейса.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;toc&amp;quot;&lt;br /&gt;
!Наши конкурсанты&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
* [[#AVG Anti-Virus|AVG Anti-Virus]]&lt;br /&gt;
* [[#BitDefender|BitDefender]]&lt;br /&gt;
* [[#ClamAV|ClamAV]]&lt;br /&gt;
* [[#F-Prot Anti-Virus|F-Prot Anti-Virus]]&lt;br /&gt;
* [[#F-Secure Anti-Virus Linux Workstation|F-Secure Anti Virus]]&lt;br /&gt;
* [[#Interscan VirusWall|Interscan VirusWall]]&lt;br /&gt;
* [[#Kaspersky Workstation|Kaspersky Workstation]]&lt;br /&gt;
|-&lt;br /&gt;
! [[#Вердикт|Вердикт]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== AVG Anti-Virus ==&lt;br /&gt;
[[Изображение:LXF74-75 AVG-1.png|thumb|AVG в Bash выглядит не особо эффектно.]]&lt;br /&gt;
''Хорошо известный кросс-платформенный антивирус.''&lt;br /&gt;
* Версия: 7.1&lt;br /&gt;
* Сайт: http://www.grisoft.com &lt;br /&gt;
* Цена: $40 на один сервер&lt;br /&gt;
&lt;br /&gt;
Grisoft хорошо известны в мире антивирусов благодаря бесплатной версии антивирусного ПО для платформы Windows. Бесплатная версия имеет ряд серьезных ограничений, поскольку предназначена для частного некоммерческого использования, но сам факт ее существования уже радует. На фоне мрачных пророчеств об ожидаемой эпидемии вирусов и почтовых червей, Grisoft недавно объявил о выпуске версии своего антивируса для платформы Linux, но предлагает также целый класс коммерческих решений, нацеленных на сканирование почты.&lt;br /&gt;
&lt;br /&gt;
Установка проста, благодаря RPM, и программа довольно удобна в использовании. В нее входит две небольших утилиты, одна для сканирования файлов, а другая для обновления вирусной базы. Их комбинация предоставляет максимально гибкое средство для написания своих собственных решений, и AVG является хорошим выбором для оперативного слежения за последними уязвимостями.&lt;br /&gt;
&lt;br /&gt;
Алгоритм сканирования довольно быстр, эффективен и имеет множество настроек. Сканирование на наличие вирусов включает в себя тот же самый эвристический алгоритм, что и другие программы Grisoft. Опасные участки кода запускаются на виртуальной машине, после чего AVG пытается определить, действительно ли код опасен. Преимущество этого метода — возможность идентифицировать новые вирусы до того, как они появятся в базе данных, но есть и недостаток — ограниченное число атак, которые распознаются эвристическим алгоритмом.&lt;br /&gt;
&lt;br /&gt;
AVG — неплохая программа, и, что немаловажно, умеет автоматически обновлять вирусные базы: достойное решение для малого или среднего бизнеса.&lt;br /&gt;
&lt;br /&gt;
Сильной стороной производителя является широкая линейка продуктов (Grisoft использует один и тот же алгоритм во всех своих антивирусах), а также наличие свободной версии для Linux.&lt;br /&gt;
&lt;br /&gt;
К тому же открытый подход к разработке ПО помогает добиться главного — доверия пользователя.&lt;br /&gt;
&lt;br /&gt;
=== Вердикт Linux Format ===&lt;br /&gt;
Стоит денег, но может оказаться полезен в определенной ситуации&lt;br /&gt;
: '''Рейтинг: 6/10'''&lt;br /&gt;
&lt;br /&gt;
== BitDefender Linux Edition ==&lt;br /&gt;
[[Изображение:LXF74-75 BitDefender-1.png|thumb|Красивое имя — BitDefender, но выглядит он довольно серенько.]]&lt;br /&gt;
''Хорошая поддержка, бесплатный продукт, красивое название.''&lt;br /&gt;
* Версия: 9&lt;br /&gt;
* Сайт: http://www.bitdefender.com &lt;br /&gt;
* Цена: Бесплатен для персонального использования&lt;br /&gt;
&lt;br /&gt;
BitDefender получил наши голоса за хорошее название. Оно звучит динамично, колоритно и волнующе. Подобно AVG, свободная версия является простой командной утилитой, которую можно вызывать из скриптов или запускать по запросу. В данном обзоре это самый простой антивирус, причем на качестве его простота не сказывается отрицательно.&lt;br /&gt;
&lt;br /&gt;
Установка программы элементарна, благодаря использованию RPM, но на процесс установки особо не повлияешь. Все, что вы получаете после установки — одну команду, прописанную в системных путях под названием bdc. Первым делом обновите вирусную базу — и удивитесь, потому как на команду bdc -update последует сообщение «Нет доступных обновлений». Вы, конечно, подумаете «вот какая у меня свежая вирусная база», но на самом деле вы просто подали команду, не имея нужных привилегий.&lt;br /&gt;
&lt;br /&gt;
Это пример некорректного сообщения об ошибке, которое может ввести в заблуждение, и BitDefender не мешало бы стать в этом плане более информативным. Попутно заметим, что команду следует набирать аккуратно и случайно не набрать bcd, которая выполняет абсолютно другие функции (вы будете смеяться, когда она преобразует стандартный ввод в код перфокарт ASCII).&lt;br /&gt;
&lt;br /&gt;
BitDefender — быстрый и эффективный сканер, хорошо поддерживаемый, легкий в использовании. Он без особых проблем вписывается в скрипты для проверки почты или передачи файлов, отчего заметно снижается вероятность заражения вирусами: не спешите с покупкой коммерческой версии программы, в которой фильтрация почты включена по умолчанию.&lt;br /&gt;
&lt;br /&gt;
BitDefender имеет право на существование, особенно если вы уже сталкивались с заражением вирусами, но в нем нет ни одной «вкусности», как в других антивирусах. Так или иначе, вирусные базы он обновляет хорошо (доказано на практике).&lt;br /&gt;
&lt;br /&gt;
=== Вердикт Linux Format ===&lt;br /&gt;
Бесплатный — и это отлично, но ничем «эдаким» не привлекает.&lt;br /&gt;
: '''Рейтинг: 4/10'''&lt;br /&gt;
&lt;br /&gt;
== ClamAV ==&lt;br /&gt;
[[Изображение:LXF74-75 ClamAV-1.png|thumb|Оболочка KlamAV для KDE — удобный интерфейс для проверки на вирусы.]]&lt;br /&gt;
''Оркестр, туш! Антивирус с открытыми исходниками!''&lt;br /&gt;
* Версия: 0.87.1&lt;br /&gt;
* Сайт: http://www.clamav.net&lt;br /&gt;
* Цена: Бесплатно, по лицензии GPL&lt;br /&gt;
ClamAV — самый известный из антивирусов (по крайней мере в open-source сообществе) в нашем Сравнении. Есть серьезные основания считать, что это единственная open-source альтернатива рассмотренным коммерческим или проприетарным продуктам. Есть, конечно, и другие проекты, но работы над ними постепенно прекращаются; а для создания хорошей защиты от вирусов надо идти в ногу со временем.&lt;br /&gt;
&lt;br /&gt;
Довольно легко понять, почему в мире open-source так мало антивирусных проектов. Проблема тут не столько в сложности написания такого рода ПО, сколько в необходимости должной поддержки после выпуска релиза, которая по силам только уж совсем фанатичным группам разработчиков. Антивирус, в котором нет своевременного обновления вирусных баз, вряд ли позволит пользователю жить спокойно.&lt;br /&gt;
&lt;br /&gt;
Хотя ClamAV — открытый проект, он преодолел все эти проблемы и поддерживается разработчиками и сообществом, которое вокруг него возникло, на должном уровне. Достаточно взглянуть на частоту обновления вирусной базы данных, чтобы понять: ClamAV действительно оперативно реагирует на современные вирусные угрозы. Каждый день в его списке появляется множество новых вирусов. Команда, отвечающая за обновление вирусной базы данных, реагирует на угрозу в течение часа после ее объявления. Такой оперативности не добились даже коммерческие антивирусы.&lt;br /&gt;
&lt;br /&gt;
В итоге — этому антивирусу доверилось множество народу. Почтовый сервер под защитой ClamAV работает в [http://SourceForge.net SourceForge.net], но список покоренных IT-фирм этим отнюдь не исчерпывается — среди них есть и достаточно мелкие, и провайдеры услуг Интернета, которые отвечают за чистоту сотен тысяч электронных писем в день.&lt;br /&gt;
&lt;br /&gt;
Немаловажное преимущество: в отличие от некоторых других исследованных нами антивирусов, ClamAV работоспособен как на рабочей станции, так и в виде компонента интегрированного корпоративного решения.&lt;br /&gt;
&lt;br /&gt;
=== Вирусная похлебка ===&lt;br /&gt;
[[Изображение:LXF74-75 ClamAV-2.png|thumb|KlamAV может автоматически настроить проверку вирусов для вашего почтового клиента]]&lt;br /&gt;
В сущности, ClamAV подобен любому из антивирусов, которые мы рассматриваем в этом обзоре. Для работы необходимо установить два пакета: один содержит несколько командных утилит для проверки файлов, другой — средства управления вирусной базой. Единственное требование ClamAV- в системе должны присутствовать инструменты работы с архивами. В принципе, они и так установлены на большинстве Linux-систем, за исключением разве что unzip и unrar. В идеале, следует завести отдельную учетную запись для демона, который запускается при обновлении базы данных утилитой Freshclam..&lt;br /&gt;
&lt;br /&gt;
Возможности программы оправдывают ожидания. Есть командная строка и сканирование по запросу, с целым букетом возможностей. Демон умеет сканировать и обновлять базу данных автоматически, что позволяет с легкостью интегрировать ClamAV и на сервер, и на рабочую станцию.&lt;br /&gt;
&lt;br /&gt;
ClamAV — убедительное свидетельство мощи модели открытых разработок: он инициировал написание огромного количества утилит на все случаи жизни, особенно жизни почтовых серверов. Множество приложений легко интегрируют ClamAV с популярными серверами — например, Postfix, Sendmail, Exim и Qmail. С другой стороны, его можно использовать для проверки на наличие вирусов в почтовых клиентах типа KMail или Evolution, просто фильтруя почту командой ClamAV.Антивирусы обычно выглядят не слишком эффектно, но открытость помогла ClamAV обрасти симпатичными графическими надстройками, включая KlamAV для KDE — с ней ClamAV смотрится не хуже коммерческого ПО.&lt;br /&gt;
&lt;br /&gt;
KlamAV позволяет манипулировать базой данных, производить сканирование на наличие вирусов и помещать сомнительные или инфицированные файлы в надежный карантин, спасая их от немедленной расправы.&lt;br /&gt;
&lt;br /&gt;
Есть и другие оболочки (для Gnome и даже Java) с аналогичной функциональностью. ClamAV — не просто open-source проект: с ним вы чувствуете себя членом сообщества. ClamAV помогает очищать Интернет от вирусов и наглядно демонстрирует, что сообщество open-source имеет в своем арсенале мощный антивирус мирового класса.&lt;br /&gt;
&lt;br /&gt;
=== Вердикт Linux Format ===&lt;br /&gt;
Продукт open source. Отличная поддержка и функциональность.&lt;br /&gt;
: '''Рейтинг: 8/10'''&lt;br /&gt;
&lt;br /&gt;
== F-Prot Anti-Virus ==&lt;br /&gt;
[[Изображение:LXF74-75 F-Prot-1.png|thumb|Термин «нейросеть» намекает на причастность к крутым разработкам.]]&lt;br /&gt;
''Очередной тяжеловес из мира Windows.''&lt;br /&gt;
* Версия: 4.6.2&lt;br /&gt;
* Сайт: http://www.f-prot.com&lt;br /&gt;
* Цена: Бесплатно для персонального использования&lt;br /&gt;
F-Prot — высококлассный и популярный антивирус, портированный для Linux и Unix платформ. Для личного применения его можно бесплатно загрузить с сайта разработчика. Сканирование вашей системы запускается из вашей любимой оболочки при помощи командной строки. Разработчики антивирусов явно поют по одним нотам, поскольку все приложения отличаются одинаковым подходом.&lt;br /&gt;
&lt;br /&gt;
F-Prot похож на всех остальных, но в нем есть серьезное упущение — вирусные базы не загружаются и не устанавливаются автоматически, целиком оставаясь на совести пользователя, который должен сам загружать вирусную базу и размещать в нужном месте системы.&lt;br /&gt;
&lt;br /&gt;
F-Prot в основном делает акцент на макровирусы и трояны. Для поиска деструктивных макросов даже предусмотрен специальный модуль. Очевидно, в вашей Linux-системе он ни к чему, если вы не используете ее как почтовый сервер для макросолюбивых приложений Windows.&lt;br /&gt;
&lt;br /&gt;
Хорошая особенность этого антивируса — алгоритм искусственного интеллекта на основе нейронной сети, очень полезный при поиске деструктивного кода. В документации о нем написано не слишком подробно, но заявлено, что алгоритм строит адаптивный образец для изучения и получения выводов.&lt;br /&gt;
&lt;br /&gt;
Сопутствующий эвристический анализ помогает отловить вирус до его появления в вирусной базе данных. F-Prot — ваш выбор, если вы опасаетесь атаки доселе неизвестных или уж очень хитрых вирусов. Можно еще кое к чему придраться. Например, при вызове списка команд для прокручивания списка надо нажимать клавишу — очевидный шаг назад к MS-DOS-версии этой программы. Выглядит несколько неестественно для людей, привыкших к перенаправлению вывода в less.&lt;br /&gt;
&lt;br /&gt;
Также выяснилось, что программа плохо работает с Linux-архивами, особенно с Bzip2 (с .tar и Zip файлами проблем нет) — еще одно указание, что F-Prot всего лишь дубль успешного продукта с другой платформы. В общем, его ниша — продвинутый анализ, в противоположность рутинной защите.&lt;br /&gt;
&lt;br /&gt;
=== Вердикт Linux Format ===&lt;br /&gt;
Скажите этак небрежно «нейросеть», — и все будут думать: «Вот это да!».&lt;br /&gt;
: '''Рейтинг: 6/10'''&lt;br /&gt;
&lt;br /&gt;
== F-Secure Anti-Virus Linux Workstation ==&lt;br /&gt;
[[Изображение:LXF74-75 F-Secure-1.png|thumb|Даже после базовой установки можно настраивать множество опций.]]&lt;br /&gt;
''Интересный интерфейс пользователя.''&lt;br /&gt;
* Версия: 4.52&lt;br /&gt;
* Сайт: http://www.f-secure.com &lt;br /&gt;
* Цена: $150&lt;br /&gt;
F-Secure отличается от соперников тем, что больше подходит для предприятий, чем для рабочей станции. Оболочка к антивирусу даже имеет соответствующее корпоративно-звучащее название — Policy Manager.&lt;br /&gt;
&lt;br /&gt;
Policy Manager состоит из клиента и сервера. Впервые запуская сервер, вы должны будете ответить на несколько вопросов о конфигурации, например, как часто обновлять вирусные базы (от «ежедневно» до «ежечасно»). После этого сервер будет работать в фоновом режиме.&lt;br /&gt;
&lt;br /&gt;
Работа ведется через Policy Manager Console — Java-интерфейс пользователя к антивирусу и всем связанным с F-Secure продуктам. Из консоли можно сканировать файлы, изменять политику сканирования и обновлять базу данных, да еще решать добрую сотню других задач, естественных для категории «антивирус». К счастью, предусмотрена упрощенная обзорная панель, оформленная как web-страница.&lt;br /&gt;
&lt;br /&gt;
Огромный плюс этой программы — наличие превосходной документации в PDF-формате. Этим часто пренебрегают другие производители антивирусов, особенно открытых. Руководство администратора успешно справилось с описанием главных угроз и дает подробные указания по правильной настройке программы.&lt;br /&gt;
&lt;br /&gt;
F-Secure в общем состоит из того же набора утилит, что и конкуренты (сканер, демон и менеджер обновлений), но выделяется на их фоне благодаря Policy Manager. Пожалуй, он больше подходит для крупных корпоративных сетей, чем для нескольких машин, так как для них будет чересчур сложен.&lt;br /&gt;
&lt;br /&gt;
=== Вердикт Linux Format ===&lt;br /&gt;
Для одиночной машины — перебор; зато это отличное решение для для маленьких сетей.&lt;br /&gt;
: '''Рейтинг: 7/10'''&lt;br /&gt;
&lt;br /&gt;
== InterScan VirusWall ==&lt;br /&gt;
[[Изображение:LXF74-75 F-VirusWall-1.png|thumb|VirusWall и его пользовательский web-интерфейс]]&lt;br /&gt;
''Удаленная web-утилита для тяжелой работы.''&lt;br /&gt;
* Версия: 3.81&lt;br /&gt;
* Сайт: http://www.trendmicro.com&lt;br /&gt;
* Цена: $30 за одиночную лицензию&lt;br /&gt;
По названию можно догадаться: продукт связан с программой VirusWall SMB (малый-средний бизнес). Решение SMB — это прокси-сервер для всего входящего и исходящего трафика, выполняющий намного больше функций, чем простое сканирование на наличие вирусов.&lt;br /&gt;
&lt;br /&gt;
Данная усеченная версия унаследовала множество функций своего большого брата. Она не только умеет сканировать локальные файлы, но может следить за FTP, HTTP и почтовым трафиком с файлами и вложениями, способными представлять угрозу для системы.&lt;br /&gt;
&lt;br /&gt;
У VirusWall тот же web-интерфейс, что и у SMB-версии: программа очень удобно управляется и настраивается всего на двух страницах. Забудьте возню с командными строками и собственными скриптами, гораздо проще организовать удаленное управление.&lt;br /&gt;
&lt;br /&gt;
Установка довольно мудреная — каждым компонентом приложения управляет скрипт оболочки, и иногда непонятно, что установлено, а что нет.&lt;br /&gt;
&lt;br /&gt;
В остальном — все как у всех. Можно задать расписание обновлений вирусной базы и проверки вашей файловой системы. Маловато опций, управляющих поисковым движком — например, отсутствует эвристический анализ; тем не менее VirusWall сумел определить все вирусы, которые мы ему подсунули.&lt;br /&gt;
&lt;br /&gt;
Несомненный плюс VirusWall — простота его применения в качестве прокси-сервера FTP или HTTP, который прозрачно проверяет трафик между сервером и клиентом. Если ваши потребности со временем возрастут, то его легко можно будет обновить до SMB-версии.&lt;br /&gt;
&lt;br /&gt;
Для одиночной машины данная программа слишком амбициозна. Конечно, отслеживать появление вирусов очень важно, но стоит ли из-за этого разоряться на содержание целого Web-сервера? Если у вас всего несколько машин, проще раз в день запускать обычное антивирусное приложение.&lt;br /&gt;
&lt;br /&gt;
=== Вердикт Linux Format ===&lt;br /&gt;
Неплохой выбор, если нужно удаленно управлять системой.&lt;br /&gt;
: '''Рейтинг: 6/10'''&lt;br /&gt;
&lt;br /&gt;
== Kaspersky Workstation ==&lt;br /&gt;
[[Изображение:LXF74-75 Kaspersky-1.png|thumb|Знакомый интерфейс Webmin завоюет много поклонников.]]&lt;br /&gt;
''Выдающийся антивирус из-под Окон.''&lt;br /&gt;
* Версия: 5.5&lt;br /&gt;
* Сайт: http://www.kaspersky.com&lt;br /&gt;
* Цена: $50 за одну лицензию&lt;br /&gt;
Лаборатория Касперского — известный поставщик решений для Windows — представляет Linux-версию своего антивируса. Kaspersky одним из первых обнародовал коммерческую версию антивирусного ПО для рабочих станций Linux. Workstation можно установить из RPM, tar- или Deb-архивов, затем выполнить скрипт загрузки новейших антивирусных баз, сконфигурировать «монитор», отслеживающий вредоносную активность, и — что лучше всего — обзавестись модулем Webmin.&lt;br /&gt;
&lt;br /&gt;
Webmin — популярная утилита администрирования, работающая со своим собственным Web-сервером. Она позволяет настраивать любые аспекты вашей системы: локально — при помощи Web-браузера, или удаленно — если вы разрешите, чтоб ее было видно через ваш брандмауэр. Это отличный подход к управлению антивирусным ПО, который намного приятнее и эффективнее использования командной строки.&lt;br /&gt;
&lt;br /&gt;
У Webmin имеется несколько подмодулей, для просмотра вирусов online, настройки антивируса, запуска или остановки сканирования и обновления вирусной базы данных.&lt;br /&gt;
&lt;br /&gt;
Конечно же, налицо весь джентльменский набор командных утилит, при помощи которых можно выполнить те же самые действия, что и через webmin, а также резидентный сканер и эвристический анализ. Kaspersky проверяет некоторые файлы немного медленнее, чем другие антивирусы, но при работе на одиночной машине это практически не заметно.&lt;br /&gt;
&lt;br /&gt;
Использование интерфейса Webmin весьма украшает антивирус Kaspersky. С ним удобно и просто работать (не утопаешь в море командных ключей), и он хорошо масштабируется под небольшие сети.&lt;br /&gt;
&lt;br /&gt;
Итак, еще одна солидная программа Windows весьма удачно перебралась под Linux — явное свидетельство того, что Kaspersky чувствует рынок куда лучше конкурентов.&lt;br /&gt;
&lt;br /&gt;
=== Вердикт Linux Format ===&lt;br /&gt;
Превосходная защита от вирусов с удобным интерфейсом.&lt;br /&gt;
: '''Рейтинг: 7/10'''&lt;br /&gt;
&lt;br /&gt;
== Вердикт ==&lt;br /&gt;
[[Изображение:LXF74-75 ClamAV-3.png|thumb|Победитель — ClamAV: универсальный, открытый и беспощадный к вирусам!]]&lt;br /&gt;
Из нашего обзора как минимум можно уяснить, что выбор решений очень широк. Если вам нужен простой антивирус, то любая из рассмотренных здесь программ вам более чем подойдет. Все они обнаружили наши тестовые вирусы и умеют обновлять свои вирусные базы.&lt;br /&gt;
&lt;br /&gt;
Если вас не устраивают рассмотренные программы — приглашайте эксперта. Существует множество других антивирусов, большинство из которых не хуже рассмотренных здесь, но годятся скорее для работы на крупных предприятиях.&lt;br /&gt;
&lt;br /&gt;
Мы ограничили наш обзор решениями для рабочих станций, которые легко масштабируются и хороши для использования в небольших сетях.&lt;br /&gt;
&lt;br /&gt;
Исходя из удобства рабочих станций, мы предпочитали антивирусы с графическим интерфейсом, не обязательно супер-элегантным — просто хочется иметь точные знания, а не пытаться понять смысл сообщений, отображаемых в командной строке. Поэтому нам понравился Kaspersky Workstation — он действительно проявил заботу о пользователях Linux своими модулями Webmin.&lt;br /&gt;
&lt;br /&gt;
Разработчиков коммерческих антивирусов часто обвиняют в использовании вирусных угроз для наживания денег. Эта ситуация вполне реальна и создает благоприятную почву для развития непредвзятых open-source проектов. Такой проект — ClamAV. По функциональности он в состоянии конкурировать с другими антивирусами и, что еще важнее, его вирусная база данных очень часто обновляется, чем не могут похвастаться многие коммерческие решения.&lt;br /&gt;
&lt;br /&gt;
Открытость данного приложения имеет множество других выгод, особенно когда мы имеем дело с хитрыми и безжалостными вирусописателями. Вы можете посмотреть код и свободно внести изменения в программу или, обнаружив новый вирус, записать его в вирусную базу данных ClamAV. Приложение работает, и это главное!&lt;br /&gt;
&lt;br /&gt;
== Сводная таблица ==&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;5&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
!Название||Демон||Старт по запросу||Эвристика||Нейросети||Удаленное управление||Карантин||Обновление баз||GUI||Бесплатный&lt;br /&gt;
|-&lt;br /&gt;
!Grisoft AVG&lt;br /&gt;
|{{ok}}||{{ok}}||{{ok}}|| || || ||{{ok}}|| ||&lt;br /&gt;
|-&lt;br /&gt;
!BitDefender&lt;br /&gt;
|{{ok}}||{{ok}}||{{ok}}||{{ok}}|| ||{{ok}}||{{ok}}|| ||{{ok}}&lt;br /&gt;
|-&lt;br /&gt;
!ClamAV&lt;br /&gt;
|{{ok}}||{{ok}}|| || || ||{{ok}}||{{ok}}||{{ok}}||{{ok}}&lt;br /&gt;
|-&lt;br /&gt;
!F-Prot&lt;br /&gt;
|{{ok}}||{{ok}}||{{ok}}|| || || || || ||{{ok}}&lt;br /&gt;
|-&lt;br /&gt;
!F-Secure&lt;br /&gt;
| ||{{ok}}||{{ok}}|| ||{{ok}}||{{ok}}||{{ok}}||{{ok}}||&lt;br /&gt;
|-&lt;br /&gt;
!Interscan VirusWall&lt;br /&gt;
| ||{{ok}}|| || ||{{ok}}||{{ok}}||{{ok}}||{{ok}}||&lt;br /&gt;
|-&lt;br /&gt;
!Kaspersky&lt;br /&gt;
|{{ok}}||{{ok}}||{{ok}}|| ||{{ok}}||{{ok}}||{{ok}}||{{ok}}||&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF74-75:%D0%96%D0%B8%D0%B7%D0%BD%D1%8C_%D0%BD%D0%B0_%D1%80%D0%B0%D0%B1%D0%BE%D1%87%D0%B5%D0%BC_%D1%81%D1%82%D0%BE%D0%BB%D0%B5</id>
		<title>LXF74-75:Жизнь на рабочем столе</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF74-75:%D0%96%D0%B8%D0%B7%D0%BD%D1%8C_%D0%BD%D0%B0_%D1%80%D0%B0%D0%B1%D0%BE%D1%87%D0%B5%D0%BC_%D1%81%D1%82%D0%BE%D0%BB%D0%B5"/>
				<updated>2008-05-18T14:16:35Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: Новая: {{TOCright}} ''Если нельзя, но очень хочется — то можно. А если очень хочется, но уже можно? Тогда, конечно же,...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{TOCright}}&lt;br /&gt;
''Если нельзя, но очень хочется — то можно. А если очень хочется, но уже можно? Тогда, конечно же, нужно! Так считает Петр Семилетов.''&lt;br /&gt;
&lt;br /&gt;
Многие люди жить не могут без того, чтобы настраивать то, что они часто используют. Хлебом человека не корми, а дай ему скачать новые мелодии к мобильному телефону или какой-нибудь модный скин для мультимедийного плейера. Современные рабочие столы для UNIX-подобных систем — рай для любителей настроек. Казалось бы, чего еще желать?&lt;br /&gt;
&lt;br /&gt;
Те же KDE и GNOME, первый в большей степени, второй в меньшей, позволяет изменить по вкусу оформление окон и элементов управления, выбрать обои, добавить на свои панели всякие расширения в виде апплетов. Наиболее интересным звеном тут являются апплеты. Они что-то умеют делать. Они интерактивны.&lt;br /&gt;
&lt;br /&gt;
Но вот беда — их число ограничено. Эти апплеты собраны для конкретной версии рабочего стола и идут в комплекте с ним. Хотите другие апплеты? Ищите их в сети, затем — в зависимости от степени компьютерных знаний — устанавливайте из RPM-пакета (если есть на то права доступа) или из исходных текстов (опять же, при наличии прав). Хлопотно? Да.&lt;br /&gt;
&lt;br /&gt;
Но существует и совсем другой подход. Вы знаете его. Посмотрите на браузер Firefox. Есть движок и есть дополнения, устанавливаемые локально в каталог пользователя. Что может быть удобнее?&lt;br /&gt;
&lt;br /&gt;
Именно такую концепцию взяли на вооружение разработчики двух продуктов — SuperKaramba (для KDE) и GDesklets (для GNOME). Сами по себе эти программы представляют собой движки, которые обеспечивают подключаемым к ним «темам» различные функции — отрисовку, доступ к информации о состоянии системы и так далее. А уже дело «темы»дополнения — как эту информацию отобразить. Кроме того, движки обеспечивают взаимодействие «тем» с пользователем — реакцию на щелчок мыши и прочее.&lt;br /&gt;
&lt;br /&gt;
Что до «тем», то их достаточно скачать из сети (ниже будут приведены источники) и в готовом виде подключить к движку.&lt;br /&gt;
&lt;br /&gt;
== Superkaramba — еще больше возможностей в KDE ==&lt;br /&gt;
[[Изображение:LXF74-75 Superkaramba-1.png|thumb]][[Изображение:LXF74-75 Superkaramba-2.png|thumb]]&lt;br /&gt;
Начнем обзор с SuperKaramba. Главный сайт проекта находится на http://netdragon.sourceforge.net/ А «темы» можно взять с http://kde-look.org и http://www.superkaramba.com. Правда, последний сайт долгое время не обновлялся, хотя в будущем вроде бы снова начнет. Зато на http://kde-look.org свежие «темы» появляются с завидной регулярностью. SuperKaramba, включенная в состав KDE 3.5, написана на языке C++, а скрипты в «темах» пишутся на Python. Интересующиеся разработкой собственных «тем» для SuperKaramba могут заглянуть в ее исходные тексты, в каталог examples — кроме примеров, тем лежит еще и документация к SuperKaramba API с подробным описанием функций, которые предоставляются движком.&lt;br /&gt;
&lt;br /&gt;
SuperKaramba — логическое развитие проекта Karamba (http://www.efd.lth.se/~d98hk/karamba), развитие которого остановилось весной 2003 года. Собственно говоря, SuperKaramba — это та же Karamba, но с возможностью использования в «темах» скриптов на Python. Разумеется, часть Karamba тоже претерпела кое-какие изменения. Завершая историческую тему в нашем обзоре, отметим, что корни Karamba лежат в такой программе для Windows, как Samurize (http://www.samurize.com/modules/news). Именно она была вдохновителем создания Karamba. Кстати, Samurize бесплатна. Но вернемся к SuperKaramba.&lt;br /&gt;
&lt;br /&gt;
При первом запуске нам показывают окошко с выбором «тем».&lt;br /&gt;
&lt;br /&gt;
[[Изображение:LXF74-75 Superkaramba-3.png|thumb]]&lt;br /&gt;
Кнопка ''«Get new stuff»'' предназначена для запуска браузера, позволяющего скачать из Сети новые «темы».&lt;br /&gt;
&lt;br /&gt;
Кнопка ''«Open local theme»'' вызывает окошко, в котором можно выбрать и установить «тему», находящуюся где-нибудь в локальном каталоге. При этом новая «тема» добавляется в список доступных для запуска «тем».&lt;br /&gt;
&lt;br /&gt;
Далее, чтобы нужная вам «тема» начала работу, выберите ее из списка и нажмите кнопку ''«Add to desktop»''. «Тема» появится на рабочем столе. Для правильной работы многих «тем» на рабочем столе нужны обои, причем центрированные или растянутые на весь рабочий стол, а не черепицей.&lt;br /&gt;
&lt;br /&gt;
Автоматическая загрузка «тем» при старте SuperKaramba — вопрос отдельный. Если у вас в KDE включено сохранении сессии при завершении сеанса работы, то при последующем входе в KDE, SuperKaramba «восстановится» со всеми запущенными вами ранее «темами». В противном случае вам придется запускать SuperKaramba вручную и снова выбирать «темы». Есть и другой способ.&lt;br /&gt;
&lt;br /&gt;
Можно написать скрипт, из которого запускается SuperKaramba с нужным вам набором «тем». Делается это так. В любом текстовом редакторе вроде KWrite создаем пустой документ, в нем пишем:&lt;br /&gt;
 superkaramba &amp;lt;путь к теме1&amp;gt; &amp;lt;путь к теме2&amp;gt; &amp;lt;и так далее&amp;gt;&lt;br /&gt;
&lt;br /&gt;
То есть, после SuperKaramba прописываем полные пути к темам, которые вы хотите загрузить. Сохраняем файл в $HOME/.kde/Autostart под именем, допустим, karamba.sh, заходим в свойства этого файла и ставим ему атрибут исполняемого. Теперь наш скрипт будет выполняться каждый раз при запуске KDE.&lt;br /&gt;
&lt;br /&gt;
При помещении на рабочий стол новой «темы», обратите внимание на ряд моментов. В некоторых случаях «тема» по умолчанию помещается непосредственно под окном SuperKaramba, поэтому если вы включили тему и ее не видно, то просто передвиньте окно выбора «тем». Далее, размещенная на рабочем столе «тема» перекрывает собой значки на рабочем столе. «Тему» можно передвинуть на другое место, но по умолчанию такая возможность выключена. Чтобы включить перемещение «темы», щелкните по «теме» (не в окне выбора, а на рабочем столе) правой кнопкой мыши, чтобы вызывать контекстное меню. В нем снимите галочку с пункта Toggle locked position. После этого вы можете свободно перемещать «тему».&lt;br /&gt;
&lt;br /&gt;
Некоторые «темы» имеют настройки — добраться к ним можно из того же контекстного меню, выбрав пункт Configure theme. В старых версиях SuperKaramba была возможность напрямую редактировать служебные файлы «темы» — что достигалось вызовом текстового редактора с нужным файлом. Впрочем, вам никто не мешает и сейчас открыть скрипт «темы» в чем-нибудь вроде KWrite или TEA, изменить скрипт, сохранить его и затем перезагрузить тему в SuperKaramba. Обратите также внимание на файл с расширением .theme, входящий в состав каждой «темы». Это файл, описывающий интерфейс «темы». В частности, в нем есть параметр INTERVAL, который задает промежуток между обновлениями темы — то есть как часто «тема» будет отрисовываться на рабочем столе. Значение следует писать в миллисекундах (тысячные доли секунды). Например, 3 секунды — это 3000 миллисекунд. Если частое обновление «темы» утомляет зрение или нагружает систему, попробуйте увеличить интервал обновления. Но, как я уже сказал выше, в последних версиях SuperKaramba разработчики убрали возможность прямого вызова служебных файлов «темы». Теперь все настройки «темы» доступны из отдельного, предоставляемого самой «темой», окна. А бывает, что такого окна вовсе нет. Что до интервала обновления, то предоставить такую возможность в окошке настроек разработчики почему-то забывают.&lt;br /&gt;
&lt;br /&gt;
Среди изобилия «тем» для SuperKaramba можно обратить внимание на такие, как:&lt;br /&gt;
[[Изображение:LXF74-75 Superkaramba-4.png|thumb]]&lt;br /&gt;
* '''Liquid Weather''' — пожалуй, одна из наиболее активно разрабатываемых «тем». Показывает прогноз погоды. Для нормальной работы этой «темы» не требуется постоянный доступ к Сети, поскольку информация на рабочем столе обновляется с большим промежутком — минимум один час. Также необходимо настроить «тему», указав ей код вашего города. Чтобы получить код, воспользуйтесь из контекстного меню «темы» пунктами Find location on BBC или Find location on Weather.com а затем введите полученный код, используя пункт меню Enter your location code. Ждите, пока произойдет обновление.&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
[[Изображение:LXF74-75 Superkaramba-5.png|thumb]]&lt;br /&gt;
* '''Amarokpack/Amaroker''' — эта «тема» (а точнее, набор «тем») отображает на себе информацию о воспроизводимой в плейере Amarok песне — исполнитель, название и обложку с альбома, если такая есть в базе данных Amarok. Кроме того, на «теме» находятся кнопки управления плейером. Недостатки — некоторые обложки не масштабируются к размеру «темы». Да и процессорный ресурс можно было бы поедать в меньшей степени. Хотя это зависит от того, прозрачный скин вы выбрали для Amaroker или нет.&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
[[Изображение:LXF74-75 Superkaramba-6.png|thumb]]&lt;br /&gt;
* '''Aero-G''' — набор круглых «тем»-мониторов, в числе которых — мониторы загрузки процессора, оперативное памяти, раздела подкачки и тому подобное. Минимальное потребление ресурсов, скромный и приятный внешний вид.&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
[[Изображение:LXF74-75 Superkaramba-7.png|thumb]]&lt;br /&gt;
* '''Fantastik''' — еще один монитор, достаточно легкий в плане загрузки процессора. На этот раз концепция «темы» несколько иная — все в одном. На одной панели постоянно обновляются показатели различных датчиков-мониторов. Необходимый минимум, кроме разве что температур. «Тема» поддерживает смену своего фонового изображения.&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вердикт Linux Format ===&lt;br /&gt;
* Возможности — 10/10&lt;br /&gt;
* Функционирование — 5/10&lt;br /&gt;
* Простота использования — 7/10&lt;br /&gt;
* Документация — 10/10&lt;br /&gt;
Хотите удивить друзей или коллег футуристичным интерфейсом? Поставьте SuperKaramba. Но запаситесь мощным ПК.&lt;br /&gt;
* '''Рейтинг — 8/10'''&lt;br /&gt;
&lt;br /&gt;
== Gdesklets — все цвета радуги для строгого гнома ==&lt;br /&gt;
[[Изображение:LXF74-75 Gdesklets-1.png|thumb|Окно менеджера десклетов]]&lt;br /&gt;
В отличие от SuperKaramba, где язык программирования Python служит лишь для расширения возможностей подключаемых «тем», GDesklets сама написана на Python, что в очередной раз подтверждает гибкость и пригодность этого языка для любых целей.&lt;br /&gt;
&lt;br /&gt;
Присутствие GDesklets в Сети выражено сразу двумя сайтами. Это новое место проживания программы — http://www.gdesklets.org и старое — http://gdesklets.gnomedesktop.org. Со старого сайта (хоть он и старый, но обновляется регулярно) пользователи могут скачивать десклеты — «темы»-дополнения. Запускаем GDesklets Без сомнения, естественный режим GDesklets — среда Gnome. Хотя и в том же KDE работа GDesklets не вызывает нареканий.&lt;br /&gt;
&lt;br /&gt;
После запуска GDesklets пришвартовываются в область уведомлений, то бишь в tray. Оттуда становится доступным контекстное меню. Давайте поглядим, что в нем есть интересного. Во-первых, вызов окна Настроек. Кстати, GDesklets немного русифицированы. Не полностью, нет. Но можно встретить русские названия меню и опций. Думаю, со временем их станет больше. Быть может, вашими стараниями.&lt;br /&gt;
&lt;br /&gt;
Итак, окно настроек. Тут можно выбрать текстовый редактор, который используется для просмотра и редактирования (если возникнет такое желание) исходного кода десклетов. Далее, можно включить поддержку Xcomposite, если он у вас работает. А если не работает, и вы не знаете, что это такое, то вот вам в двух словах: технология Composite — это такая надстройка над графической системой. Composite как бы перехватывает отрисовку всех окон и рисует их все в эдаком виртуальном экране, который затем уже выводится на экран физический. Это позволяет ему, Composite’у, рисовать окна с разными красивыми тенями, делать окна полупрозрачными и так далее. Я пробовал Composite при аппаратном 3D-ускорении на Radeon 8500 — тормозит.&lt;br /&gt;
&lt;br /&gt;
Еще в окне настроек GDesklets можно выставить разрешение экрана, включить/выключить иконку для tray (по умолчанию она включена), а также выбрать сочетание клавиш для «плавающего» (floating) режима десклетов. По умолчанию это [Shift][F12]. А что за «плавающий» режим такой? Нажимаем [Shift]-[F12], и все десклеты отображаются поверх всех открытых окон. Нажимаем то же сочетание клавиш, и окна «погружаются» обратно на рабочий стол.&lt;br /&gt;
&lt;br /&gt;
Подключение десклетов В контекстном меню находим пункт «Управление апплетами». Взору нашему является окно со списком установленных десклетов, причем расфасованных по тематическим категориям. Между прочим, чтобы установить новую тему, можно перенести ссылку на нее из браузера в это окно. Или же перетащить из Nautilus архив с десклетом — его даже не надо распаковывать в отдельную директорию. Чтобы поместить десклет на рабочий стол, дважды щелкните по нему в списке и сместите мышь на рабочий стол. Мышь теперь крепко держит в своих острых зубах десклет. Выберите место и отпустите над ним клавишу мыши. Мышь разожмет свою виртуальную пасть и выпустит десклет, который сразу же приклеится к рабочему столу. В будущем, чтобы переместить десклет, нажмите над ним среднюю кнопку мыши (либо правую и левую кнопки, если мышь двухкнопочная) и свободно двигайте мышь на новое место рабочего стола.&lt;br /&gt;
&lt;br /&gt;
Удалить же десклет можно из контекстного меню, присущего каждому десклету. Выберите из такого меню пункт Remove desklet, и неугодный вам десклет исчезнет. А еще десклеты, во всяком случае многие из них, имеют окно настроек. Вызывается оно из того же контекстного меню, только пунктом Configure desklet. Если окна настроек у десклета нет, то оно и не появится. И наоборот. Давайте посмотрим теперь на некоторые интересные десклеты.&lt;br /&gt;
[[Изображение:LXF74-75 Gdesklets-2.png|thumb]]&lt;br /&gt;
* '''Clock/date display''' — простой, но вместе с тем весьма удобный и не требующий особых системных ресурсов десклет, который отображает часы (в аналоговом и цифровом виде) и дату.&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
[[Изображение:LXF74-75 Gdesklets-3.png|thumb]]&lt;br /&gt;
* '''Juju Countdown'''. Этот десклет отображает информацию о том, сколько дней и времени осталось до заданной вами даты. При достижении даты появляется написанное вами сообщение. Получается весьма наглядно, если вы ждете какой-либо «день икс».&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
[[Изображение:LXF74-75 Gdesklets-4.png|thumb]]&lt;br /&gt;
* '''Ebichu Clock''' — просто очень красивый «аналоговый» хронометр, чем-то напоминающий большие и круглые часы, что устанавливали на вокзалах провинциальных городков. Только на Ebichu Clock вдобавок еще изображен мультипликационный герой Ebichu.&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
[[Изображение:LXF74-75 Gdesklets-5.png|thumb]]&lt;br /&gt;
* '''Ephemeride'''. Еще один календарь, зато какой! Выглядит будто отрывной. Отрывать листки, конечно же, нельзя. Зато можно настроить цвета (дня недели, числа, месяца и года) и размер.&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
[[Изображение:LXF74-75 Gdesklets-6.png|thumb]]&lt;br /&gt;
* '''FTB''' — набор лаконичных, выполненных в одном стиле десклетов разного назначения. Больше десяти штук. Отличаются невысоким потреблением ресурсов. Среди FRB-десклетов есть мониторы процессора, расхода памяти и дискового пространства, сетевого трафика, аналоговые и цифровые часы. Очень рекомендую использовать весь пакет.&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вердикт Linux Format ===&lt;br /&gt;
* Возможности — 10/10&lt;br /&gt;
* Функционирование — 10/10&lt;br /&gt;
* Простота использования — 9/10&lt;br /&gt;
* Документация — 8/10&lt;br /&gt;
GDesklets будет органично дополнять ваш рабочий стол, если дополнения-десклеты не проявят свой норов сообщениями об ошибках.&lt;br /&gt;
* '''Рейтинг — 8/10'''&lt;br /&gt;
&lt;br /&gt;
== Стабильность и ресурсопотребление ==&lt;br /&gt;
[[Изображение:LXF74-75 GKRellm-1.png|thumb]]&lt;br /&gt;
Оба продукта — SuperKaramba и GDesklets — достаточно требовательны к системным ресурсам. Вернее, не сами эти программы, а их дополнения. Среди них вполне можно обнаружить такие, что потребляют даже 99 процентов вычислительных ресурсов процессора. Но это в крайнем случае, хотя многие «мониторы» преспокойно отъедают 15 процентов ресурсов на процессоре в 3 ГГц. При вдумчивом подходе к выбору активных дополнений можно настроить SuperKaramba и GDesklets, чтобы на них тратилось от силы 5 процентов. Пользователям, которым такое положение вещей не по вкусу, можно рекомендовать куда более «легкую» утилиту мониторинга — GKRellm.&lt;br /&gt;
&lt;br /&gt;
Говоря о стабильности, следует отметить, что сами по себе SuperKaramba и GDesklets работают достаточно стабильно — я не сталкивался с «падениями» и зависаниями. Впечатление могут портить некоторые «темы»-дополнения, но это уже зависит от их разработчиков. В целом у меня сложилось впечатление, что число хорошо работающих «тем» для SuperKaramba больше, нежели десклетов для GDesklets. Но и для того, и для другого разных дополнений более чем достаточно, и каждый может подобрать себе работающую конфигурацию.&lt;br /&gt;
&lt;br /&gt;
== Заключение ==&lt;br /&gt;
Использование SuperKaramba и GDesklets может украсить рабочий стол, однако загромождение его всевозможными «темами» и десклетами вполне способно превратить быструю систему в неповоротливого бронтозавра. Всё хорошо в меру. Несколько дополнений к GDesklets или SuperKaramba, встроенных в рабочий стол, могут освободить место на панелях, где находятся аналогичные мониторы, да и визуально оживят десктоп — конечно же, если вам этого хочется.&lt;br /&gt;
&lt;br /&gt;
Остается пожелать только большей стабильности и правильной работы «тем» и десклетов, да меньшего потребления ресурсов. Тогда SuperKaramba и GDesklets наверняка будут официально включены в KDE и Gnome как незаменимыме части этих рабочих сред — как сейчас механизмы апплетов.&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/%D0%A8%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD:TOCright</id>
		<title>Шаблон:TOCright</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/%D0%A8%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD:TOCright"/>
				<updated>2008-05-18T13:54:29Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: Новая: {| align=&amp;quot;right&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;0&amp;quot; style=&amp;quot;clear:right; margin-bottom: .5em; float: right; padding: .5em 0 .8em 1.4em; background: none;&amp;quot;   | __TOC__   |}&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| align=&amp;quot;right&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;0&amp;quot; style=&amp;quot;clear:right; margin-bottom: .5em; float: right; padding: .5em 0 .8em 1.4em; background: none;&amp;quot; &lt;br /&gt;
 | __TOC__  &lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF74-75</id>
		<title>LXF74-75</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF74-75"/>
				<updated>2008-05-18T13:16:58Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: /* Обзоры */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Изображение:Lxf74-75.jpg|right|Обложка журнала]]&lt;br /&gt;
&lt;br /&gt;
== LinuxFormat 74-75, Январь 2006 ==&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
=== Обзоры ===&lt;br /&gt;
* [[LXF74-75:FireFox 1.5|LXF74-75:FireFox 1.5]]&lt;br /&gt;
Mozilla поработала на славу!&lt;br /&gt;
&lt;br /&gt;
* [[LXF74-75:Parallel Workstation 2.0|LXF74-75:Parallel Workstation 2.0]]&lt;br /&gt;
Почти что VMWare или все-таки нет?!&lt;br /&gt;
&lt;br /&gt;
* [[LXF74-75:VMware Workstation 5.5|LXF74-75:VMware Workstation 5.5]]&lt;br /&gt;
Теперь – с бесплатным «пробником»&lt;br /&gt;
&lt;br /&gt;
* [[LXF74-75:Ubuntu 5.10|LXF74-75:Ubuntu 5.10]]&lt;br /&gt;
Это что за зверушка?&lt;br /&gt;
&lt;br /&gt;
* [[LXF74-75:Slackware 10.2|LXF74-75:Slackware 10.2]]&lt;br /&gt;
Этот Linux использовал еще ваш папа&lt;br /&gt;
&lt;br /&gt;
* [[LXF74-75:Cairo|LXF74-75:Cairo]]&lt;br /&gt;
Графика для фараонов&lt;br /&gt;
&lt;br /&gt;
* [[LXF74-75:Maya 7.0|LXF74-75:Maya 7.0]]&lt;br /&gt;
И что, она лучше Blender?&lt;br /&gt;
&lt;br /&gt;
* [[LXF74-75:ThinkFree Office 3|LXF74-75:ThinkFree Office 3]]&lt;br /&gt;
Думает быстрее, чем OOo.&lt;br /&gt;
&lt;br /&gt;
* [[LXF74-75:Жизнь на рабочем столе|LXF74-75:Жизнь на рабочем столе]]&lt;br /&gt;
SuperKaramba, Gdesklets побери!&lt;br /&gt;
&lt;br /&gt;
=== Сравнение ===&lt;br /&gt;
* [[LXF74-75:Сравнение|Остановим вирусы!]]&lt;br /&gt;
&lt;br /&gt;
=== Что за штука…? ===&lt;br /&gt;
* [[LXF74-75:Что за штука...|Что такое... HIBERNATE?]]&lt;br /&gt;
Холодно, темно – пора спать!&lt;br /&gt;
&lt;br /&gt;
=== Специальный репортаж ===&lt;br /&gt;
* [[LXF74-75:Дистрибутив своими руками|LXF74-75:Дистрибутив своими руками]]&lt;br /&gt;
Возьмите полкило ядра и 100 грамм X.Org    &lt;br /&gt;
* [[LXF74-75:LXF READER AWARDS|LXF74-75:LXF READER AWARDS]]&lt;br /&gt;
Голосуйте или они никому не достанутся!&lt;br /&gt;
* [[LXF74-75:Технологии Linux-2006|LXF74-75:Технологии Linux-2006]]&lt;br /&gt;
Мы больше не можем скрывать это!&lt;br /&gt;
* [[LXF74-75:Linux обучающий|LXF74-75:Linux обучающий]]&lt;br /&gt;
Учитель! Прочти меня! &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Интервью ===&lt;br /&gt;
* [[LXF74-75:Эндрю Мортон|LXF74-75:Эндрю Мортон]]&lt;br /&gt;
Хранитель ядра в гостях у LinuxFormat&lt;br /&gt;
&lt;br /&gt;
* [[LXF74-75:В ожидании Ларри|LXF74-75:В ожидании Ларри]]&lt;br /&gt;
Лингвист-программист Ларри Уолл&lt;br /&gt;
&lt;br /&gt;
* [[LXF74-75:Первые шаги|Первые шаги в системе]]&lt;br /&gt;
Не теряйте важные файлы&lt;br /&gt;
&lt;br /&gt;
* [[LXF74-75:Gambas|Gambas напоследок]]&lt;br /&gt;
Отделяем креветок от панцирей&lt;br /&gt;
&lt;br /&gt;
* [[LXF74-75:Inkscape|Inkscape: Повелитель градиентов]]&lt;br /&gt;
Inkscape по-русски!&lt;br /&gt;
&lt;br /&gt;
* [[LXF74-75:PHP|PHP в 2 частях]]&lt;br /&gt;
# Колдуем над Google API&lt;br /&gt;
# Sprechen sie multibyte?&lt;br /&gt;
&lt;br /&gt;
* [[LXF74-75:Python|Уроки Рython]]&lt;br /&gt;
Как амебе превратиться в удава?&lt;br /&gt;
&lt;br /&gt;
=== Ответы ===&lt;br /&gt;
* [[LXF74-75:Ответы|Ответы]]&lt;br /&gt;
Поможем пользователям Mandriva&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF74-75:ThinkFree_Office_3</id>
		<title>LXF74-75:ThinkFree Office 3</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF74-75:ThinkFree_Office_3"/>
				<updated>2008-05-17T14:37:10Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: Новая: ''Мыслить свободно — считает Алекс Кокс (Alex Cox) — это значит найти офисный пакет, лишенный традиционн...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;''Мыслить свободно — считает Алекс Кокс (Alex Cox) — это значит найти офисный пакет, лишенный традиционных ограничений.''&lt;br /&gt;
{{Врезка|left|Ширина=190px|&lt;br /&gt;
Заголовок = Самое главное |&lt;br /&gt;
Содержание =Программа для 3D-моделирования и &lt;br /&gt;
рендеринга. См. также: Realsoft 3D и &lt;br /&gt;
свободное ПО, POV-Ray.&lt;br /&gt;
* '''РАЗРАБОТЧИК:''' Haansoft&lt;br /&gt;
* '''САЙТ:''' [http://www.thinkfree.com www.thinkfree.com]&lt;br /&gt;
* '''ЦЕНА:''' $49.95 (download edition)}}&lt;br /&gt;
[[Изображение:LXF74-75 ThinkFree Office 3-1.png|thumb|ThinkFree Office отказывается от излишеств ради функциональности, поэтому в нем вы найдете только нужные возможности.]]&lt;br /&gt;
Концепция одноплатформного приложения, если над ней задуматься, довольно смешна. Компилировать что-то под одну-единственную платформу — это попахивает ленью, да и оставляет большую часть мировой аудитории неохваченной. Работать в нескольких операционных системах и все время переключаться между ними не так-то просто, если вы не можете использовать одни и те же инструменты. Реальным решением этой проблемы может стать написание эффективного переносимого кода, и Java от корпорации Sun — решение ничем не хуже других. ThinkFree Office 3 — это Java-версия трех самых популярных и широко используемых офисных приложений — Microsoft Word, Excel и PowerPoint. Здесь они скопированы от всей души и во всей своей красе. ThinkFree Write, Calc и Show очень похожи на своих двойников и включают те же самые основные функции. Совершенно очевидно, что ThinkFree нацеливается напрямую на пользователей, мигрирующих с продукции компании Microsoft — по умолчанию используется формат файлов .doc, .xls and .ppt.&lt;br /&gt;
&lt;br /&gt;
=== В чем же фишка? ===&lt;br /&gt;
А фишка в том, что продается этот продукт за куда меньшую цену, чем MS Office (Standard Edition 2003 стоит $399, правда, с пакетом Outlook), а поскольку приложения легко переносимы (в настоящее время они доступны для Linux, Windows, Mac и есть даже online-версия), их привычный внешний вид может способствовать их успеху. Стоимость лицензии для школ составляет 1 доллар за машину, это намного меньше того, что запрашивает Microsoft. Благодаря одинаковому интерфейсу, те навыки, которые дети получат, работая здесь, могут быть с тем же успехом использованы в большом мире, где превалирует MS. Довольно забавно, но единственное, что вам понадобится — это Java. В качестве рекомендуемого дистрибутива называется Fedora Core, и мы можем подтвердить, что ThinkFree функционирует довольно успешно после установки Java. SUSE и Turbolinux, в которых Java установлен по умолчанию, также упоминаются в этом списке, что означает возможность работы ThinkFree Office 3 на любой платформе, где имеется Java. Совместимость с оконными менеджерами не является проблемой, так как интерфейс пакета, скопированный с Microsoft Office, полностью проприетарный и создается средствами Java, как и вся прочая графика. Естественно, это также означает, что поскольку нет ограничений по выбору операционной системы, в которой работает ThinkFree, отсутствуют и сложность установки, и «ад зависимостей». Большое удивление вызвала скорость работы. Мы не думали, что он окажется настолько быстрым: на нашем Pentium 4 3.4GHz с 512 MB RAM (Fedora Core 3), он просто летал. Прокрутка плавная, экран обновляется быстро… у нас абсолютно никаких претензий к работе движка. Создание таблиц, форматирование, вычисления и создание новых слайдов — все это происходит мгновенно. Созданный для мобильности, он тщательно проработан, и вы это чувствуете. Все три приложения имеют один и тот же основной интерфейс и работают в одном темпе.&lt;br /&gt;
&lt;br /&gt;
=== Write ===&lt;br /&gt;
[[Изображение:LXF74-75 ThinkFree Office 3-2.png|thumb|Write легко импортирует рисунки и графики и дает возможность поворачивать изображения и изменять их размеры.]]&lt;br /&gt;
ThinkFree Write, текстовый редактор, идеально подходит для ежедневного использования. Это очень полезный инструмент, не требующий особых усилий, для создания документов со сложным форматированием, с таблицами, связанными объектами, такими как, например, рисунки и линии, гиперссылками, сносками. Write работает быстро, и изображение на мониторе появляется сразу же, даже если вы сверхрезво набираете текст. Он автоматически исправляет наиболее распространенные ошибки, подчеркивает ошибки в правописании и обладает значительным словарем. А еще он — это нечто неизбежное — обладает набором отвратительных клипартов 80-х годов. Вечный бонус. Он может сохранять документы в формате PDF и Word.doc, а также в RTF, в виде чистого текста и в масштабируемых векторных форматах. Это ограниченный выбор, но зато он совместим почти со всеми приложениями. Он также неплохо открывает файлы, созданные в формате .doc с использованием других приложений, но наши тесты показали, что он не может точно воспроизводить чертежи и трехмерные объекты. Возникли и некоторые проблемы: в одном месте во время написания этой статьи, Write повис и не реагировал на ввод с клавиатуры. Сохраняйте информацию почаще, если, конечно, не хотите потренировать продукт в автовосстановлении.&lt;br /&gt;
&lt;br /&gt;
=== Calc ===&lt;br /&gt;
Calc — чудесный редактор таблиц. Правда. Он не очень сложный, но делает все настолько эффективно, что работать с ним — одно удовольствие. Поскольку у него та же структура, что и у Write, он обладает многими из его функций, и его интерфейс столь же быстр. Конечно же, Calc скопирован с Excel: и формат вычислений, и все прочее в нем идентично этой программе. Даже иконки пугающе похожи. Это хорошо. Функция создания графиков почти напрямую скопирована — и это здорово. Поддерживается более 300 типов функций Excel — исключения имеются в основном в группах инженерных и финансовых функций, поэтому подавляющее большинство рабочих книг будут открываться. Очень важно, что нет поддержки макросов MS Office. Между приложениями не происходит чрезмерного взаимодействия, однако графики, которые вы создаете, можно скопировать и вставить непосредственно в ваш документ Write или презентацию Show. Это еще один пример того, что ThinkFree Office делает достаточно, чтобы стать очень полезным.&lt;br /&gt;
&lt;br /&gt;
=== Show ===&lt;br /&gt;
Можно ли сделать это в PowerPoint? Show, скорее всего, с этим справится. Здесь можно выбирать из большого количества переходов между слайдами, и, как и остальные программы пакета, они работают хорошо даже на слабых машинах. Show отлично переводит файлы PowerPoint, а это означает, что вы легко сможете сделать вашу презентацию кросс-платформенной. Онлайн-версия позволяет вам с легкостью получать информацию с других платформ, даже если у вас не установлено соответствующее приложение. Использовать слово «новшество» в данном случае, наверное, слишком смело, учитывая тот факт, что весь пакет является производным — со всеми вытекающими последствиями. Но он гораздо умнее!&lt;br /&gt;
&lt;br /&gt;
=== Скучные заметки ===&lt;br /&gt;
{{Врезка|Ширина=300px|&lt;br /&gt;
Заголовок = Близнецы-братья|&lt;br /&gt;
Содержание =Сходство между ThinkFree Office и Microsoft Office&lt;br /&gt;
&lt;br /&gt;
[[Изображение:LXF74-75 ThinkFree Office 3-3.png|300px]]&amp;lt;br /&amp;gt;&lt;br /&gt;
Show действительно отлично работает, обеспечивая поддержку формата РРТ и одинаково хорошо справляется с анимацией и статичными слайд-шоу. Можно даже сделать экспорт в формат PDF, что вовсе не так легко достижимо в Powerpoint.&lt;br /&gt;
&lt;br /&gt;
[[Изображение:LXF74-75 ThinkFree Office 3-4.png|300px]]&amp;lt;br /&amp;gt;&lt;br /&gt;
Большие директора вряд ли впадут в панику, столкнувшись со знакомым интерфейсом Calc. Это — самый близкий клон всего набора, что действительно о чем-то говорит. Вряд ли вам удастся найти документ Excel, который смог бы поставить его в тупик.}}&lt;br /&gt;
&lt;br /&gt;
Клоны неизбежно вызывают некоторое раздражение, особенно у тех, кто привык к оригиналу. Некоторые свойства очень похожи на ранние версии их двойников MS или OpenOffice.org. Проверка правописания у Write, например, игнорирует апострофы, даже если вы выбрали слово из предложенного им же контекстного меню. Надо признать, мы ожидали, что ошибок будет немало, но все оказалось не настолько плохо, как могло быть. Многим это, конечно же, не понравится. Возможно, вы будете в их числе. Вы можете метать молнии на тему того, что это поделка на тему MS, что формат .doc небезопасен, что нет даже поддержки формата OpenOffice.org. Но это не OpenOffice.org — для ThinkFree даже не важно, существует ли он вообще. Если бы ОOо был инсталлирован по всему миру в количестве, подобном МS Office, возможно, ThinkFree обратил бы на него внимание. А в том виде, в котором он существует, его целью являются пользователи MS, а результат вряд ли осчастливит Linux-сообщество. Вот что настораживает: поставьте рядом ThinkFree Office и OpenOffice, и вы не увидите особой разницы, если они не выполняют какой-либо специфической задачи. Если их что-то и отличает, так это то, что ThinkFree Office больше похож на опробованный и привычный инструментарий от Microsoft.&lt;br /&gt;
&lt;br /&gt;
Ключевой разницей между обсуждаемым пакетом и ООо является легкость; систему Sun долго ругали за ее медлительность. Мы протестировали время загрузки текстовых редакторов из каждого пакета и чистой перезагрузки. ThinkFree Write загрузился относительно быстро — за 7,4 секунды, что составляет половину того времени, которое потребовалось для загрузки OpenOffice Writer на той же машине и составило 14,5 секунд. Используя Quick Launcher, мы смогли загрузить ThinkFree менее чем за пять секунд — и это впечатляет.&lt;br /&gt;
&lt;br /&gt;
Но взгляните на панели инструментов каждого из конкурирующих приложений, и вы увидите, кто из них может предложить больше. На самом деле, нет никакого сравнения между богатством выбора OpenOffice.org, или приближающегося к нему KOffice и голыми косточками ThinkFree Office. От вашего внимания не ускользнет то, что ThinkFree обладает меньшим количеством отдельных приложений, чем остальные, или то, что в него встроено меньше инструментов. Он играет в ту же игру, но при этом не располагает полным набором инструментов. Так что пока это — офисный пакет в трусах и майке.&lt;br /&gt;
&lt;br /&gt;
=== Стоит ли переживать? ===&lt;br /&gt;
В ThinkFree Office мало навороченных функций, он предпочитает им стабильность и краткость. Во многих случаях более простой интерфейс является преимуществом: в нем меньше ерунды, которой вы никогда не будете пользоваться, он меньше раздут, в нем сложнее запутаться, хотя все это может привести к проблеме с совместимостью с MS Office. Знакомый интерфейс может превратить ThinkFree Office в фантастическую первую ступеньку на пути к Linux для новичков, которые боятся слишком радикальных перемен. Да, в плане офисных приложений ThinkFree Office — это серьезный выбор, подходящий для всего, начиная с одной системы и заканчивая целой сетью. Этот пакет работает на FC3 так же хорошо, как и на Windows XP (мы проверили), если даже не лучше.&lt;br /&gt;
&lt;br /&gt;
Это не открытый пакет, не бесплатный, и даже не пытающийся стать таковым. Если вам нужно недорогое программное обеспечение, которое обладает способностями MS Office, но при этом не пугает и не требует переподготовки пользователей, то, возможно, у Haansoft есть, что вам предложить.&lt;br /&gt;
&lt;br /&gt;
=== Вердикт Linux Format ===&lt;br /&gt;
{{Врезка|Ширина=200px|&lt;br /&gt;
Заголовок = Пол считает|&lt;br /&gt;
Содержание = «Это солидная альтернатива использованию Microsoft Office через CrossOver, но как вы сможете обойтись без OpenOffice.org Base?»}}&lt;br /&gt;
* Возможности — 5/10&lt;br /&gt;
* Производительность — 7/10&lt;br /&gt;
* Простота использования — 9/10&lt;br /&gt;
* Документация — 8/10&lt;br /&gt;
Стоимость лицензий и солидная кодовая база делают ThinkFree Office серьезным соперником. Стоит попробовать.&lt;br /&gt;
* '''Рейтинг — 7/10'''&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF74-75:Maya_7.0</id>
		<title>LXF74-75:Maya 7.0</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF74-75:Maya_7.0"/>
				<updated>2008-05-16T19:48:30Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: Новая: ''Если этот релиз преследовал цель поразить нововведениями, то в нем есть все для этого, говорит Ник Ве...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;''Если этот релиз преследовал цель поразить нововведениями, то в нем есть все для этого, говорит Ник Вейтч (Nick Veitch).''&lt;br /&gt;
&lt;br /&gt;
{{Врезка|left|Ширина=190px|&lt;br /&gt;
Заголовок = Самое главное |&lt;br /&gt;
Содержание =Программа для 3D-моделирования и &lt;br /&gt;
рендеринга. См. также: Realsoft 3D и &lt;br /&gt;
свободное ПО, POV-Ray.&lt;br /&gt;
* '''РАЗРАБОТЧИК:''' Alias&lt;br /&gt;
* '''WEB:''' [http://www.alias.com www.alias.com]&lt;br /&gt;
* '''ЦЕНА:''' $7350 (или $2250 для версии Complete)}}&lt;br /&gt;
[[Изображение:LXF74-75 Maya_7.0-1.png|thumb|Сложные сцены становятся простыми, если под рукой есть Maya.]]&lt;br /&gt;
[[Изображение:LXF74-75 Maya_7.0-2.png|thumb|Обозреватель волос — новая, весьма желанная функция.]]&lt;br /&gt;
После постоянных нововведений, создается ощущение, что работая над данной версией графического 3D-пакета (кстати, одновременно была выпущена версия для Windows), команда Maya приостановилась и обратила внимание на рендеринг текста и работу с многоугольниками.&lt;br /&gt;
&lt;br /&gt;
Например, в 7-й версии появилась возможность совершить операции моделирования над текстом, а впоследствии спокойно его заменить (до этого эта возможность присутствовала лишь в некоторых конкурирующих программах). Появилась возможность вращения объектов сцены при помощи всего лишь одного инструмента, а не нескольких, как это было раньше. Появились и новые инструменты, которые по-хорошему, должны были давно уже быть, например, новый полигонный примитив — спираль, странно, что ее не было раньше (не сказать, что она часто требуется, но иногда бывает весьма кстати). Появились и нововведения, которые будут весьма полезны для художников. Тесное сотрудничество с Adobe Software позволило улучшить поддержку слоев Photoshop и сделало возможность «подписаться» на объекты Illustrator — ими можно будет оперировать непосредственно в самой программе, но они могут хранится и во внешних файлах для простоты обновления. Появление данных функций ожидалось довольно давно, но они будут полезны больше пользователям Windows, нежели Linux.&lt;br /&gt;
&lt;br /&gt;
Большая часть нововведений находятся в области динамических и визуальных эффектов. Новый мультипликационный рендерер, который имитирует ручную анимацию — это лучшее решение в своем роде. Есть множество улучшений в моделировании тканей и контроле за мехом и волосами, особенно это заметно при применении к ним динамических эффектов типа «ветер».&lt;br /&gt;
&lt;br /&gt;
=== Интерфейс ===&lt;br /&gt;
[[Изображение:LXF74-75 Maya_7.0-1.png|thumb|Проработанная кинематика человеческого тела позволяет создавать качественную анимацию.]]&lt;br /&gt;
Мы протестировали программу на одном и том же оборудовании, как под Windows, так и под Linux. В то время, как интерфейс и время рендеринга в обоих системах практически одинаковы (иногда под Linux чуть быстрее), GUI в Linux был гораздо более вялым — трудно сказать почему, но возможно из-за X.org и графических драйверов.&lt;br /&gt;
&lt;br /&gt;
Интерфейс стал выглядеть весьма неуклюже. Очевидно, что с каждым разом все труднее и труднее разместить все инструменты и опции на инструментальных панелях и меню. Здешнюю систему «полок», меню специальных операций и меню навигации по объектам пробовали облегчить, но все равно довольно часто приходится долго искать тот или иной инструмент.&lt;br /&gt;
&lt;br /&gt;
С каждой новой версией, изучение программы становится все труднее из-за растущего количества функций. Это раздражает еще и потому, что образовательная (свободно распространяемая) версия выпускается только для Windows и OS X, а выпуска ее под Linux пока в планах нет.&lt;br /&gt;
&lt;br /&gt;
Однако, с этим релизом, Maya все равно остается в центре 3D-моделирования для Linux, хотя бы потому, что является одной из немногих 3D-систем поддерживающих эту платформу для отрисовки сцен. Realsoft уже начал портировать на Linux свои 3D-пакеты, а вот LightWave и 3ds могут появиться еще не скоро…&lt;br /&gt;
{{Врезка|Ширина=190px|&lt;br /&gt;
Заголовок = Главные нововведения|&lt;br /&gt;
Содержание =* Многоугольники&lt;br /&gt;
* Поддержка Adobe Illustrator&lt;br /&gt;
* Оптимизатор сцен&lt;br /&gt;
* Кинематика тела&lt;br /&gt;
* Динамический мех&lt;br /&gt;
* «Мультяшный» шейдер&lt;br /&gt;
* Улучшенное отображение тканей}}&lt;br /&gt;
&lt;br /&gt;
=== Вердикт Linux Format ===&lt;br /&gt;
* Возможности — 9/10&lt;br /&gt;
* Производительность — 9/10&lt;br /&gt;
* Простота использования — 6/10&lt;br /&gt;
* Цена — 7/10&lt;br /&gt;
Лучший 3D-пакет, который доступен для Linux.&lt;br /&gt;
* '''Рейтинг 9/10'''&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF74-75:Cairo</id>
		<title>LXF74-75:Cairo</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF74-75:Cairo"/>
				<updated>2008-05-16T19:32:48Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: Новая: == Графическая библиотека Cairo == ''Грэм Моррисон (Graham Morrison) рассматривает один из самых ценных бриллиант...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Графическая библиотека Cairo ==&lt;br /&gt;
''Грэм Моррисон (Graham Morrison) рассматривает один из самых ценных бриллиантов в короне Gnome.''&lt;br /&gt;
&lt;br /&gt;
{{Врезка|left|Ширина=225px|&lt;br /&gt;
Заголовок = Самое главное |&lt;br /&gt;
Содержание = Масштабируемая векторная графика для виджетов и окон. &lt;br /&gt;
Аналоги: Qt Arthur, OpenVG.&lt;br /&gt;
* '''ВЕРСИЯ:''' 1.0 &lt;br /&gt;
* '''РАЗРАБОТЧИК:''' The Cairo Development &lt;br /&gt;
* '''WEB:''' http://cairographics.org&lt;br /&gt;
* '''ЦЕНА:''' Бесплатно по лицензии LGPG}}&lt;br /&gt;
[[Изображение:LXF74-75 Cairo-1.png|thumb|Cairo может больше, чем рендеринг примитивов: вот примеры композиций как с полупрозрачными, так и с непрозрачными слоями.]]&lt;br /&gt;
Cairo позволяет сделать рабочий стол Linux намного красивей. Это API для векторного рендеринга, обладающий потенциальной возможностью трансформировать все пиксельные окна и виджеты в красивые, полностью масштабируемые кривые и линии (см. статью «Что такое.. Cairo?» в [[LXF71]]). Достаточно вспомнить о кривых Безье, отображении текста со сглаживанием (antialiasing) и аффинных преобразованиях — масштабирование, поворот и сдвиг (наверняка вы видели их в Inkscape и Adobe Illustrator).&lt;br /&gt;
&lt;br /&gt;
Поскольку Cairo — это API (интерфейс прикладного программирования), он чрезвычайно полезен для разработчиков программ. Большинство пользователей не заметят эффекта от появления Cairo до тех пор, пока не появятся программы, его использующие.&lt;br /&gt;
&lt;br /&gt;
Разработку приложений, использующих Cairo, надо вести на поддерживаемом библиотекой языке программирования. По умолчанию это C. Поддерживаются также Java, Python, Perl, Ruby, а также среда .NET (соотвествующие привязки включены в состав Mono). Поддержка C++ находится в стадии разработки.&lt;br /&gt;
&lt;br /&gt;
Функции, содержащиеся в API довольно просты, но документированы на уровне простого описания структур и функций. Вам не нужно иметь каких-то специальных знаний: если вы знакомы с функциями рендеринга других API, например GTK или Qt, то быстро разберетесь, что к чему. Фактически это напоминает переход от Gimp к Scribus. Вместо того чтобы иметь дело с абсолютными значениями, вы пользуетесь курсором, который перемещается относительно предыдущей позиции.&lt;br /&gt;
&lt;br /&gt;
=== Векторная виктория ===&lt;br /&gt;
Разработчики, использующие Cairo, могут создавать графику, полностью независимую от устройств, на которые она будет выводиться, при этом заметно повышая качество вывода. Все это благодаря векторам: их можно искривлять, масштабировать и поворачивать без потери качества. Независимость от устройств позволяет использовать различные буферы для конечного рендеринга. Первый релиз официально поддерживает три таких буфера: Xlib для X Window System, рендеринг в файл изображения и Win32 для платформы Windows.&lt;br /&gt;
&lt;br /&gt;
Есть и другие буферы, которые легко можно использовать с Cairo: например, отрисовка в PDF-файл. Однако наиболее интересный из них — Glitz. Вектора используются для построения трехмерных моделей, вывод которых на экран может быть ускорен посредством OpenGL. Именно этим и занимается Glitz. Тот же принцип используется и в OS X, и потому комбинация Glitz и Cairo будет наиболее эффективна на рабочем столе Linux.&lt;br /&gt;
&lt;br /&gt;
Даже если вы не программист, то все равно не заметить появление Cairo будет довольно трудно. Он довольно активно используется в Gnome 2.12. Только взгляните на выбор цветов, в котором теперь очень плавные переходы от цвета к цвету — все это благодаря Cairo. Последний релиз движка визуализации Gecko, который будет включен в Firefox 1.5, также использует Cairo, и OpenOffice.Org, и команда Novell уже работают над Cairo-визуализацией слайдов и презентаций.&lt;br /&gt;
&lt;br /&gt;
Cairo 1.0 имеет ошибку в начертании штриховых линий и кривых, которая была исправлена в релизе 1.0.2. Cairo, фактически, находится в постоянном развитии, и каждый релиз — всего лишь шаг на длинном пути к совершенству. Но, по крайней мере, API сейчас остается постоянным, чего нельзя было сказать о версиях, предшествующих 1.0.&lt;br /&gt;
&lt;br /&gt;
=== Свободу Cairo! ===&lt;br /&gt;
[[Изображение:LXF74-75 Cairo-2.png|thumb|Cairo делает возможными плавные цветовые переходы в Gnome 2.12]]&lt;br /&gt;
У Cairo имеется и конкурент в лице Qt Arthur. Да, благодаря привычке изобретать колесо, два самых популярных рабочих стола Linux имеют два разных API для выполнения одной и тоже задачи. Arthur предлагает примерно те же возможности, что и Cairo (в том числе, ускорение через OpenGL), но поскольку компания Trolltech накладывает некоторые ограничения на использование Arthur, Cairo кажется нам лучшим выбором для открытого рабочего окружения.&lt;br /&gt;
&lt;br /&gt;
Cairo — это блестящая идея в блестящем исполнении. Независимость от устройства вывода наряду с улучшением качества выводимой графики говорит о достижении зрелости в развитии графических средств Linux. Формат SVG (Scalable Vector Graphics) становится все более и более привычным явлением, и Cairo может его без проблем использовать.&lt;br /&gt;
&lt;br /&gt;
Cairo окажет огромное влияние на будущее Gnome, особенно при использовании аппаратного ускорения. Как успешно это будет — зависит от разработчиков. Впрочем, судя по первому релизу, даже если возникнут некоторые проблемы, они не смогут помешать успеху этого замечательного инструментария.&lt;br /&gt;
&lt;br /&gt;
=== Вердикт Linux Format ===&lt;br /&gt;
* Возможности — 8/10&lt;br /&gt;
* Функционирование — 8/10&lt;br /&gt;
* Простота использования — 7/10&lt;br /&gt;
* Документация — 6/10&lt;br /&gt;
Cairo должна стать стандартным графическим API для рабочего стола Linux.&lt;br /&gt;
* '''Рейтинг — 8/10'''&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF80:MetaPost</id>
		<title>LXF80:MetaPost</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF80:MetaPost"/>
				<updated>2008-05-16T19:14:57Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: {{Цикл/MetaPost}}&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/MetaPost}}&lt;br /&gt;
== MetaPost Дополнительные главы ==&lt;br /&gt;
'''ЧАСТЬ 4 '''&lt;br /&gt;
&lt;br /&gt;
''Всё описать невозможно, но никто не запрещает попробовать.&lt;br /&gt;
'''Евгений Балдин '''представляет вашему вниманию заключительную серию учебника MetaPost.''&lt;br /&gt;
&lt;br /&gt;
Возможности META в то или иной мере уже изложены. В этой статье будут разобраны полезные приёмы, которые можно применять при кодировании картинок и описаны некоторые из стандартных пакетов, поставляемых с ''MetaPost''.&lt;br /&gt;
&lt;br /&gt;
Исходники стандартных ''MetaPost''-пакетов обычно находятся в директории '''$(TEXMF)/texmf-dist/metapost/''', а документация к ним – в директории '''$(TEXMF)/texmf-dist/doc/metapost/''', где '''$(TEXMF)''' – корневая директория для дистрибутива ''LaTeX''. Сказанное верно для T''eX Live''.&lt;br /&gt;
&lt;br /&gt;
=== Пакет boxes ===&lt;br /&gt;
''boxes ''– один из самых первых пакетов общего назначения, появившихся в ''MetaPost''. Его предназначение – рисовать простые диаграммы. Он проектировался как более изощрённая замена для пакета Брайана Кернигана ''pic ''(''man pic'').&lt;br /&gt;
&lt;br /&gt;
[[Изображение:Img 80 100 1.jpg|thumb|400px|MetaPost-конвейер]]&lt;br /&gt;
&lt;br /&gt;
С другой стороны, функциональности этого пакета достаточно для автоматической генерации достаточно сложных зависимостей. В качестве примера разберём, как была реализована диаграмма, объясняющая действие ''MetaPost''-конвейера во введении в цикл статей по ''MetaPost''. (''см. [[LXF76]]'')&lt;br /&gt;
&lt;br /&gt;
 %Файл dop.mp&lt;br /&gt;
 %в отличии от boxes здесь ещё определено окружение rboxit&lt;br /&gt;
 input rboxes;&lt;br /&gt;
 %определяем ещё один вид box'а&lt;br /&gt;
 %параметры можно передавать и так&lt;br /&gt;
 %expr - изолированные выражения&lt;br /&gt;
 %text - абсолютно всё, что передаётся&lt;br /&gt;
 vardef drawshadowed(expr dx,dy)(text t) =&lt;br /&gt;
 fixsize(t);&lt;br /&gt;
 forsuffixes s=t:&lt;br /&gt;
 fill bpath.s shifted (dx,dy);&lt;br /&gt;
 unfill bpath.s;&lt;br /&gt;
 drawboxed(s);&lt;br /&gt;
 % можно было напечатать только текст&lt;br /&gt;
 % и не рисовать рамку&lt;br /&gt;
 % draw pic(s) withcolor red;&lt;br /&gt;
 endfor;&lt;br /&gt;
 enddef;&lt;br /&gt;
 %пример boxes&lt;br /&gt;
 beginfig(2) ;&lt;br /&gt;
 numeric u;u:=1mm;&lt;br /&gt;
 %определяем box'ы&lt;br /&gt;
 %определяем box с прямыми углами&lt;br /&gt;
 boxit.a(btex \texttt{META}-картинка etex);&lt;br /&gt;
 %определяем box с закруглёнными углами&lt;br /&gt;
 rboxit.b(btex \texttt{metapost} etex);&lt;br /&gt;
 %определяем жёсткую связь между a и b&lt;br /&gt;
 b.n = a.s - (0,5u);&lt;br /&gt;
 boxit.c(btex PostScript без шрифтов etex);&lt;br /&gt;
 c.n = b.s - (0,5u);&lt;br /&gt;
 rboxit.e(btex \texttt{latex}\(+\)\texttt{dvips} etex);&lt;br /&gt;
 e.n=c.s-(20u,10u);&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;boxit.d(btex \LaTeX-&amp;lt;&amp;lt;обёртка&amp;gt;&amp;gt; etex);&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 d.e=a.w-(5u,0);&lt;br /&gt;
 boxit.g(btex eps-файл etex);&lt;br /&gt;
 g.n=e.s-(0,5u);&lt;br /&gt;
 rboxit.h(btex \texttt{mptopdf} etex);&lt;br /&gt;
 h.n=c.s-(-20u,10u);&lt;br /&gt;
 boxit.i(btex pdf-файл etex);&lt;br /&gt;
 i.n=h.s-(0,5u)&lt;br /&gt;
 %разрешаем зависимости и рисуем boxes&lt;br /&gt;
 drawshadowed(1/3u,-1/3u,a,b,c,d,e,g,h,i);&lt;br /&gt;
 pickup pencircle scaled 0.3u;&lt;br /&gt;
 %рисуем стрелки (сдвижка вида (0u,-1/3u) появилась,&lt;br /&gt;
 %так как было определено новое окружение drawshadowed)&lt;br /&gt;
 drawarrow a.s -- b.n-(0u,-1/3u);&lt;br /&gt;
 drawarrow b.s -- c.n-(0u,-1/3u);&lt;br /&gt;
 drawarrow c.s{dir -90} .. {dir -90}e.n-(0u,-1/3u);&lt;br /&gt;
 drawarrow c.s{dir -90} .. {dir -90}h.n-(0u,-1/3u);&lt;br /&gt;
 drawarrow e.s -- g.n-(0u,-1/3u);&lt;br /&gt;
 drawarrow h.s -- i.n-(0u,-1/3u);&lt;br /&gt;
 drawarrow d.s{dir -90} .. {dir 0}e.w-(1/3u,0u);&lt;br /&gt;
 endfig;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на ещё один вид цикла – forsuffixes. Эта запись позволяет разбирать произвольное число передаваемых аргументов.&lt;br /&gt;
&lt;br /&gt;
Алгоритм создания диаграммы следующий:&lt;br /&gt;
&lt;br /&gt;
• С помощью команд boxit, rboxit или circleit объявляем box. Имя box'a добавляется к команде через точку как суффикс. В данном примере определено 8 box'ов от «'''a'''» до «'''i'''» включительно.&lt;br /&gt;
&lt;br /&gt;
• Составляем уравнения связей. Через точку к именам box'ов можно добавить один из восьми суффиксов: n – север (верхняя точка), s – юг (нижняя точка), w – запад (крайняя точка рамки слева), e – восток (крайняя точка рамки справа) и sw, bw, se, sw – комбинации уже перечисленных суффиксов, которые соответствуют углам рамки&lt;br /&gt;
&lt;br /&gt;
Уравнение связи&lt;br /&gt;
&lt;br /&gt;
 b.n = a.s — (0,5u);&lt;br /&gt;
&lt;br /&gt;
можно описать следующим образом: северная (верхняя) точка box'a «b» находится ниже южной (нижней) точки box'а «a» на 5u. При составлении уравнения связей следует пользоваться только знаком равенства. Это не присваивание, а именно уравнение, которое требуется разрешить.&lt;br /&gt;
&lt;br /&gt;
• С помощью команды drawboxed нарисовать «закодированную» диаграмму. При исполнении этой команды разрешается система уравнений. По умолчанию, если не указать специально, box располагается в точке (0,0).&lt;br /&gt;
&lt;br /&gt;
• Нарисовать стрелки между элементами диаграммы. Можно пользоваться именами box'ов со стандартными суффиксами.&lt;br /&gt;
&lt;br /&gt;
Прежде чем использовать этот пакет, необходимо прочитать соответствующий раздел в руководстве пользователя по ''MetaPost ''Джона Хобби '''mpman.pdf'''.&lt;br /&gt;
&lt;br /&gt;
=== Фейнмановские диаграммы ===&lt;br /&gt;
Простота ''MetaPost ''позволяет использовать его как базу для построений более высокого порядка. Существует несколько подобных ''LaTeX''-пакетов. ''mfpic ''уже упоминался. В этом разделе описывается ещё один старейший пакет, созданный по данной технологии.&lt;br /&gt;
&lt;br /&gt;
[[Изображение:Img 80 101 1.jpg|left|thumb|350px|Простейшая фейнмановская диаграмма]]&lt;br /&gt;
[[Изображение:Img 80 101 2.jpg|rigth|thumb|350px|Раскрашенная фейнмановская диаграмма]]&lt;br /&gt;
&lt;br /&gt;
В 1995 году Торстен Охл (Torsten Ohl) представил пакет ''feynmp д''ля рисования фейнмановских диаграмм. Фейнмановские диаграммы используются для вычисления сумм большого числа вкладов от элементарных процессов. В своё время эта технология довольно сильно продвинула технику вычислений в физике высоких энергий. Её можно использовать везде, где сложный процесс описывается с помощью элементарных приближений. Пакет ''feynmp ''– это пакет ''LaTeX'', который для рисования диаграмм использует ''MetaPost''.&lt;br /&gt;
&lt;br /&gt;
Интересующий меня с целью извлечения электронной ширины J/ резонанса процесс имеет в Борновском приближении следующий вид: Это несложная диаграмма, и если не считать метки, то для её описания требуется всего пять операторов:&lt;br /&gt;
&lt;br /&gt;
 %Файл eepsiee.tex&lt;br /&gt;
 %пакет для рисования фейнмановских диаграмм&lt;br /&gt;
 \usepackage{feynmp}&lt;br /&gt;
 ...&lt;br /&gt;
 \begin{fmffile}{ee-psi-ee} %имя mp-файл&lt;br /&gt;
 \begin{fmfgraph*}(110,62) %размер диаграммы&lt;br /&gt;
 \fmfleft{ei,pi} %вершины-источники&lt;br /&gt;
 \fmfright{eo,po} %исходящие вершины&lt;br /&gt;
 \fmflabel{$e^-$}{ei} %метка источника e^-&lt;br /&gt;
 \fmflabel{$e^+$}{pi} %метка источника e^+&lt;br /&gt;
 \fmflabel{$e^+$}{po} %метка исходящей вершины&lt;br /&gt;
 \fmflabel{$e^-$}{eo} %метка исходящей вершины&lt;br /&gt;
 %линия соединяющая источники&lt;br /&gt;
 \fmf{fermion}{ei,Ji,pi}&lt;br /&gt;
 %линия соединяющие исходящее вершины&lt;br /&gt;
 \fmf{fermion}{po,Jo,eo}&lt;br /&gt;
 %Метка для начальной вершины промежуточной частицы&lt;br /&gt;
 \fmflabel{$\Gamma_{e^{+}e^{-}}$}{Ji}&lt;br /&gt;
 %Метка для конечной вершины промежуточной частицы&lt;br /&gt;
 \fmflabel{$Br_{e^{+}e^{-}}$}{Jo}&lt;br /&gt;
 %Соединительная линия&lt;br /&gt;
 \fmf{heavy,label=$J/\psi$}{Ji,Jo}&lt;br /&gt;
 \end{fmfgraph*}&lt;br /&gt;
 \end{fmffile}&lt;br /&gt;
&lt;br /&gt;
Окружение '''\begin{fmffile}''' в качестве параметра требует имя mp-файла, в который будут писать команды META. В данном примере имя файла определено как '''ee-psi-ee.mp'''. Для того, чтобы получить диаграмму, описанную в файле '''eepsiee.tex''', были проделаны следующие действия:&lt;br /&gt;
&lt;br /&gt;
 &amp;gt; latex eepsiee.tex&lt;br /&gt;
 &amp;gt; mpost ee-psi-ee.mp&lt;br /&gt;
 &amp;gt; latex eepsiee.tex&lt;br /&gt;
&lt;br /&gt;
После выполнения этих команд результат можно посмотреть с помощью программы ''xdvi ''или преобразовать dvi-файл в PostScript или pdf.&lt;br /&gt;
&lt;br /&gt;
Следующая простейшая диаграмма не имеет особого смысла. Она просто демонстрирует возможности пакета:&lt;br /&gt;
&lt;br /&gt;
«Сотрудничество» c ''MetaPost ''даёт возможность ''feynmp ''получить доступ к цвету. Цвет можно определять точно так же, как он определяется в ''MetaPost''.&lt;br /&gt;
&lt;br /&gt;
 %Файл eepsihadr.tex&lt;br /&gt;
 \begin{fmffile}{ee-psi-hadr}&lt;br /&gt;
 \begin{fmfgraph*}(110,62)&lt;br /&gt;
 \fmfleft{i1,i2}&lt;br /&gt;
 \fmfright{o1,o2}&lt;br /&gt;
 \fmflabel{$e^-$}{i1}&lt;br /&gt;
 \fmflabel{$e^+$}{i2}&lt;br /&gt;
 \fmflabel{$q^+$}{o1}&lt;br /&gt;
 \fmflabel{$q^-$}{o2}&lt;br /&gt;
 \fmf{fermion,foreground=green}{i1,v1}&lt;br /&gt;
 \fmf{fermion,foreground=red}{v1,i2}&lt;br /&gt;
 \fmf{fermion,foreground=green}{o1,v2,v3,v4,v5}&lt;br /&gt;
 \fmf{fermion,foreground=red}{v5,v6,v7,v8,o2}&lt;br /&gt;
 %изменяем натяжение (расталкиваем вершины)&lt;br /&gt;
 \fmf{heavy,label=$J/\psi$,tension=1/3,&lt;br /&gt;
 foreground=red+green}{v1,v5}&lt;br /&gt;
 \fmffreeze&lt;br /&gt;
 \fmf{gluon,foreground=blue}{v2,v8}&lt;br /&gt;
 \fmf{gluon,foreground=blue}{v3,v7}&lt;br /&gt;
 \fmf{gluon,foreground=blue}{v4,v6}&lt;br /&gt;
 \fmfv{label=$\Gamma_{e^+e^-}$}{v1}&lt;br /&gt;
 \fmfv{label=$Br_{\text{hadr}}$,label.dist=0.3w}{v5}&lt;br /&gt;
 \end{fmfgraph*}&lt;br /&gt;
 \end{fmffile}&lt;br /&gt;
&lt;br /&gt;
При создании диаграммы ''MetaPost ''пытается оптимально расположить вершины, минимизируя взвешенную сумму расстояний между ними. При оптимизации используется понятие натяжения между вершинами. По умолчанию натяжение равно 1. С помощью опции tension натяжение можно изменить. Чем меньше натяжение, тем сильнее расталкиваются вершины.&lt;br /&gt;
&lt;br /&gt;
Обычно полученная диаграмма со значениями по умолчанию не требует вмешательства в код. В случае, если результат не устраивает, достаточно, как правило, изменить натяжение для одного, максимум для двух соединений.&lt;br /&gt;
&lt;br /&gt;
Подробнейшую документацию по пакету ''feynmp ''можно найти в файле '''$(TEXMF)/texmf-dist/doc/latex/feynmf/manual.ps.gz''', где '''$(TEXMF)''' – корень дерева ''LaTeX ''(заведомо верно для ''TeXLive'').&lt;br /&gt;
&lt;br /&gt;
=== Фракталы ===&lt;br /&gt;
META, естественно, поддерживает рекурсию. Пользуясь этим, а также генераторами случайных uniformdeviate и normaldeviate, можно организовать фрактальную «лесопосадку».&lt;br /&gt;
&lt;br /&gt;
 %фрактальная лесопосадка&lt;br /&gt;
 beginfig(1) ;&lt;br /&gt;
 u:=1mm; branchrotation := 50;&lt;br /&gt;
 offset := 180-branchrotation;&lt;br /&gt;
 thinning := 0.7;&lt;br /&gt;
 shortening := 0.8;&lt;br /&gt;
 def drawit(expr p, linethickness,col) =&lt;br /&gt;
 draw p withpen pencircle scaled linethickness withcolor col;&lt;br /&gt;
 enddef;&lt;br /&gt;
 %A - основание B - направление роста, n - число бранчей,&lt;br /&gt;
 %size - толщина дерева, col - цвет&lt;br /&gt;
 vardef tree(expr A,B,n,size,col) =&lt;br /&gt;
 save C,D,thickness; pair C,D;&lt;br /&gt;
 thickness := size;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;C := shortening[B, A rotatedaround(B,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 offset+uniformdeviate(branchrotation))];&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;D := shortening[B, A rotatedaround(B,&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 -offset-uniformdeviate(branchrotation))];&lt;br /&gt;
 if n&amp;gt;0:&lt;br /&gt;
 drawit(A--B, thickness, col);&lt;br /&gt;
 thickness := thinning*thickness;&lt;br /&gt;
 tree(B, C, n-1, thickness,col);&lt;br /&gt;
 tree(B, D, n-1, thickness,col);&lt;br /&gt;
 else:&lt;br /&gt;
 drawit(A--B,thickness,col);&lt;br /&gt;
 thickness := thinning*thickness;&lt;br /&gt;
 drawit(B--C, thickness,col);&lt;br /&gt;
 drawit(B--D, thickness,col);&lt;br /&gt;
 fi;&lt;br /&gt;
 enddef;&lt;br /&gt;
 numeric nbr,nx,ny,ell,size;&lt;br /&gt;
 color col;&lt;br /&gt;
 nx:=10;ny:=5;&lt;br /&gt;
 pair A;&lt;br /&gt;
 for ix:=1 upto nx:&lt;br /&gt;
 for iy:=1 upto ny:&lt;br /&gt;
 nbr:=4+uniformdeviate 5;&lt;br /&gt;
 ell:=nbr*u;&lt;br /&gt;
 x:=ix*(1+1/20*normaldeviate);&lt;br /&gt;
 y:=iy*(1+1/20*normaldeviate);&lt;br /&gt;
 A:=(20u*(x+y*sqrt(2)/2),20u*y*sqrt(2)/2);&lt;br /&gt;
 size:=ell/5;&lt;br /&gt;
 col:=(uniformdeviate 1,uniformdeviate 1,uniformdeviate 1);&lt;br /&gt;
 show ix,iy,A,ell,nbr,size,col;&lt;br /&gt;
 tree(A, A+(0,ell), nbr, size,col);&lt;br /&gt;
 endfor;&lt;br /&gt;
 endfor;&lt;br /&gt;
 endfig;&lt;br /&gt;
&lt;br /&gt;
Увлечение автоматически создаваемыми картинами влечёт за собой опасность переполнения памяти. ''MetaPost ''создавался в то время, когда к используемой памяти относились исключительно бережно.&lt;br /&gt;
&lt;br /&gt;
Если при компиляции картинки будет выдана ошибка ''MetaPost c''apacity exceeded, то необходимо поправить файл конфигурации '''texmf.cnf'''. Обычно этот файл можно найти в директории '''$(TEXMF)/''' '''web2c/texnf.cnf'''.&lt;br /&gt;
&lt;br /&gt;
За выделяемый объём памяти для ''MetaPost ''отвечает переменная main_memory.mpost. Значение этой переменной должно быть меньше значения main_memory, которое определяет верхнюю границу использования памяти для всех TeX-подобных программ. Обратите внимание на то, что в конфигурационном файле может быть несколько переменных с одним и тем же именем – используется последнее значение.&lt;br /&gt;
&lt;br /&gt;
В моём случае ограничение по памяти составляло 15 Мб. Очевидно, что размер используемой памяти можно безболезненно увеличить. С другой стороны, если происходит переполнение, то это, возможно, значит, что в алгоритм закралась ошибка.&lt;br /&gt;
&lt;br /&gt;
После исправления значения переменных следует заново сгенерировать форматные файлы, например, с помощью команды texconfig init.&lt;br /&gt;
&lt;br /&gt;
=== Увеличительное стекло ===&lt;br /&gt;
Бывает, в процессе создания картинки необходимо увеличить участок для лучшей детализации. ''MetaPost ''предоставляет средство для этого в виде команды clip, которая позволяет обрезать картинку по любому замкнутому пути. Ниже идёт код, который позволил увеличить кусок циферблата корабельных часов.&lt;br /&gt;
&lt;br /&gt;
 %Файл dop.mp&lt;br /&gt;
 R:=3.6u;&lt;br /&gt;
 path q;&lt;br /&gt;
 %определяем форму области которую хотим вырезать&lt;br /&gt;
 q:=(-R,0)..(R,0)..cycle;&lt;br /&gt;
 %определяем центр вырезаемой области (orig)&lt;br /&gt;
 %и местоположение увеличенного участка (copy)&lt;br /&gt;
 pair orig,copy;&lt;br /&gt;
 orig=(65u,24u);copy=(45u,7.5u);&lt;br /&gt;
 %отмечаем вырезаемую область&lt;br /&gt;
 draw q shifted orig dashed evenly scaled 1/2u&lt;br /&gt;
 withpen pencircle scaled 0.2u witcholor red;&lt;br /&gt;
 picture p;&lt;br /&gt;
 %сохраняем текущую картинку в переменной p&lt;br /&gt;
 p:=currentpicture;&lt;br /&gt;
 %коэффициент увеличения&lt;br /&gt;
 numeric scale;scale:=3;&lt;br /&gt;
 %Обрезаем картинку p по замкнутому пути q&lt;br /&gt;
 clip p to (q shifted orig);&lt;br /&gt;
 %чистим область, где будет нарисована увеличенная копия&lt;br /&gt;
 fill q scaled scale shifted copy withcolor white;&lt;br /&gt;
 %рисуем копию&lt;br /&gt;
 draw p shifted -orig scaled scale shifted copy;&lt;br /&gt;
 %рисуем дополнительную стрелку и метку&lt;br /&gt;
 %на уже увеличенной копии&lt;br /&gt;
 draw copy withpen pencircle scaled 1u withcolor red;&lt;br /&gt;
 drawarrow copy--(copy+7u*dir -120)&lt;br /&gt;
 withpen pencircle scaled 0.4u withcolor red;&lt;br /&gt;
 label.lrt(btex \(\vec{u}\) etex,&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;1/3[copy,(copy+7u*dir -120)]);&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Изображение:Img 80 103 2.jpg|thumb|400px|Преобразование Галилея]]&lt;br /&gt;
&lt;br /&gt;
Пользуясь этим приёмом, можно создать любой фон для какойугодно фигуры, сделать любую штриховку.&lt;br /&gt;
&lt;br /&gt;
=== Штриховка ===&lt;br /&gt;
clip-технология, которая упоминалась выше, позволяет создать любой вид штриховки. В стандартной поставке ''MetaPost ''идут пакеты, которые этим пользуются.&lt;br /&gt;
&lt;br /&gt;
Пакет ''hatching.mp ''представляет из себя обычный «хак»:&lt;br /&gt;
&lt;br /&gt;
 %Файл dop.mp&lt;br /&gt;
 %пример использования пакета hatching&lt;br /&gt;
 input hatching;&lt;br /&gt;
 beginfig(3) ;&lt;br /&gt;
 numeric u;u=1mm;&lt;br /&gt;
 path q;&lt;br /&gt;
 q=(10u,0)..{dir -135}(0u,0u){dir 135}..&lt;br /&gt;
 (-10u,0)..{dir 90}(0u,0u){dir -90}..cycle;&lt;br /&gt;
 hatchfill q withcolor red withcolor (25,1u,-1);&lt;br /&gt;
 draw q;&lt;br /&gt;
 endfig;&lt;br /&gt;
&lt;br /&gt;
[[Изображение:Img 80 103 1.jpg|thumb|400px|Пакет hatching]]&lt;br /&gt;
&lt;br /&gt;
Функция hatchfill берёт информацию о штриховке из данных, которые следуют с декларацией withcolor. Сигналом, что эти данные предназначены именно для hatchfill, является то, что голубая компонента тройки чисел меньше 0. Красная компонента соответствует углу наклона штриховки, зелёная – расстоянию между штрихами. Подробности можно узнать в краткой документации к пакету.&lt;br /&gt;
&lt;br /&gt;
Более развитым (возможно, излишне) является пакет ''mpattern'':&lt;br /&gt;
&lt;br /&gt;
 %создаём &amp;quot;обои&amp;quot; ракета&lt;br /&gt;
 beginpattern(rocket);&lt;br /&gt;
 begingroup;save u;&lt;br /&gt;
 u:=1mm;&lt;br /&gt;
 draw Rocket scaled 2/3u rotated -30;&lt;br /&gt;
 patternbbox(-5u,-8u,5u,8u);&lt;br /&gt;
 endgroup;&lt;br /&gt;
 endpattern;&lt;br /&gt;
 %создаём &amp;quot;обои&amp;quot; повёрнутая клетка&lt;br /&gt;
 beginpattern(rotated_checker);&lt;br /&gt;
 fill unitsquare scaled 4mm rotated 45 withcolor .7white;&lt;br /&gt;
 endpattern;&lt;br /&gt;
 beginfig(4);&lt;br /&gt;
 numeric u; u:=1mm;&lt;br /&gt;
 path p;&lt;br /&gt;
 z1=(10u,0u);&lt;br /&gt;
 p=fullcircle scaled 50u;&lt;br /&gt;
 %рисуем фигуру в клетку&lt;br /&gt;
 fill p withpattern rotated_checker;&lt;br /&gt;
 unfill p shifted z1;&lt;br /&gt;
 %рисуем фигуру &amp;quot;в ракету&amp;quot;&lt;br /&gt;
 fill p shifted z1 withpattern rocket;&lt;br /&gt;
 endfig;&lt;br /&gt;
&lt;br /&gt;
[[Изображение:Img 80 103 3.jpg|thumb|400px|Пакет hatching]]&lt;br /&gt;
&lt;br /&gt;
Здесь уже определены свои команды для создания штриховки. Пакет не свободен от недостатков, но он достаточно прост, и можно легко «довести» код до необходимой кондиции. Простота – это общее свойство пакетов ''MetaPost''. META вынуждает писать кратко. Подробности можно найти в документации к пакету.&lt;br /&gt;
&lt;br /&gt;
=== Вставка eps ===&lt;br /&gt;
Пакет ''exteps.mp ''позволяет включить eps-картинку как единый объект. Краткая документация доступна в файле '''exteps.pdf''', поставляемом с этим пакетом.&lt;br /&gt;
&lt;br /&gt;
 %Файл dop.mp&lt;br /&gt;
 input exteps;&lt;br /&gt;
 %Включение eps-картинки&lt;br /&gt;
 beginfig(6) ;&lt;br /&gt;
 numeric u;u:=1mm;&lt;br /&gt;
 % базовая надпись&lt;br /&gt;
 for alpha:=-90 step 3 until 0:&lt;br /&gt;
 label(btex LinuxFormat в России etex&lt;br /&gt;
 scaled (5*(1+alpha/100)) rotated alpha,(0,0))&lt;br /&gt;
 withcolor&lt;br /&gt;
 (uniformdeviate 1,uniformdeviate 1,uniformdeviate 1);&lt;br /&gt;
 endfor;&lt;br /&gt;
 % посадим Тукса (penguin.eps) справа&lt;br /&gt;
 begineps &amp;quot;penguin.eps&amp;quot; ;&lt;br /&gt;
 % ширина картинки&lt;br /&gt;
 width:=30u;&lt;br /&gt;
 % сдвиг картинки от начала координат&lt;br /&gt;
 base:= (60u,5u);&lt;br /&gt;
 % можно нарисовать решётку на картинки&lt;br /&gt;
 % grid := true;&lt;br /&gt;
 % обрезание по bounding box&lt;br /&gt;
 % clip := true;&lt;br /&gt;
 endeps;&lt;br /&gt;
 % посадим Тукса (penguin.eps) слева&lt;br /&gt;
 begineps &amp;quot;penguin.eps&amp;quot; ;&lt;br /&gt;
 % поворот&lt;br /&gt;
 angle:=90;&lt;br /&gt;
 width:=30u;&lt;br /&gt;
 base:= (-30u,-40u);&lt;br /&gt;
 endeps;&lt;br /&gt;
 endfig ;&lt;br /&gt;
&lt;br /&gt;
=== Большие числа ===&lt;br /&gt;
Когда обсуждалась вставка меток, в качестве примера был представлен треугольник Паскаля. Из-за ограничений META на максимальный размер числа треугольник Паскаля отрисовывался до 14-й строчки.&lt;br /&gt;
&lt;br /&gt;
[[Изображение:Img 80 105 1.jpg|thumb|400px|Треугольник Паскаля]]&lt;br /&gt;
&lt;br /&gt;
Это ограничение можно обойти, воспользовавшись пакетом ''sarith.mp''. Он был создан специально для пакета ''graphics.mp'', что вполне естественно, так как если при рисовании незначительных рисунков больших чисел быть не может, то при анализе данных их наличие – вполне рядовая ситуация.&lt;br /&gt;
&lt;br /&gt;
 %Файл dop.mp&lt;br /&gt;
 %Macros for arithmetic on strings that represent big numbers&lt;br /&gt;
 input sarith;&lt;br /&gt;
 %Треугольник Паскаля с большими числами&lt;br /&gt;
 beginfig(5) ;&lt;br /&gt;
 numeric u;&lt;br /&gt;
 u = 1.mm;&lt;br /&gt;
 numeric dy,dx,x,y,i,j,sy,ds,nlast;dy:=5u;&lt;br /&gt;
 dx:=6u;x=0;y=0;nlast:=20;&lt;br /&gt;
 %для хранения больших чисел нужна строка&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;string n[][];&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 ds=0.04;sy=0.032;&lt;br /&gt;
 picture z;&lt;br /&gt;
 for i:=0 upto nlast:&lt;br /&gt;
 dy:=dy*(1-sy);&lt;br /&gt;
 y:=y-dy;&lt;br /&gt;
 for j:=0 upto i:&lt;br /&gt;
 if (j=0) or (j=i):&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;n[i][j]:=Sabs 1; %&amp;lt;/nowiki&amp;gt;сложение&lt;br /&gt;
 else:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;n[i][j]:=n[i-1][j-1] Sadd n[i-1][j]; %&amp;lt;/nowiki&amp;gt;сложение&lt;br /&gt;
 fi&lt;br /&gt;
 %формат вывода&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;z:=thelabel(format(&amp;quot;%6g&amp;quot;, n[i][j]),(0,0));&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 x:=dx*(j-i/2);&lt;br /&gt;
 label(z scaled (1-ds*i),(x,y));&lt;br /&gt;
 endfor&lt;br /&gt;
 z:=thelabel.lft(decimal(i)&amp;amp;&amp;quot;:&amp;quot;,(0,0));&lt;br /&gt;
 label(z scaled (1-ds*i),(dx*(-nlast/2-1),y));&lt;br /&gt;
 endfor&lt;br /&gt;
 endfig ;&lt;br /&gt;
&lt;br /&gt;
Для представления больших чисел используется встроенный тип string – строка.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=1&lt;br /&gt;
!style=&amp;quot;background-color:#EEEEFF;&amp;quot; |  Оператор&lt;br /&gt;
!style=&amp;quot;background-color:#EEEEFF;&amp;quot; |  Действие&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;nowiki&amp;gt;Scvnum &amp;lt;number&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
| конвертация в numric&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;nowiki&amp;gt;Sabs &amp;lt;number&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
| абсолютное значение&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;nowiki&amp;gt;&amp;lt;number&amp;gt; Sadd &amp;lt;number&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
| сложение&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;nowiki&amp;gt;&amp;lt;number&amp;gt; Ssub &amp;lt;number&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
| вычитание&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;nowiki&amp;gt;&amp;lt;number&amp;gt; Smul &amp;lt;number&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
| умножение&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;nowiki&amp;gt;&amp;lt;number&amp;gt; Sdiv &amp;lt;number&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
| деление&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;nowiki&amp;gt;&amp;lt;number&amp;gt; Sleq &amp;lt;number&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
| &amp;lt;nowiki&amp;gt;сравнение &amp;lt;=&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;nowiki&amp;gt;&amp;lt;number&amp;gt; Sneq &amp;lt;number&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
| &amp;lt;nowiki&amp;gt;сравнение &amp;lt;&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Документация к пакету sarith.mp является частью документации к&lt;br /&gt;
graphics.mp ('''mpgraph.pdf''' от Джона Хобби).&lt;br /&gt;
&lt;br /&gt;
=== Макрос TEX ===&lt;br /&gt;
Вы, наверное, уже обратили внимание, что метки в ''MetaPost ''являются статическими. Всё, что между btex и etex, отдаётся ''LaTeX ''для обработки. Это значит, что метку нельзя скомпоновать из различных кусков. Решением является немного модифицированный макрос из стандартного пакета ''TEX.mp'':&lt;br /&gt;
&lt;br /&gt;
 %Файл macros.mp&lt;br /&gt;
 vardef TEX primary s =&lt;br /&gt;
 write &amp;quot;verbatimtex&amp;quot; to &amp;quot;mptextmp.mp&amp;quot;;&lt;br /&gt;
 write &amp;quot;\input{preheader-base}&amp;quot; to &amp;quot;mptextmp.mp&amp;quot;;&lt;br /&gt;
 write &amp;quot;\begin{document}&amp;quot; to &amp;quot;mptextmp.mp&amp;quot;;&lt;br /&gt;
 write &amp;quot;etex&amp;quot; to &amp;quot;mptextmp.mp&amp;quot;;&lt;br /&gt;
 write &amp;quot;btex &amp;quot;&amp;amp;s&amp;amp;&amp;quot; etex&amp;quot; to &amp;quot;mptextmp.mp&amp;quot;;&lt;br /&gt;
 write EOF to &amp;quot;mptextmp.mp&amp;quot;;&lt;br /&gt;
 scantokens &amp;quot;input mptextmp&amp;quot;&lt;br /&gt;
 enddef;&lt;br /&gt;
&lt;br /&gt;
В процессе вызова макроса TEX всё, что находится внутри него, записывается в '''mptextmp.mp''', а затем этот файл включается в основной файл прямо во время компиляции. То есть происходит модификация программы прямо во время компиляции. Пример использования макроса приведен ниже:&lt;br /&gt;
&lt;br /&gt;
 %Файл coord.mp&lt;br /&gt;
 numeric u;u:=2mm;&lt;br /&gt;
 for i:=-15 step 5 until 15:&lt;br /&gt;
 label.lft(TEX(&amp;quot;\(&amp;quot;&amp;amp;decimal(i)&amp;amp;&amp;quot;\)&amp;quot;),(-10u,i*u));&lt;br /&gt;
 endfor;&lt;br /&gt;
&lt;br /&gt;
При формировании ASCII-строчки использовался оператор &amp;amp; для объединения. Хотя в данном случае можно было обойтись только статическими записями, но иногда этот приём может пригодиться для целей автоматизации, где скорость компиляции – не главное.&lt;br /&gt;
&lt;br /&gt;
Основной минус этого способа в том, что он очень «мееедленный». Для ускорения следует оставить в '''preheader-base.tex''' только самые необходимые инструкции. Что-то вроде:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;\documentclass[12pt]{article}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;\usepackage[warn]{mathtext}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;\usepackage[T2A]{fontenc}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;\usepackage[koi8-r]{inputenc}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;\usepackage[english,russian]{babel}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Заключение ===&lt;br /&gt;
Естественно, в таком кратком обзоре невозможно рассказать всё. Основные понятия и приёмы уже изложены, но множество вещей выпало из обзора. В частности, совсем не рассмотрены 3D объекты, создание геометрических чертежей, параметризация пути и векторные поля в M''etaPost''. Это не смертельно, так как есть весьма качественная свободная литература, посвящённая этим предметам.&lt;br /&gt;
&lt;br /&gt;
''MetaPost ''достаточно легко использовать после обучения, но обучение перед использованием просто необходимо. Это свойство всех стоящих технологий, которые позволяют делать то, для чего компьютеры и существуют: автоматизировать рутинные действия, для выполнения которых не требуется задумываться. Думать же, в любом случае, прерогатива человека.&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF79:MetaPost</id>
		<title>LXF79:MetaPost</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF79:MetaPost"/>
				<updated>2008-05-16T19:14:49Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: {{Цикл/MetaPost}}&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/MetaPost}}&lt;br /&gt;
''Даже жизнь можно отобразить в виде графика функции от времени. '''Евгений Балдин''' расскажет, как выразить это на языке Metapost.''&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
Отображение данных на бумаге всегда было и останется нетривиальным процессом. Несмотря на то, что получение данных, как правило, занимает гораздо больше ресурсов, задача оформления графиков достойна автоматизации. В частности, автоматизация позволяет один раз придумать, как представить данные наилучшим образом, и в дальнейшем не снижать уровень оформления.&lt;br /&gt;
&lt;br /&gt;
По-хорошему, графики следует создавать в специализированных приложениях. Автоматизация этого процесса достаточно специфична, чтобы реализовывать его с помощью программ, не предназначенных только для этого. Если вам нужны двумерные графики, то никто не справится с этим лучше чем gnuplot. Если вас интересуют гистограммы, то это работа для пакетов анализа paw/cernlib или root. Но если вам хочется разукрасить график, то MetaPost будет для этого очень кстати.&lt;br /&gt;
&lt;br /&gt;
Ничего не мешает нарисовать график самостоятельно. Всё, что для этого нужно:&lt;br /&gt;
* знать диапазон функции и её аргумента,&lt;br /&gt;
* нарисовать оси координат,&lt;br /&gt;
* создать сетку и поставить метки на осях,&lt;br /&gt;
* изобразить функцию.&lt;br /&gt;
&lt;br /&gt;
[[Изображение:Img 79 109 1.jpg|thumb|Иллюстрация для объяснения понятия дифференцирования]]&lt;br /&gt;
&lt;br /&gt;
В этом смысле кодирование графика ничем не отличается от кодирования рисунка – нужно лишь уметь рисовать стрелки и линии. Однако это годится только для простых графиков. Графики в MetaPost Для серьёзной работы с графиками в MetaPost есть довольно продвинутый пакет graph.mp. Этот пакет написан «отцом» MetaPost Джоном Хобби, и к нему прилагается подробная документация, которую можно найти в стандартной поставке LaTeX в виде файла mpgraph.pdf. Если вы планируете воспользоваться этим пакетом, то прежде изучите этот текст.&lt;br /&gt;
 %Файл graphics.mp&lt;br /&gt;
 input graph;&lt;br /&gt;
 %График переменной скорости - тема &amp;quot;дифференцирование&amp;quot;&lt;br /&gt;
 beginfig(2) ;&lt;br /&gt;
  numeric u;&lt;br /&gt;
  u = 0.6mm;&lt;br /&gt;
  %начало графика&lt;br /&gt;
  draw begingraph(12cm,3cm);&lt;br /&gt;
   path r;&lt;br /&gt;
   numeric e,pi,A,sigma,n,scale,mean,y[],x[];&lt;br /&gt;
   e:=2.718;pi:=3.14159;A=50;&lt;br /&gt;
   sigma=1.4;n:=100;scale=10;mean=5;&lt;br /&gt;
   %создание функции - она использовалась не один раз&lt;br /&gt;
   for j:=0 upto n:&lt;br /&gt;
    if (j=0):&lt;br /&gt;
               x[0]=0;y[0]=0;&lt;br /&gt;
    else:&lt;br /&gt;
               x[j]:=scale*j/n;&lt;br /&gt;
               y[j]:=y[j-1]+A*(e**(-(((scale*j/n-mean)/(1.41*sigma))**2)))*&lt;br /&gt;
               (x[j]-x[j-1])/(sqrt(2*pi)*sigma);&lt;br /&gt;
    fi&lt;br /&gt;
   endfor;&lt;br /&gt;
   %здесь нужна функция из отрезков, поэтому step 6&lt;br /&gt;
   r:=(0,0)for j:=0 step 6 until (n-1):&lt;br /&gt;
     --((2,0)+(x[j],y[j])) endfor ..(12,50)--(15,50);&lt;br /&gt;
   %отрисовка функции&lt;br /&gt;
   gdraw r withpen pencircle scaled 0.8u;&lt;br /&gt;
   %сетка&lt;br /&gt;
   autogrid(grid.bot,grid.lft) withcolor .5white;&lt;br /&gt;
   %дополнительные метки на оси абсцисс&lt;br /&gt;
   otick.bot(btex 2\,\text{с} etex,2);&lt;br /&gt;
   otick.bot(btex 12\,\text{с} etex,12);&lt;br /&gt;
   %текст и стрелка за пределами графика&lt;br /&gt;
   gdrawdblarrow (2,-20)--(12,-20)&lt;br /&gt;
            withpen pencircle scaled 0.5u;&lt;br /&gt;
   glabel.top(btex \(T=10\,\text{с}\) etex,(7.5,-20));&lt;br /&gt;
   gdrawdblarrow (13.5,0)--(13.5,50)&lt;br /&gt;
            withpen pencircle scaled 0.5u;&lt;br /&gt;
   %текстовые метки внутри графика&lt;br /&gt;
   glabel.lft(btex \(S=50\,\text{м}\) etex&lt;br /&gt;
          rotated 90, 1/2[(13.5,0),(13.5,50)]);&lt;br /&gt;
   glabel.rt(btex \(v(t)=\frac{dx(t)}{dt}\) etex&lt;br /&gt;
                 scaled 1.3,(0,25));&lt;br /&gt;
   glabel(btex \(dx\) etex,(11.1,20)) ;&lt;br /&gt;
   glabel(btex \(dt\) etex,(10,9)) ;&lt;br /&gt;
   %подписи к осям&lt;br /&gt;
   glabel.rt(btex Время (с) etex,(13,-20)) ;&lt;br /&gt;
   glabel.lft(btex Расстояние (м) etex rotated 90,OUT) shifted (0cm,0.5cm);&lt;br /&gt;
  endgraph;&lt;br /&gt;
 endfig ;&lt;br /&gt;
&lt;br /&gt;
В graph.mp определено специальное окружение. Между begingraph и endgraph действует своя система координат. Она привязана не к геометрическим размерам картинки, а к диапазону осей графика. То есть точка (0,0) соответствует точке пересечения оси абсцисс и оси ординат графика. Размер создаваемого графика указывается сразу после begingraph.&lt;br /&gt;
&lt;br /&gt;
Вместо стандартных команд draw, fill, label и dotlabel используются gdraw, gfill, glabel и gdotlabel, соответственно. Новые команды работают с учётом координат графика. С их помощью можно построить функцию именно по точкам, не заботясь о сдвигах и тому подобном. Для подписи осей существует специальная точка OUT, которая в зависимости от суффикса команды glabel выносит текст за пределы основной сетки.&lt;br /&gt;
&lt;br /&gt;
Функция «отрисовывается» точно так же, как любая из кривых: создаётся путь, который затем выводится с помощью команды gdraw.&lt;br /&gt;
&lt;br /&gt;
Для фиксации диапазона графика используется команда: setrange(&amp;quot;нижний левый угол&amp;quot;,&amp;quot;верхний правый угол&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
При вызове этой инструкции все последующие функции работают в указанном диапазоне. Таким образом, используя одно и то же пространство, можно совместить несколько графиков, имеющих различный диапазон аргументов и функций. Шкалу графика можно сделать логарифмической с помощью инструкции setcoord:&lt;br /&gt;
 %x- линейная шкала, y - логарифмическая&lt;br /&gt;
 setcoord(linear,log);&lt;br /&gt;
Для создания сетки и меток используется команда autogrid:&lt;br /&gt;
 %сетка по нижней и левой осям&lt;br /&gt;
 autogrid(grid.bot,grid.lft) withcolor .5white;&lt;br /&gt;
 %внешние метки по нижней оси и внутренние метки по правой оси&lt;br /&gt;
 autogrid(otick.bot,itick.rt);&lt;br /&gt;
&lt;br /&gt;
=== Работа с файлами данных ===&lt;br /&gt;
&lt;br /&gt;
[[Изображение:Img 79 110 1.jpg|thumb|Число постов на linux.org.ru]]&lt;br /&gt;
&lt;br /&gt;
С помощью команды gdraw можно читать данные из файла. Если в качестве аргумента передаётся текстовая строка, то gdraw предполагает, что это имя файла.&lt;br /&gt;
 %Файл graphics.mp&lt;br /&gt;
 %Число постов на LOR от месяца года  beginfig(4) ;&lt;br /&gt;
  u := 0.4mm;&lt;br /&gt;
  draw begingraph(150u,100u);&lt;br /&gt;
   pickup pencircle scaled 0.2u;&lt;br /&gt;
   gdraw(&amp;quot;lor-1998.dat&amp;quot;) plot btex \(\circ\) etex;&lt;br /&gt;
   gdraw(&amp;quot;lor-1999.dat&amp;quot;) plot btex \(\circ\) etex;&lt;br /&gt;
   gdraw(&amp;quot;lor-2000.dat&amp;quot;);&lt;br /&gt;
   gdraw(&amp;quot;lor-2001.dat&amp;quot;);&lt;br /&gt;
   gdraw(&amp;quot;lor-2002.dat&amp;quot;);&lt;br /&gt;
   gdraw(&amp;quot;lor-2003.dat&amp;quot;) plot btex \(\bullet\) etex;&lt;br /&gt;
   gdraw(&amp;quot;lor-2004.dat&amp;quot;);&lt;br /&gt;
   gdraw(&amp;quot;lor-2005.dat&amp;quot;);&lt;br /&gt;
   gdraw(&amp;quot;lor-2006.dat&amp;quot;);&lt;br /&gt;
   gdraw (0,100)--(12,100) withpen pencircle scaled 1u dashed evenly scaled 1u withcolor blue;&lt;br /&gt;
   glabel.top(btex 2000--2002 etex,(9,100)) withcolor blue;&lt;br /&gt;
   gdraw (0,200)--(12,200) withpen pencircle scaled 1u dashed evenly scaled 1u withcolor red;&lt;br /&gt;
   glabel.top(btex 2004--2006 etex,(9,200)) withcolor red;&lt;br /&gt;
   glabel.lft(btex число «постов» etex rotated 90,OUT);&lt;br /&gt;
   glabel.bot(btex номер месяца в году etex,OUT);&lt;br /&gt;
  endgraph;&lt;br /&gt;
 endfig;&lt;br /&gt;
Как и команда draw, gdraw «понимает» инструкции withpen (какое перо использовать), withcolor (цвет линии) и dashed (использовать пунктир). Дополнительно gdraw воспринимает команду plot {picture}. Указанная в инструкции plot картинка выбирается в качестве маркера. На рисунке чёрными маркерами отмечен 2003 год – год, когда произошло удвоение ежемесячного числа новостных постов на LOR ([http://www.linux.org.ru www.linux.org.ru]), а белыми маркерами – первый год существования этого ресурса.&lt;br /&gt;
&lt;br /&gt;
По умолчанию предполагается, что входной файл представляет из себя два столбца цифр, разделённых пробелами. Пример файла lor-2006.dat (данные взяты с сайта [http://www.linux.org.ru www.linux.org.ru]):&lt;br /&gt;
 1 175&lt;br /&gt;
 2 181&lt;br /&gt;
 3 184&lt;br /&gt;
Если данные имеют более сложное представление, чем в упомянутом выше файле, то используется команда gdata. gdata («имя файла», переменная куда считываются данные, действие);&lt;br /&gt;
&lt;br /&gt;
Если на текстовый файл вида:&lt;br /&gt;
 1 7.289 H&lt;br /&gt;
 2 2.425 He&lt;br /&gt;
 --вырезано--&lt;br /&gt;
 26 -57.710 Mn&lt;br /&gt;
 27 -60.604 Fe&lt;br /&gt;
воздействовать с помощью следующего кода:&lt;br /&gt;
 %Файл graphics.mp&lt;br /&gt;
 %дефект масс&lt;br /&gt;
 beginfig(5) ;&lt;br /&gt;
  u := 0.8mm;&lt;br /&gt;
 draw begingraph(150u,100u);&lt;br /&gt;
 gdraw &amp;quot;mendeleev.dat&amp;quot; dashed evenly scaled 1u withcolor 0.5white ;&lt;br /&gt;
 gdata(&amp;quot;mendeleev.dat&amp;quot;, s, glabel(s3,(scantokens s1,scantokens s2));&lt;br /&gt;
  )&lt;br /&gt;
 glabel.lft(btex Дефект массы (МэВ) etex rotated 90,OUT);&lt;br /&gt;
 glabel.bot(btex Порядковый номер элемента в таблице etex,OUT);&lt;br /&gt;
 endgraph;&lt;br /&gt;
 endfig;&lt;br /&gt;
то получится простенькая картинка.&lt;br /&gt;
[[Изображение:Img 79 111 1.jpg|thumb|Дефект массы химических элементов от порядкового номера в периодической таблице Меделеева. Приведены элементы от водорода до железа.]]&lt;br /&gt;
Переменная s объявляется массивом, в который считывается строка. В качестве разделителя выступает пробел. Запись s1 соответствует s[1] – первому элементу массива. Макрос scantokens «встраивает» значение аргумента в код. В данном случае происходит перевод строки в число. В качестве «действия» в команде gdata может быть набор из нескольких команд.&lt;br /&gt;
&lt;br /&gt;
=== Гистограммы в MetaPost ===&lt;br /&gt;
&lt;br /&gt;
Если вы хотите нарисовать гистограмму, то можно воспользоваться следующими макросами:&lt;br /&gt;
 %Файл graphics.mp&lt;br /&gt;
 %создает профиль гистограммы из пути&lt;br /&gt;
 def histpath(expr pairs) =&lt;br /&gt;
 for i=0 upto length pairs:&lt;br /&gt;
  if (i&amp;gt;0):--else:fi((point i of pairs)-&lt;br /&gt;
   ((xpart(point 1 of pairs)-&lt;br /&gt;
    xpart(point 0 of pairs))/2,0))--&lt;br /&gt;
  ((point i of pairs)+&lt;br /&gt;
   ((xpart(point 1 of pairs)-&lt;br /&gt;
    xpart(point 0 of pairs))/2,0))&lt;br /&gt;
 endfor&lt;br /&gt;
 enddef;&lt;br /&gt;
 %создает замкнутый профиль гистограммы&lt;br /&gt;
 %для закрашивания&lt;br /&gt;
 def histpathcycle(expr pairs) =&lt;br /&gt;
 ((xpart(point 0 of pairs),0)-&lt;br /&gt;
  ((xpart(point 1 of pairs)-&lt;br /&gt;
   xpart(point 0 of pairs))/2,0))&lt;br /&gt;
 --histpath(pairs)--&lt;br /&gt;
 ((xpart(point infinity of pairs),0)+&lt;br /&gt;
  ((xpart(point 1 of pairs)-&lt;br /&gt;
   xpart(point 0 of pairs))/2,0))--cycle&lt;br /&gt;
 enddef;&lt;br /&gt;
Распределение, представленное на картинке, похоже на убывающую экспоненту. Вот так рисовались «пятёрки»:&lt;br /&gt;
[[Изображение:Img 79 111 2.jpg|thumb|Распределение по баллам, полученным на Открытой олимпиаде по физике в НГУ в 2004 году.]]&lt;br /&gt;
 %Файл graphics.mp&lt;br /&gt;
 %Оценки&lt;br /&gt;
 path five;&lt;br /&gt;
 five:=(21,2)--(22,5)--(23,1)--(24,0)--(25,1)--(26,1)--(27,1)--(28,3)--(29,0)--(30,0)--(31,0);&lt;br /&gt;
 %Заполняем гистограмму&lt;br /&gt;
 gfill histpathcycle(five) withcolor 0.6white;&lt;br /&gt;
Для закрашивания контура применяется инструкция gfill – аналог команды fill.&lt;br /&gt;
&lt;br /&gt;
Данные по оценкам получались в результате обработки текстовых файлов со статистикой с помощью простого скрипта на Perl. Время, которое потребовалось на автоматизацию, составило примерно один человеко-день, что многократно меньше времени написания полного отчёта, куда вошли подобные гистограммы, и оформления всех условий и решений Открытой олимпиады и последовавших за ней летних вступительных экзаменов.&lt;br /&gt;
&lt;br /&gt;
Создание своих макросов на MetaPost является стандартным действием. META не страдает избыточностью и поощряет «доводку» окружения под ваши нужды.&lt;br /&gt;
&lt;br /&gt;
=== Круговые диаграммы ===&lt;br /&gt;
&lt;br /&gt;
Пакет piechartmp.mp относительно молод. Замечательная, можно сказать красочная, документация поставляется в виде файла piechartmp.pdf и примеров.&lt;br /&gt;
&lt;br /&gt;
[[Изображение:Img 79 111 3.jpg|thumb|Распределение оценок.]]&lt;br /&gt;
&lt;br /&gt;
Как обычно, за русским языком надо приглядывать. По умолчанию пакет работает только с латиницей.&lt;br /&gt;
 %Файл pie.mp&lt;br /&gt;
 input piechartmp;&lt;br /&gt;
 %Круговые гистограммы&lt;br /&gt;
 %Открытая Олимпиада &amp;quot;ФФ-51&amp;quot;&lt;br /&gt;
 beginfig(1) ;&lt;br /&gt;
  numeric u; u:=1mm;&lt;br /&gt;
 %чтобы был русский&lt;br /&gt;
 SetupText(1, &amp;quot;\input{preheader-base}&amp;quot;, &amp;quot;\begin{document}&amp;quot;)&lt;br /&gt;
 label(btex Открытая олимпиада НГУ-2005 etex,(5u,25u));&lt;br /&gt;
 label(btex распределение оценок ФФ-51 etex,(5u,20u));&lt;br /&gt;
 %Чтобы отображался процент&lt;br /&gt;
 SetupPercent(this, &amp;quot; \%&amp;quot;);&lt;br /&gt;
 %Опеределение сегментов&lt;br /&gt;
 Segment( 15,&amp;quot;\small два&amp;quot;, auto);&lt;br /&gt;
 Segment( 24,&amp;quot;три&amp;quot;, auto);&lt;br /&gt;
 Segment( 16,&amp;quot;\large четыре&amp;quot;, auto);&lt;br /&gt;
 Segment( 16,&amp;quot;\huge пять&amp;quot;, red );&lt;br /&gt;
 %Создание круговой гистограммы&lt;br /&gt;
 PieChart(30u, 0.2, 65, 0, 0);&lt;br /&gt;
 %метки&lt;br /&gt;
 Label(0)(percent)(inwards,0) withcolor white;&lt;br /&gt;
 Label.auto(0)(name)(outwards,0);&lt;br /&gt;
 endfig;&lt;br /&gt;
Алгоритм создания круговой или секторной диаграммы следующий:&lt;br /&gt;
* Если вы хотите воспользоваться автоматической системой размещения меток, то с помощью команды SetupText следует настроить вывод текста. В файле preheader-base.tex должна быть минимальная шапка для документа LaTeX. Если вы хотите использовать русский язык, то там обязательно должны быть строки вида \usepackage[T2A]{fontenc} и \usepackage[koi8-r]{inputenc}. Вместо koi8-r можно поставить свою кодировку.&lt;br /&gt;
&lt;br /&gt;
* С помощью команды Segment следует определить сегменты. В качестве аргументов команде передаётся число (измеряемая величина), текстовая метка и цвет сегмента (можно указать значение по умолчанию – auto). Можно также ввести четвёртый необязательный строковый параметр, который заменяет измеряемую величину при создании меток. Это решает проблему ограничения на диапазон чисел в MetaPost.&lt;br /&gt;
* Нарисовать гистограмму. В качестве параметров команде PieChart передаётся размер, высота диаграммы, угол, под которым мы на неё смотрим (трёхмерность), угол поворота вокруг центральной оси и «смещение» сегментов относительно центра.&lt;br /&gt;
* Расставить метки. В момент создания каждому сегменту присваивается порядковый номер. Отсчет начинается с единицы. Все изменения в круговой диаграмме делаются глобально. Пакет написан так, чтобы в одном mp-файле было удобно работать ровно с одной диаграммой. Если при описании диаграммы внутри окружения beginfig вы уже что-то определили, то нет необходимости повторять это в последующих окружениях. Этот режим удобен, если нужно создать несколько модификаций одной диаграммы, например, для создания «оверлеев» в презентации. Минусом такого подхода является то, что если в этом же mp-файле хочется создать ещё одну гистограмму, то уже определённые сегменты необходимо спрятать.&lt;br /&gt;
[[Изображение:Img 79 112 1.jpg|thumb|Распределение «вещества» в современной вселенной.]]&lt;br /&gt;
&lt;br /&gt;
 %Круговые гистограммы&lt;br /&gt;
 %распределение вещества во вселенной&lt;br /&gt;
 beginfig(2) ;&lt;br /&gt;
 numeric u; u:=1mm;&lt;br /&gt;
 %прячем определённые ранее сегменты&lt;br /&gt;
 SegmentState(1,hidden,this);&lt;br /&gt;
 SegmentState(2,hidden,this);&lt;br /&gt;
 SegmentState(3,hidden,this);&lt;br /&gt;
 SegmentState(4,hidden,this);&lt;br /&gt;
 %Опеределение новых сегментов&lt;br /&gt;
 Segment( 65,&amp;quot;\Large \bf тёмная энергия&amp;quot;,green,&amp;quot;\LARGE 65\%--70\%&amp;quot;);&lt;br /&gt;
 Segment( 25,&amp;quot;\Large \bf тёмная материя&amp;quot;, (1,0,1),&amp;quot;\LARGE 25\%&amp;quot;);&lt;br /&gt;
 Segment( 0.5,&amp;quot;звёзды&amp;quot;, (1,1,0),&amp;quot;\LARGE 0.5\%&amp;quot;);&lt;br /&gt;
 Segment( 5,&amp;quot;обычное вещество&amp;quot;, red,&amp;quot;\LARGE 5\%&amp;quot;);&lt;br /&gt;
 Segment( 1,&amp;quot;нейтрино&amp;quot;, black,&amp;quot;\LARGE 0.3\%--3\%&amp;quot;);&lt;br /&gt;
 %Выдвигаем сегменты из диаграммы&lt;br /&gt;
 SegmentState(7,this,0.7);&lt;br /&gt;
 SegmentState(9,this,0.7);&lt;br /&gt;
 SegmentState(8,this,0.7);&lt;br /&gt;
 %Создание круговой гистограммы&lt;br /&gt;
 PieChart(30u, 0.3, 30, 340, 0);&lt;br /&gt;
 %метки&lt;br /&gt;
 Label.auto(0)(name)(outwards,0) ;&lt;br /&gt;
 Label.auto(5)(value)(inwards,0) shifted (7u,-7u) withcolor white;&lt;br /&gt;
 Label.auto(6)(value)(inwards,0) shifted (0u,5u) withcolor white;&lt;br /&gt;
 Label.auto(7)(value)(inwards,(0u,-15u)) withcolor (1,1,0);&lt;br /&gt;
 Label.auto(8)(value)(inwards,(25u,10u)) withcolor red;&lt;br /&gt;
 Label.auto(9)(value)(inwards,(20u,20u)) withcolor black;&lt;br /&gt;
 endfig;&lt;br /&gt;
Состояние каждого из сегментов можно задавать с помощью команды SegmentState1.&lt;br /&gt;
&lt;br /&gt;
Состояние сегмента может быть:&lt;br /&gt;
* normal – сегмент становится видимым,&lt;br /&gt;
* invisible – сегмент не рисуется при создании круговой диаграммы (в диаграмме остаётся пустое место),&lt;br /&gt;
* hidden – при создании диаграммы этот сегмент игнорируется.&lt;br /&gt;
Радиальный сдвиг сегмента указывается в процентах, где 1 – это 100%, то есть сегмент полностью «выдвинут».&lt;br /&gt;
&lt;br /&gt;
Для установки меток используется команда Label2:&lt;br /&gt;
&lt;br /&gt;
Label понимает те же суффиксы, что и обычная команда label, плюс auto. При установке суффикса auto Label пытается сама угадать, где лучше поставить метку.&lt;br /&gt;
&lt;br /&gt;
В качестве порядкового номера сегмента можно передать 0. В этом случае команда Label применяется ко всем видимым сегментам. Label может принимать в качестве аргумента список порядковых номеров сегментов, разделённый запятыми (например: 5, 7, 9).&lt;br /&gt;
&lt;br /&gt;
Метка может быть простой текстовой строкой или одним из стандартных значений:&lt;br /&gt;
* value – измеряемая величина, которая приписывается сегменту при его создании,&lt;br /&gt;
* percent – процент занимаемой площади,&lt;br /&gt;
* name – имя сегмента, которое приписывается ему при его создании.&lt;br /&gt;
Базовая точка представляется в виде пары чисел (x,y), где x – расстояние от вершины сегмента (0 – это вершина, 1 – это противоположный от вершины край), а y – эквивалент полярного угла (0 – край сегмента по часовой стрелки, 1 – край сегмента против часовой стрелки). В пакете определены константы inwards=(0.7,0.7) и outwards=(1.1,0.5). Сдвиг же представлен в терминах всего графика (например, (1cm,0) означает сдвиг на 1 сантиметр вправо).&lt;br /&gt;
&lt;br /&gt;
При желании тип заливки и порядок цветов по умолчанию можно определять самостоятельно. Подробнее об этом рассказано в документации к пакету piechartmp.pdf.&lt;br /&gt;
&lt;br /&gt;
=== LaTeX рисует с помощью MetaPost ===&lt;br /&gt;
&lt;br /&gt;
Для рисования графиков можно воспользоваться и возможностями самого LaTeX. Например, с этой обязанностью прекрасно справляется стандартный пакет mfpic. Для «отрисовки» функций с помощью этого пакета достаточно задать саму функцию, а не рисовать по точкам:&lt;br /&gt;
 %файл graphics-mfpic.tex&lt;br /&gt;
 %Пример от Сергея В. Знаменского&lt;br /&gt;
 \documentclass{article}&lt;br /&gt;
 \usepackage[koi8-r]{inputenc}&lt;br /&gt;
 \usepackage[russian]{babel}&lt;br /&gt;
 \usepackage[MetaPost]{mfpic}&lt;br /&gt;
 %указываем mp-файл куда будет «складываться» код mfpic&lt;br /&gt;
 \opengraphsfile{graph-mfp}&lt;br /&gt;
 \begin{document}&lt;br /&gt;
 %не печатать номер страницы&lt;br /&gt;
 \pagestyle{empty}&lt;br /&gt;
 %начинаем создание графика&lt;br /&gt;
 \mfpic[1][57.2]{-100}{300}{-1.2}{1.2}&lt;br /&gt;
 %оси координат&lt;br /&gt;
 \axes&lt;br /&gt;
 \xmarks{-90,90,180,270}&lt;br /&gt;
 \ymarks{-1,1}&lt;br /&gt;
 %рисуем синус точками&lt;br /&gt;
 \dotted\function{-90,270,4.5}{sind(x)}&lt;br /&gt;
 %рисуем косинус пунктиром&lt;br /&gt;
 \dashed\function{-90,270,4.5}{cosd(x)}&lt;br /&gt;
 %рисуем тангенс сплошной линией&lt;br /&gt;
 \function{-50,50,10}{tand(x)}&lt;br /&gt;
 \function{130,230,10}{tand(x)}&lt;br /&gt;
 %заканчиваем создание графика&lt;br /&gt;
 \endmfpic&lt;br /&gt;
 %закрываем mp-файл&lt;br /&gt;
 \closegraphsfile&lt;br /&gt;
 \end{document}&lt;br /&gt;
Для получения картинки необходимо выполнить следующие действия:&lt;br /&gt;
 &amp;gt; LaTeX graphics-mfpic.tex&lt;br /&gt;
 &amp;gt; mpost graph-mfp.mp&lt;br /&gt;
 &amp;gt; LaTeX graphics-mfpic.tex&lt;br /&gt;
 &amp;gt; dvips -E graphics-mfpic.dvi -o graphics-mfpic.eps&lt;br /&gt;
При компиляции файла graphics-mfpic.tex создаётся graph-mfp.mp, куда пишутся команды на языке META. Если посмотреть на код graph-mfp.mp, то можно увидеть, что там используется макрос function, который позволяет рисовать функции одной командой, без всяких циклов. Как это делается, можно подглядеть в библиотечке grafbase.mp, которая входит в состав пакета mfpic.&lt;br /&gt;
&lt;br /&gt;
Более подробно про пакет mfpic можно узнать из документации которую можно найти в директории $(TEXMF)/texmf-dist/doc/generic/mfpic/, где $(TEXMF) – директория в которую установлен LaTeX (это заведомо верно для дистрибутива TeX Live).&lt;br /&gt;
&lt;br /&gt;
=== gnuplot ===&lt;br /&gt;
&lt;br /&gt;
[[Изображение:Img 79 113 1.jpg|thumb|Интегральная светимость от времени. Данные за полтора года (примерно 130 тысяч точек) обработаны с помощью программы gnuplot.]]&lt;br /&gt;
&lt;br /&gt;
В случае отображения больших объёмов данных лучше использовать gnuplot. Чтобы gnuplot работал с MetaPost, необходимо определить правильное устройство вывода. Для этого в gnuplot следует передать команду:&lt;br /&gt;
 set terminal mp color LaTeX&lt;br /&gt;
В этом случае gnuplot будет выводить графики в формате MetaPost. К сожалению, похоже, что вывод в MetaPost давно не поддерживался, поэтому установка кодировки:&lt;br /&gt;
 set encoding koi8r&lt;br /&gt;
не оказывает должного эффекта. Получившийся mp-файл приходится дорабатывать вручную. К счастью, это не сложно (следует поправить только заголовок), но для автоматизации следует озадачиться исправлением этой неприятной ошибки в gnuplot.&lt;br /&gt;
&lt;br /&gt;
В случае, если возникнет желание изменить метки, следует обратить внимание на переменную textmag, которая отвечает за размер текста.&lt;br /&gt;
&lt;br /&gt;
=== Подведём итоги ===&lt;br /&gt;
&lt;br /&gt;
С помощью MetaPost можно создавать двумерные графики и диаграммы любой сложности. Возможности языка META и стандартные пакеты позволяют сконцентрироваться на смысловой части и не отвлекаться на отдельные элементы оформления.&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF78:MetaPost</id>
		<title>LXF78:MetaPost</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF78:MetaPost"/>
				<updated>2008-05-16T19:14:45Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: {{Цикл/MetaPost}}&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/MetaPost}}&lt;br /&gt;
''Часть 3. Компьютер не умеет читать ваши мысли, зато неукоснительно следует инструкциям. '''Евгений Балдин''' научит вас отдавать правильные команды и извлекать из этого выгоду.''&lt;br /&gt;
&lt;br /&gt;
До сего момента мы концентрировались на том, как объяснить компьютеру, чтобы он сделал то или иное движение. Теперь воспользуемся способностью компьютера помнить предыдущие действия и извлекать их из памяти по мере необходимости. Автоматизация рутинных процедур это то, для чего компьютеры и предназначены. Практиковаться в автоматизации следует постоянно. Несмотря на затраченное на обучение время, в результате время же и экономится. &lt;br /&gt;
&lt;br /&gt;
===Объекты picture'''===&lt;br /&gt;
&lt;br /&gt;
В процесс повествования объект picture или картинка уже упоминался. Картинка представляет из себя совокупность путей и точек, которую можно подвергать трансформации. В уже существующие картинки можно добавлять пути, замкнутые области и другие картинки. &lt;br /&gt;
&lt;br /&gt;
Для начала опять же воспользуемся миллиметровкой для отрисовки какого-либо рисунка, например, ракеты: &lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
[[Изображение:Img_78_104_1.jpg]]&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ракета может быть без выхлопа (rocket) и c выхлопом (firerocket). В процессе создания firerocket был использован рисунок самого выхлопа (fire).&lt;br /&gt;
&lt;br /&gt;
 %Файл picture.1.mp&lt;br /&gt;
 %Ракета без выхлопа 10x12 Центр у стабилизаторов&lt;br /&gt;
  picture rocket;rocket:=nullpicture;&lt;br /&gt;
  addto rocket contour (-2,-1)--(-2,6)--(0,10)--(2,6)--(2,-1)--cycle&lt;br /&gt;
  withpen pencircle scaled 0.4 withcolor white;&lt;br /&gt;
  addto rocket  doublepath (-2,-1)--(-2,6)--(0,10)--(2,6)--(2,-1)--cycle&lt;br /&gt;
  withpen pencircle scaled 0.5;%Корпус&lt;br /&gt;
  addto rocket contour (-2,2.5)--(-4,1)--(-4.5,-3)--(-2,-3)--cycle&lt;br /&gt;
  withpen pencircle scaled 0.4 withcolor white;&lt;br /&gt;
  addto rocket  doublepath (-2,2.5)--(-4,1)--(-4.5,-3)--(-2,-3)--cycle&lt;br /&gt;
  withpen pencircle scaled 0.5;%левая дюза&lt;br /&gt;
  addto rocket contour (2,2.5)--(4,1)--(4.5,-3)--(2,-3)--cycle&lt;br /&gt;
  withpen pencircle scaled 0.4 withcolor white;&lt;br /&gt;
  addto rocket  doublepath (2,2.5)--(4,1)--(4.5,-3)--(2,-3)--cycle&lt;br /&gt;
  withpen pencircle scaled 0.5;%правая дюза&lt;br /&gt;
  addto rocket  doublepath (0,2.5)--(0,-3)&lt;br /&gt;
  withpen pencircle scaled 0.8;%центральная дюза&lt;br /&gt;
  %выхлоп&lt;br /&gt;
  picture fire;fire:=nullpicture;&lt;br /&gt;
  addto fire  doublepath (0,-4)--(0,-6)&lt;br /&gt;
  withpen pencircle scaled 0.3;%выхлоп 1&lt;br /&gt;
  addto fire  doublepath (-1.5,-4)--(-1.5,-6)&lt;br /&gt;
  withpen pencircle scaled 0.3;%выхлоп 2&lt;br /&gt;
  addto fire  doublepath (1.5,-4)--(1.5,-6)&lt;br /&gt;
  withpen pencircle scaled 0.3;%выхлоп 3&lt;br /&gt;
  addto fire  contour (-2.5,-6.5){dir 135}..(-4,-8)..&lt;br /&gt;
  {dir 50}(-1.2,-8.2){dir -110}..(0,-10)&lt;br /&gt;
  ..{dir 110}(1.2,-8.2){dir -50}..(4,-8)..{dir -135}(2.5,-6.5)--cycle&lt;br /&gt;
  withpen pencircle scaled 0.4 withcolor white;&lt;br /&gt;
  addto fire  doublepath (-2.5,-6.5){dir 135}..(-4,-8)..&lt;br /&gt;
  {dir 50}(-1.2,-8.2){dir -110}..(0,-10)&lt;br /&gt;
  ..{dir 110}(1.2,-8.2){dir -50}..(4,-8)..{dir -135}(2.5,-6.5)&lt;br /&gt;
  withpen pencircle scaled 0.3;%облако&lt;br /&gt;
  %ракета и выхлоп&lt;br /&gt;
  picture firerocket;firerocket:=rocket;&lt;br /&gt;
  addto firerocket also fire;&lt;br /&gt;
&lt;br /&gt;
Прежде чем что-то добавить к картинке, её необходимо инициализировать. В MetaPost есть две определённые по умолчанию картинки: '''nullpicture''' — пустая картинка и '''currentpicture''' — текущая картинка. Пользуясь последней переменной, можно в любой момент сохранить результаты промежуточной отрисовки. Добавление элементов к картинке производится с помощью инструкции '''addto''', после которой указывается картинка, к которой и добавляется тот или иной элемент. Путь добавляется с помощью инструкции '''doublepath''', замкнутая область — с помощью инструкции contour, а другая картинка с помощью инструкции '''also'''.&lt;br /&gt;
&lt;br /&gt;
Ранее был создан рисунок черепашки. Для его обозначения была выбрана переменная '''Turtle'''. Теперь с ней можно поработать, как с единым элементом, например, для иллюстрации задачи: «Черепашки расположены в углах правильного треугольника со стороной a и всегда ползут в направлении своей соседки против часовой стрелки со скоростью v. Когда они встретятся?»&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
[[Изображение:Img_78_105_1.jpg]]&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Картинку можно отобразить с помощью команды '''draw'''. Над картинкой можно производить различные преобразования. В данном случае картинка поворачивалась, масштабировалась и сдвигалась.&lt;br /&gt;
&lt;br /&gt;
 %Файл pic.mp&lt;br /&gt;
 beginfig(17) ;&lt;br /&gt;
 numeric u;u = 0.8mm;&lt;br /&gt;
 numeric dphi; dphi=20;&lt;br /&gt;
    draw 30u*dir (90+dphi)--30u*dir (210+dphi)--30u*dir (330+dphi)--cycle &lt;br /&gt;
    dashed evenly scaled 1u;&lt;br /&gt;
    draw Turtle rotated (-120+dphi) scaled 1u shifted (30u*dir (90+dphi));&lt;br /&gt;
    draw Turtle rotated dphi scaled 1u shifted (30u*dir (210+dphi));&lt;br /&gt;
    draw Turtle rotated (120+dphi) scaled 1u shifted (30u*dir (330+dphi));&lt;br /&gt;
 endfig ;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание, что линия, соединяющая черепах, нарисована пунктиром. Определённая по умолчанию переменная '''evenly''' тоже является картинкой, поэтому её можно масштабировать с помощью декларации '''scaled'''. То есть, если вам нужен более широкий шаг пунктира, то вместо масштаба '''1u''' можно указать '''2u'''. Если вас не устраивает где располагаются штрихи у штриховки, то можно воспользоваться декларацией сдвига '''shifted'''.&lt;br /&gt;
&lt;br /&gt;
Кроме шаблона '''evenly''' в MetaPost определён шаблон '''withdots''', который позволяет рисовать кривую с помощью точек.&lt;br /&gt;
&lt;br /&gt;
Вы можете определить свой шаблон для пунктира примерно следующим образом:&lt;br /&gt;
 picture dash_center;&lt;br /&gt;
 dash_center:=dashpattern(on 3 off 1.5 on 0.5 off 1.5);&lt;br /&gt;
 draw 30u*dir (90+dphi)--30u*dir (210+dphi)--  30u*dir (330+dphi)--cycle dashed dash_center scaled 1u;&lt;br /&gt;
&lt;br /&gt;
Функция '''dashpattern''' принимает список '''on/off''' с числовой информацией в какой момент рисовать/не рисовать. В этом примере определён шаблон для штрих-пунктирной линии, которая обычно используется для обозначения оси симметрии.&lt;br /&gt;
&lt;br /&gt;
===Трансформация===&lt;br /&gt;
К задаче N 3 варианта ГГФ-51в требовалось изобразить L-образную трубку с водой. По условию, трубка сначала стояла вертикально, а потом была положена на стол.&lt;br /&gt;
&lt;br /&gt;
Чтобы схематично это изобразить, вовсе необязательно уметь работать в трёхмерном редакторе. Ниже идёт код, который рисует вертикально стоящую пробирку с размерами, а затем наклоняет её.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
[[Изображение:Img_78_105_3.jpg]]&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
 %Файл transform.mp&lt;br /&gt;
 %пример использования slanted&lt;br /&gt;
 beginfig(1) ;&lt;br /&gt;
 numeric u;&lt;br /&gt;
 u = 0.8mm;&lt;br /&gt;
 %пробирка&lt;br /&gt;
 cutdraw (0u,0u)--(20u,0u)--(20u,30u){dir 90}..&lt;br /&gt;
  {dir -90}(17u,30u)--(17u,3u)--(0u,3u)&lt;br /&gt;
  withpen pencircle scaled 0.5u;&lt;br /&gt;
 drawdblarrow (23u,10u)--(23u,1u);&lt;br /&gt;
 label.rt(btex \(h\) etex,1/2[(23u,10u),(23u,1u)]);&lt;br /&gt;
 drawdblarrow (30u,30u)--(30u,1u);&lt;br /&gt;
 label.lft(btex \(H\) etex,1/2[(30u,30u),(30u,1u)]);&lt;br /&gt;
 picture Base;&lt;br /&gt;
 Base:=currentpicture; %запоминаем&lt;br /&gt;
 clearit; %очищаем текущую картинку&lt;br /&gt;
 %рисуем воду когда пробирка будет наклонена&lt;br /&gt;
 fill (15u,0u)--(20u,0u)--(20u,20u)--(17u,20u)--&lt;br /&gt;
  (17u,3u)--(15u,3u)--cycle withcolor 0.7white;&lt;br /&gt;
 draw Base;&lt;br /&gt;
 draw (12u,20u)--(20u,20u);draw (12u,10u)--(20u,10u);&lt;br /&gt;
 drawdblarrow (14u,20u)--(14u,10u);&lt;br /&gt;
 label.lft(btex \(d\) etex,(14u,16u));&lt;br /&gt;
 picture Slant;&lt;br /&gt;
 Slant=currentpicture; %запоминаем&lt;br /&gt;
 clearit; %очищаем текущую картинку&lt;br /&gt;
 %рисуем воду когда пробирка стоит&lt;br /&gt;
 fill (5u,0u)--(20u,0u)--(20u,10u)--(17u,10u)--&lt;br /&gt;
  (17u,3u)--(5u,3u)--cycle withcolor 0.7white;&lt;br /&gt;
 %отрисовываем пробирку&lt;br /&gt;
 draw Base;&lt;br /&gt;
 %отрисовываем пробирку и наклоняем её&lt;br /&gt;
 draw Slant yscaled 2/3 slanted 1/2 shifted (40u,0u);&lt;br /&gt;
 endfig ;&lt;br /&gt;
&lt;br /&gt;
В примере применяется возможность сохранить текущее состояние с помощью '''currentpicture''', а так же возможность полностью очистить текущую картинку с помощью инструкции '''clearit'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
[[Изображение:Img_78_105_2.jpg]]&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Наклон вертикально стоящей пробирки происходит с помощью масштабирования '''yscaled''' и, собственно, наклона '''slanted'''.&lt;br /&gt;
&lt;br /&gt;
MetaPost поддерживает следующие базовые линейные преобразования:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellpadding=&amp;quot;6&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
!Команда&lt;br /&gt;
!Результат&lt;br /&gt;
|-&lt;br /&gt;
|align=center|(x,y) shifted (a,b)&lt;br /&gt;
|align=center|(x+a,y+a)&lt;br /&gt;
|-&lt;br /&gt;
|align=center|(x,y) scaled s&lt;br /&gt;
|align=center|(sx,sy)&lt;br /&gt;
|-&lt;br /&gt;
|align=center|(x,y) xscaled s    &lt;br /&gt;
|align=center|(sx,y)&lt;br /&gt;
|-&lt;br /&gt;
|align=center|(x,y) yscaled s&lt;br /&gt;
|align=center|(x,sy)&lt;br /&gt;
|-&lt;br /&gt;
|align=center|(x,y) slanted s&lt;br /&gt;
|align=center|(x+sy,y)&lt;br /&gt;
|-&lt;br /&gt;
|align=center|(x,y) rotated &lt;br /&gt;
|align=center|(x cos - y sin , x sin + y cos )&lt;br /&gt;
|-&lt;br /&gt;
|align=center|(x,y) zscaled (a,b)&lt;br /&gt;
|align=center|(xa-yb, xb+ya)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Кроме перечисленных базовых преобразований полезными для использования являются макросы '''rotatedaround ((a,b), c)''' — поворот вокруг точки (a,b) на угол c и '''reflectedabout (z1,z2)''' — отражение относительно линии, проходящей через точки z1 и z2.&lt;br /&gt;
&lt;br /&gt;
MetaPost поддерживает объекты типа transform, то есть можно определить любое необходимое для вас преобразование, чтобы использовать его в дальнейшем.&lt;br /&gt;
 transform t;&lt;br /&gt;
 t:= identity yscaled 2/3 slanted 1/2 shifted (40u,0u)&lt;br /&gt;
 draw Slant transformed t;&lt;br /&gt;
&lt;br /&gt;
Используемая при описании преобразования t константа '''identity''' тоже является преобразованием. '''identity''' – это «пустое» преобразование, то есть преобразование, которое ничего не делает (математически, оператор такого преобразования описывается единичной матрицей – identity matrix, что и определяет название).&lt;br /&gt;
&lt;br /&gt;
===Циклы и условные операторы===&lt;br /&gt;
&lt;br /&gt;
Циклы и условные операторы в MetaPost отличаются от того, что обычно есть в других языках программирования. Цикл не просто повторяет перечисленные в теле цикла инструкции — он дублирует текст, то есть внутри цикла не обязательно должна находиться синтаксически законченная конструкция. Это же относится и к условным операторам.&lt;br /&gt;
&lt;br /&gt;
''«Шарик с постоянной скоростью движется вдоль спицы, которая с вращается с постоянной угловой скоростью. Требуется изобразить траекторию шарика.»''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
[[Изображение:Img_78_106_1.jpg]]&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для изображения траектории надо построить минимодель явления и задать физические параметры: поступательную скорость вдоль спицы v, угловую частоту w и начальные условия r и phi. Сама траектория создаётся с помощью следующего кода:&lt;br /&gt;
&lt;br /&gt;
 %Файл cycle.mp&lt;br /&gt;
 v:=27u;w:=360;N:=2.1;phi:=45;r:=5u;n:=100;&lt;br /&gt;
 path p; pair O;&lt;br /&gt;
 O:=(r*cosd(phi),r*sind(phi));&lt;br /&gt;
 p:=O for i=0 upto n:&lt;br /&gt;
     ..((r+v*N*i/n)*dir(-w*N*i/n)+phi))&lt;br /&gt;
   endfor;&lt;br /&gt;
 draw p withpen pencircle scaled 0.5u dashed evenly scaled 1u;&lt;br /&gt;
&lt;br /&gt;
Декларация '''upto''' - это сокращение для '''step 1 until'''. Аналогично '''downto''' является сокращением для step -1 untull.&lt;br /&gt;
&lt;br /&gt;
Формальный синтаксис цикла представлен ниже:&lt;br /&gt;
 for i=x1 step x_2 until x3: text(i) endfor&lt;br /&gt;
&lt;br /&gt;
Это одна из форм, которая поддерживается META. Ещё одна форма представляет бесконечный цикл:&lt;br /&gt;
&lt;br /&gt;
 forever: “текст” endfor&lt;br /&gt;
&lt;br /&gt;
Для того чтобы выйти из подобного цикла необходимо воспользоваться конструкцией вида:&lt;br /&gt;
 exitif (“булево выражение”)&lt;br /&gt;
&lt;br /&gt;
Булево выражение может быть переменной типа '''boolean''' ('''true'''/'''false''') или результатом сравнения чисел, точек, путей или преобразований. Операторы сравнения почти совпадают с операторами сравнения языка C, за исключением оператора равенства «=» и оператора неравенства «&amp;lt;&amp;gt;». Выражение можно инвертировать с помощью приставки not и объединить с другим с помощью приставок and или or.&lt;br /&gt;
&lt;br /&gt;
Формальный синтаксис условного оператора представлен ниже:&lt;br /&gt;
 if (“булево выражение1”): “текст1”&lt;br /&gt;
 elseif (“булево выражение2”): “текст2”&lt;br /&gt;
 else: “текст3” fi&lt;br /&gt;
&lt;br /&gt;
Воспользуемся циклами для изображения циклоиды — траектории&lt;br /&gt;
точки на катящемся колесе.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
[[Изображение:Img_78_106_3.jpg]]&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание, что в конце цикла или условного оператора нет необходимости ставить «;» это позволяет использовать их довольно изощрённым образом.&lt;br /&gt;
&lt;br /&gt;
 %Файл cycle.mp &lt;br /&gt;
 %Рис к задаче 1.5.8 (20x120) - циклоида&lt;br /&gt;
 beginfig(1) ;&lt;br /&gt;
 numeric u;u = 0.8mm;&lt;br /&gt;
 numeric R; R=10u;&lt;br /&gt;
 path p,cycl;&lt;br /&gt;
 p:=(-R,0u)..(R,0u)..cycle;&lt;br /&gt;
 %колесо&lt;br /&gt;
 draw p withpen pencircle scaled 0.3u&lt;br /&gt;
                    dashed withdots scaled 0.5u;&lt;br /&gt;
 numeric j,n,v,w,phi,nsteps;&lt;br /&gt;
 j=0;n=100;v=109.8u;w=-(v/R)*180/3.14;phi=180;nsteps=4;&lt;br /&gt;
 numeric r,i;&lt;br /&gt;
 for i:=0 upto 2*nsteps:&lt;br /&gt;
   r:=R-1/nsteps*R*i;&lt;br /&gt;
   %метки&lt;br /&gt;
   for j:=0 step n/4 until n:&lt;br /&gt;
     draw (j*(v/n)+r*cosd(j*(w/n)+phi),r*sind(j*(w/n)+phi))&lt;br /&gt;
       withpen pencircle scaled 1u;&lt;br /&gt;
   endfor;&lt;br /&gt;
   %траектория меток&lt;br /&gt;
   cycl:=for j:=0 upto n:&lt;br /&gt;
     if j&amp;lt;&amp;gt;0:..fi&lt;br /&gt;
          (j*(v/n)+r*cosd(j*(w/n)+phi),r*sind(j*(w/n)+phi))&lt;br /&gt;
   endfor;&lt;br /&gt;
   draw cycl dashed evenly scaled 1/2u&lt;br /&gt;
     withcolor (max(1-i/nsteps,0)*red+&lt;br /&gt;
               min(i/nsteps,2-i/nsteps)*green+&lt;br /&gt;
               max(i/nsteps-1,0)*blue);&lt;br /&gt;
  endfor;&lt;br /&gt;
 endfig ;&lt;br /&gt;
&lt;br /&gt;
В этом коде выражение '''if j&amp;lt;&amp;gt;0:..fi''' использовалось для того, чтобы перед первой точкой пути, описывающем циклоиду, не было декларации соединения. Я не знаю, какой еще из «популярных» на сегодня языков обладает такой способностью.&lt;br /&gt;
&lt;br /&gt;
===Макросы===&lt;br /&gt;
&lt;br /&gt;
Пользовательские функции в META фактически заменяются макросами. Как следствие, функции могут вернуть любую конструкцию: от числа до картинки.&lt;br /&gt;
&lt;br /&gt;
Одним из моих ранних рисунков на META был «взрыв» в стакане. Требовалось изобразить траекторию «осколков» которые летят по параболе и найти самую дальнюю точку, которую достигают осколки при таком «взрыве».&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
[[Изображение:Img_78_106_2.jpg]]&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Была написана процедура, которая рисовала параболу по переданным параметрам. Вызов выглядел примерно следующим образом:&lt;br /&gt;
 Parabola_dashed(0u,0u,-1.25angle(20/sqrt(8),&lt;br /&gt;
           10*sqrt(8)),10*sqrt(8)*u,0,100,1);&lt;br /&gt;
&lt;br /&gt;
Сам макрос для отрисовки параболы представлен ниже.&lt;br /&gt;
 %Файл macros.mp&lt;br /&gt;
 %Рисует параболу из точки (x,y) (полёт камня) штриховая&lt;br /&gt;
 %линия. В качестве параметров передаётся (x,y), ang-угол,&lt;br /&gt;
 %vel-скорость (100), %from,to - откуда и до куда рисовать&lt;br /&gt;
 %параболу в процентах [0,100], mag - увеличение (0.8u)&lt;br /&gt;
 %Для простоты g=10&lt;br /&gt;
 def Parabola_dashed(expr x,y,ang,vel,from,to,mag) =&lt;br /&gt;
  path p;&lt;br /&gt;
  numeric t,g,n;&lt;br /&gt;
  picture dash_one;&lt;br /&gt;
  dash_one:=dashpattern(on 2mag off 2mag);&lt;br /&gt;
  n=100;%число шагов&lt;br /&gt;
  g=10.;&lt;br /&gt;
  t:=(2*vel*sind(ang)*from)/(g*n);&lt;br /&gt;
  p:=(vel*cosd(ang)*t*mag,(vel*sind(ang)*t-g*t*t/2)*mag);&lt;br /&gt;
  for i=from+1 upto to:&lt;br /&gt;
    t:=(2*vel*sind(ang)*i)/(g*n);&lt;br /&gt;
  p:=p..(vel*cosd(ang)*t*mag,&lt;br /&gt;
         (vel*sind(ang)*t-g*t*t/2)*mag);&lt;br /&gt;
 endfor;&lt;br /&gt;
 draw p shifted (x*mag,y*mag) dashed dash_one;&lt;br /&gt;
 enddef;&lt;br /&gt;
Не самое удачное решение, но оно выполняло то, что от него требовалось. В подобных случаях лучше, чтобы в результате деятельности макроса оставался объект, который потом можно нарисовать с помощью команды '''draw''' и трансформировать по мере необходимости. Тогда функции передавалось бы гораздо меньше параметров, что значительно бы все упростило. Например, вызов для рисования пружинки, которая необходима в следующем примере, использует всего три входных параметра:&lt;br /&gt;
 draw Spring(25u,1.2u,25) rotated -90&lt;br /&gt;
  shifted (-12.5u,-20u) withpen pencircle scaled 0.1u;&lt;br /&gt;
&lt;br /&gt;
''«Два тела, соединённые пружинкой, висят в поле тяжести на нитях, образующих угол в 900. В какой-то момент нить, крепящую конструкцию к потолку, разрывают.»''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
[[Изображение:Img_78_107_2.jpg]]&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Надо нарисовать пружинку. Изображение пружинка может пригодится много где ещё, поэтому оно было оформлено как макрос.&lt;br /&gt;
 %Файл macros.mp&lt;br /&gt;
 %Создаёт пружину, высоты h, радиуса r, с числом витков n&lt;br /&gt;
 % (0,0) - в основании пружины&lt;br /&gt;
 vardef Spring(expr h,r,n) =&lt;br /&gt;
  begingroup save i;&lt;br /&gt;
    (0,0)--(0,-r/2+0.5h/n){dir 180}&lt;br /&gt;
    for i=h/n step h/n until h:&lt;br /&gt;
      ..tension 1.2..(-r,i-h/n)..tension 1.2 ..&lt;br /&gt;
      (0,r/2+i-0.5h/n)..tension 1.2 ..(r,i)..&lt;br /&gt;
      tension 1.2 ..(0,-r/2+i+0.3h/n){dir 180}&lt;br /&gt;
    endfor--(0,h)&lt;br /&gt;
  endgroup&lt;br /&gt;
 enddef;&lt;br /&gt;
&lt;br /&gt;
Обратите внимания на инструкцию '''tension''' — натяжение. Она говорит с какой «силой» надо «натянуть» соединение между точками. Значение 1.2 означает, что это следует сделать чуть потуже, чем обычно. С помощью этой инструкции описывается соединение между точками в определении пути типа «натянутая прямая»:&lt;br /&gt;
 def --- = ..tenstion infinity.. enddef;&lt;br /&gt;
&lt;br /&gt;
Если отрисовка параболы является аналогом процедуры, то создание пружины аналогом функции. Вызовы '''begingroup endgroup''' позволяют обособить вычисления, проводящиеся между ними, от «внешнего мира». С помощью команды save можно защитить переменные внутри группы — «сохранённые» таким образом переменные восстанавливают свои значения после выхода за пределы endgroup.&lt;br /&gt;
&lt;br /&gt;
Параметры, которые передаются внутрь макроса, перечисляются после декларации '''expr'''. Чтобы что-то вернуть в результате исполнения макроса, возвращаемое выражение надо поместить в конце макроса без завершающего символа «;».&lt;br /&gt;
&lt;br /&gt;
Отличие '''vardef''' от '''def''' заключается в том, что в случае '''def''' в качестве названия макроса передаётся «символьная лексема», а в случае '''vardef''' «объявляемая переменная». Отличие между этими понятиями заключается в том, что объявляемая переменная может состоять из нескольких символьных лексем. Таким образом вы можете создавать переменные с модифицирующимися именами. Если вам этого не надо, то используйте '''def'''.&lt;br /&gt;
&lt;br /&gt;
Средства поддержки макросов в MetaPost исключительно мощные и разнообразные. В частности, с помощью инструкции '''primarydef''' можно доопределить недостающие бинарные операторы.&lt;br /&gt;
&lt;br /&gt;
=== Стандартные функции===&lt;br /&gt;
Лучший способ облегчить себе жизнь при написании программы  - это не писать её, а воспользоваться уже готовыми компонентами. META является специализированным языком, поэтому число стандартных функций не очень велико, но их выбор весьма показателен.&lt;br /&gt;
&lt;br /&gt;
''«Из точек A и B в море вышли два корабля...» Требуется  изобразить поверхность воды:''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
[[Изображение:Img_78_107_1.jpg]]&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При кодировании этого рисунка использовалась функция генерации случайных чисел:&lt;br /&gt;
 uniformdeviate n&lt;br /&gt;
&lt;br /&gt;
В результате выполнения функции получалось случайное число  в интервале [0,1]. Кроме упомянутой функции в META есть ещё один генератор случайных чисел normaldeviate — он создает числа в соответствии с распределением Гаусса (~exp(–x/2)).&lt;br /&gt;
&lt;br /&gt;
Хотелось бы упомянуть о возможности разлагать сложные объекты на составляющие, например:&lt;br /&gt;
  numeric x[ ],y[ ];&lt;br /&gt;
  pair A,B; A=(x1,y1);A=(x2,y2);&lt;br /&gt;
  %A=(xpart x1,ypart y1)&lt;br /&gt;
  color c; c=(r,g,b);&lt;br /&gt;
  %c=(redpart c,greenpart c,bluepart c)&lt;br /&gt;
  path p;&lt;br /&gt;
  p=A--B;&lt;br /&gt;
  %A = point 0 of p = point 2 of p&lt;br /&gt;
  %B = point 1 of p = point length p of p&lt;br /&gt;
&lt;br /&gt;
Таким образом можно «разобрать» на части любой путь, причём номер точки не обязательно должен быть целым (берётся точка на линии соединения в соответствии с дробной частью). С помощью функции '''length''' можно узнать число заданных точек в пути, а с помощью '''arclength''' — его длину.&lt;br /&gt;
&lt;br /&gt;
К уже известным вычислительным функциям '''sqrt''', '''abs''', '''mod''', '''round''', '''sind''' и '''cosd''' полезно добавить '''mlog (f(x)=256 ln x)''' и '''mexp  (f(x)=exp(x/256)).'''&lt;br /&gt;
&lt;br /&gt;
Для операций с точками будут полезны функции '''angle (x,y)''' — вычисления угла наклона к оси абсцисс для вектора ((0,0)--(x,y)) в градуcах (операция, обратная dir a) и '''unitvector (x,y)''' — единичный вектор из начала координат.&lt;br /&gt;
&lt;br /&gt;
Полный список стандартных функций представлен в «A User’s  Manual for MetaPost» Джона Хобби. Этот текст идёт со стандартной поставкой LaTeX в виде файла '''mpman.pdf'''.&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF77:MetaPost</id>
		<title>LXF77:MetaPost</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF77:MetaPost"/>
				<updated>2008-05-16T19:14:41Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: {{Цикл/MetaPost}}&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/MetaPost}}&lt;br /&gt;
== MetaPost Базовые элементы ==&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;br /&gt;
&lt;br /&gt;
[[Изображение:Img 77 96 1.png|Img 77 96 1.png]]&lt;br /&gt;
&lt;br /&gt;
Делаем это, как можем, а затем очень подробно объясняем компьютеру, что мы хотим от него. Инструкции очень простые:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;latex&amp;quot;&amp;gt;&lt;br /&gt;
%Файл coord.mp&lt;br /&gt;
%Черепашка&lt;br /&gt;
beginfig(1) ;&lt;br /&gt;
numeric u;u:=5mm;&lt;br /&gt;
draw (-5u,0u){dir 90}..{dir 0}(0,3.5u){dir0}..&lt;br /&gt;
{dir -90}(5u,0){dir -90}..{dir 180}(0u,-3.5u){dir 180}..&lt;br /&gt;
{dir 90}cycle withpen pencircle scaled 0.4u;&lt;br /&gt;
draw (4.5u,1.5u)..(7u,1.5u)..(8u,0u)..(7u,-1.5u)..&lt;br /&gt;
(4.5u,-1.5u) withpen pencircle scaled 0.4u;&lt;br /&gt;
draw (6.5u,.5u) withpen pencircle scaled 0.8u;&lt;br /&gt;
draw (6.5u,-.5u) withpen pencircle scaled 0.8u;&lt;br /&gt;
draw (-3.5u,-2.5u)..(-4.2u,-4.5u)..(-3.7u,-5u)..&lt;br /&gt;
(-2.4u,-4u)..(-2u,-3.5u) withpen pencircle scaled 0.4u;&lt;br /&gt;
draw (-3.5u,2.5u)..(-4.2u,4.5u)..(-3.7u,5u)..(-2.4u,4u)..&lt;br /&gt;
(-2u,3.5u) withpen pencircle scaled 0.4u;&lt;br /&gt;
draw (3.5u,-2.5u)..(4.2u,-4.5u)..(3.7u,-5u)..(2.4u,-4u)..&lt;br /&gt;
(2u,-3.5u) withpen pencircle scaled 0.4u;&lt;br /&gt;
draw (3.5u,2.5u)..(4.2u,4.5u)..(3.7u,5u)..(2.4u,4u)..&lt;br /&gt;
(2u,3.5u) withpen pencircle scaled 0.4u;&lt;br /&gt;
draw (-5u,0.5u)--(-6.5u,0)--(-5u,-0.5u)&lt;br /&gt;
withpen pencircle scaled 0.4u;&lt;br /&gt;
draw (0u,2.5u)..(0,0u)..(0u,-2.5u)&lt;br /&gt;
withpen pencircle scaled 0.3u;&lt;br /&gt;
draw (-2.4u,2.4u)..(-2u,0u)..(-2.4u,-2.4u)&lt;br /&gt;
withpen pencircle scaled 0.3u;&lt;br /&gt;
draw (2.4u,2.4u)..(2u,0u)..(2.4u,-2.4u)&lt;br /&gt;
withpen pencircle scaled 0.3u;&lt;br /&gt;
draw (-3u,1.5u)..(0,1u)..(3u,1.5u)&lt;br /&gt;
withpen pencircle scaled 0.3u;&lt;br /&gt;
draw (-3u,-1.5u)..(0,-1u)..(3u,-1.5u)&lt;br /&gt;
withpen pencircle scaled 0.3u;&lt;br /&gt;
endfig ;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Рисуем по точкам, используя команду draw. Каждая точка задаётся&lt;br /&gt;
парой чисел «(x,y)» – x и y координаты соответственно. Точки соединяются либо прямыми линиями «--», либо кривыми «..». Кривые, соединяющие точки описываются полиномом Бернштейна третьей степени&lt;br /&gt;
(Сергей Николаевич Бернштейн 1912). Часто их называют кубическими&lt;br /&gt;
кривыми Безье (Piere Bezier 1960).&lt;br /&gt;
&lt;br /&gt;
Компьютер обязательно должен знать каким пером (withpen&lt;br /&gt;
pencircle) и какой толщины (scaled 0.3u) рисуется текущая линия.&lt;br /&gt;
Такие объяснения могут показаться избыточными, но всегда можно скопировать предыдущую инструкцию и поправить её под свои нужды, а&lt;br /&gt;
многословность облегчает чтение кода.&lt;br /&gt;
&lt;br /&gt;
Далее этот рисунок можно использовать многократно, например,&lt;br /&gt;
для составления какого-либо узора:&lt;br /&gt;
&lt;br /&gt;
[[Изображение:Img 77 97 1.png|Img 77 97 1.png]]&lt;br /&gt;
&lt;br /&gt;
Обратите внимание, что почти все числовые значения представляют&lt;br /&gt;
из себя коэффициент умноженный на параметр, например, «2.4u».&lt;br /&gt;
Параметру «u» можно присвоить числовое значение в миллиметрах&lt;br /&gt;
(параметр «mm»). Есть несколько определённых по умолчанию значений длины, например, «cm» соответствует сантиметру.&lt;br /&gt;
&lt;br /&gt;
При программировании на Meta по мере возможности используйте&lt;br /&gt;
параметрические зависимости. Нет необходимости «прибивать что-то&lt;br /&gt;
гвоздями». В данном случае наличие параметра позволяет легко изменить масштаб рисунка:&lt;br /&gt;
&lt;br /&gt;
[[Изображение:Img 77 97 2.png|Img 77 97 2.png]]&lt;br /&gt;
&lt;br /&gt;
Очевидно, что в предложенном решении одного параметра мало,&lt;br /&gt;
так как «u» контролирует не только геометрические размеры, но и размеры пера.&lt;br /&gt;
Точки, также можно представить как переменные, имеющие тип pair:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;latex&amp;quot;&amp;gt;&lt;br /&gt;
numeric u;&lt;br /&gt;
u:=0.5mm;&lt;br /&gt;
pair A,B;&lt;br /&gt;
A:=(1u,2u);B=(5u,10u);&lt;br /&gt;
draw A--B withpen pencircle scaled 0.3u;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Следует обратить внимание, что знак присвоения «:=» в случае&lt;br /&gt;
переменной A и знак равенства в случае переменной B здесь действует&lt;br /&gt;
одинаково. Отличия возникают, когда используется уникальная способность Meta воспринимать и решать систему линейных уравнений. В&lt;br /&gt;
дальнейшем в объяснениях буквы A и B будут использоваться как переменные типа точка.&lt;br /&gt;
&lt;br /&gt;
Meta позволяет создавать свои типы перьев, но для рисования простых рисунков использовать что-то отличное от круглого пера (pencircle)&lt;br /&gt;
нет особой необходимости. Если вам хочется расширить ваши познания&lt;br /&gt;
в этой области, то обратитесь к любому руководству по MetaFont или&lt;br /&gt;
MetaPost. Нет необходимости каждый раз указывать каким пером следует рисовать. Достаточно выбрать какое-либо перо по умолчанию с&lt;br /&gt;
помощью команды pickup, например, так:&lt;br /&gt;
 pickup pencircle scaled 0.2u;&lt;br /&gt;
&lt;br /&gt;
=== Пути ===&lt;br /&gt;
[[Изображение:Img 77 97 3.png|right|frame]]&lt;br /&gt;
Инструкции draw позволяет рисовать сплошную линию.&lt;br /&gt;
На её основе в MetaPost создана команда для рисования стрелки drawarrow. Воспользуемся&lt;br /&gt;
ей для изображения суммы векторов&lt;br /&gt;
(рис. справа)&lt;br /&gt;
&lt;br /&gt;
Кроме непосредственно команды&lt;br /&gt;
draw, в этом рисунке необходимо&lt;br /&gt;
использовать команду для вставки&lt;br /&gt;
текстовых меток label, которая&lt;br /&gt;
будет подробно разобрана&lt;br /&gt;
позже:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;latex&amp;quot;&amp;gt;&lt;br /&gt;
%Файл path.mp&lt;br /&gt;
%Закон Ньютона - векторная сумма сил&lt;br /&gt;
beginfig(1);&lt;br /&gt;
numeric u;&lt;br /&gt;
u := 1mm;&lt;br /&gt;
drawarrow (0,0)--(20u,30u) withpen pencircle scaled 0.3u;&lt;br /&gt;
label.ulft(btex \(\vec{F}_1\) etex,1/2[(0,0),(20u,30u)]);&lt;br /&gt;
drawarrow (20u,30u)--(40u,30u) withpen pencircle scaled 0.3u;&lt;br /&gt;
label.top(btex \(\vec{F}_2\) etex,1/2[(20u,30u),(40u,30u)]);&lt;br /&gt;
drawarrow (40u,30u)--(50u,10u) withpen pencircle scaled 0.3u;&lt;br /&gt;
label.urt(btex \(\vec{F}_3\) etex,1/2[(40u,30u),(50u,10u)]);&lt;br /&gt;
drawarrow (50u,10u)--(35u,15u) withpen pencircle scaled 0.3u;&lt;br /&gt;
label.llft(btex \(\vec{F}_4\) etex,1/2[(50u,10u),(35u,15u)]);&lt;br /&gt;
drawarrow (0u,0u)--(35u,15u) withpen pencircle scaled 0.8u;&lt;br /&gt;
drawarrow (0u,0u)--(35u,15u) withpen pencircle scaled 0.3u&lt;br /&gt;
withcolor white;&lt;br /&gt;
draw (0u,0u) withpen pencircle scaled 2u ;&lt;br /&gt;
label.bot(btex \(\vec{F}_1+\vec{F}_2+\vec{F}_3+\vec{F}_4\) etex,&lt;br /&gt;
1/2[(35u,15u),(0u,0u)]) rotatedaround&lt;br /&gt;
(1/2[(35u,15u),(0u,0u)],angle(35,15));&lt;br /&gt;
endfig;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Конструкция вида «1/2[A,B]» имеет тип pair и равна точке, расположенной ровно по середине между точками A и B. Точно так же можно&lt;br /&gt;
выбрать точку на линии AB, но делящую эту линию в отношении 1 к 2:&lt;br /&gt;
«1/3[A,B]», или 1 к 4: «0.2[A,B]»&lt;br /&gt;
&lt;br /&gt;
Кроме drawarrow в MetaPost определена команда drawdblarrow,&lt;br /&gt;
которая рисует кончик стрелки на обоих концах пути.&lt;br /&gt;
&lt;br /&gt;
Команды, типа draw, работают с объектами path (путь). Путь – это&lt;br /&gt;
набор из точек (тип pair) с описанием того, как эти точки соединяются&lt;br /&gt;
друг с другом. Минимальный путь – это одна точка. При рисовании такого пути на рисунке остаётся отпечаток в форме пера. Во всех приведённых здесь примерах перо имеет круглую форму pencircle, поэтому в&lt;br /&gt;
этом случае возникает просто точка. Часто бывает удобно создать переменную типа path:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;latex&amp;quot;&amp;gt;&lt;br /&gt;
%Файл path.mp&lt;br /&gt;
%Рис к 1.6.8 б) нить пропущенная через изогнутую трубу&lt;br /&gt;
beginfig(2) ;&lt;br /&gt;
numeric u;&lt;br /&gt;
u = 0.8mm;&lt;br /&gt;
path p;&lt;br /&gt;
p:=(5u,0u)--(20u,0u){dir 0}..(20u,20u)..&lt;br /&gt;
{dir 0}(20u,0u)--(35u,0u);&lt;br /&gt;
cutdraw p withpen pencircle scaled 1.5u;&lt;br /&gt;
draw p withpen pencircle scaled 1u withcolor white;&lt;br /&gt;
draw p withpen pencircle scaled 0.3u&lt;br /&gt;
dashed evenly scaled 1/2u;&lt;br /&gt;
drawarrow (-10u,0u)--(0u,0u)&lt;br /&gt;
withpen pencircle scaled 0.3u;&lt;br /&gt;
draw (-10u,0u) withpen pencircle scaled 1u;&lt;br /&gt;
draw (-10u,0u)--(5u,0u) withpen pencircle scaled 0.3u;&lt;br /&gt;
drawarrow (30u,10u)--(50u,10u)&lt;br /&gt;
withpen pencircle scaled 0.3u;&lt;br /&gt;
draw (30u,10u) withpen pencircle scaled 1u;&lt;br /&gt;
draw (35u,0u)--(45u,0u) withpen pencircle scaled 0.3u;&lt;br /&gt;
label.top(btex \(\vec{v}\) etex,(-5u,0u));&lt;br /&gt;
label.top(btex \(2\vec{v}\) etex,(40u,10u));&lt;br /&gt;
endfig;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
В данном примере требовалось изобразить трубу изогнутую буквой&lt;br /&gt;
«О», сквозь которую продета нить. Для этого определяем путь «p».&lt;br /&gt;
Затем этот путь используется в трёх командах как переменная: рисуется&lt;br /&gt;
толстая чёрная труба шириной «1.5u», внутри неё рисуется более тонкая шириной «1u» белого цвета (withcolor white) – получается полая&lt;br /&gt;
труба, а затем внутри трубы отрисовывается нить, причём нить рисуется&lt;br /&gt;
пунктиром (dashed evenly).&lt;br /&gt;
&lt;br /&gt;
[[Изображение:Img 77 98 1.png|Img 77 98 1.png]]&lt;br /&gt;
&lt;br /&gt;
Первый и последний участок изогнутой трубы прямые линии, поэтому соединение с первой и последней точкой описывается как «--».&lt;br /&gt;
Чтобы нарисовать кривую, похожую на круг, достаточно двух точек:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;latex&amp;quot;&amp;gt;&lt;br /&gt;
numeric u,R; u=1mm;R=10u;&lt;br /&gt;
pair A,B; A:=(-R,0);B:=(0,R);&lt;br /&gt;
path P; P:=A..B..cycle;&lt;br /&gt;
draw P withpen pencircle 1u;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
В этом примере определяются две точки A и B. Путь P строится по&lt;br /&gt;
этим точкам, при этом выходя из точки A, мы попадаем в точку B, а&lt;br /&gt;
затем снова в точку A: команда cycle позволяет создавать замкнутую&lt;br /&gt;
кривую. Настройки Meta по умолчанию таковы, что получившаяся кривая достаточно хорошо совпадает с точной окружностью. Чтобы лучше&lt;br /&gt;
совпадать с окружностью нужно больше «опорных» точек. Для обычных&lt;br /&gt;
рисунков хватает точности построения по двум точкам, но всё-таки надо&lt;br /&gt;
осознавать, что отличие есть.&lt;br /&gt;
&lt;br /&gt;
Для уточнения пути в некоторых точках можно указать под каким&lt;br /&gt;
углом должна подходить кривая к этой точке. Инструкция вида «dir »&lt;br /&gt;
если она находится перед точкой, указывает под каким углом кривая&lt;br /&gt;
должна подходить, а после точки – под каким углом кривая должна уходить. – угол в градусах от оси абсцисс.&lt;br /&gt;
&lt;br /&gt;
Для указания направления можно так же воспользоваться сокращениями left, right, up и down, которые означают, соответственно, влево,&lt;br /&gt;
вправо, вверх и вниз.&lt;br /&gt;
&lt;br /&gt;
Существует несколько типов соединений между точками. Два из них&lt;br /&gt;
«..» и «--» мы уже изучили. Из других типов полезен тип «&amp;amp;» – «сращивание» (объединение двух путей без влияния друг на друга) и «---» –&lt;br /&gt;
«натянутая» линия (то же, что и «--», но влияет на соседние соединительные участки).&lt;br /&gt;
&lt;br /&gt;
Обратите внимания на команду cutdraw. Так как MetaPost рисует с&lt;br /&gt;
помощью перьев, то в случае круглого пера (pencircle), концы линий&lt;br /&gt;
также округлые. В случае, когда необходимо «обрубить» концы, избавиться от округлостей на концах линий, и используется эта инструкция.&lt;br /&gt;
Следует отметить, что эта команда «подчистки» концов использует другую более общую команду&lt;br /&gt;
 cutoff(«точка»,«угол»);&lt;br /&gt;
&lt;br /&gt;
=== Вставка текста ===&lt;br /&gt;
MetaFont был создан как специализированный инструмент для создания шрифтов. MetaPost создавался как инструмент для рисования&lt;br /&gt;
любых изображений, поэтому в него был встроен довольно мощный&lt;br /&gt;
механизм вставки текста. Работая совместно с LaTeX, MetaPost позволяет использовать всю мощь текстового процессора для создания надписей. Кроме всего прочего, иметь в рисунках те же шрифты, что и в тексте&lt;br /&gt;
просто красиво.&lt;br /&gt;
&lt;br /&gt;
Разберём это на примере треугольник Паскаля – треугольной числовой таблицы для составления биномиальных коэффициентов. По боковым сторонам треугольника стоят единицы, внутри треугольника числа&lt;br /&gt;
образуются сложением двух чисел, стоящих над данным:&lt;br /&gt;
&lt;br /&gt;
[[Изображение:Img 77 98 2.png|Img 77 98 2.png]]&lt;br /&gt;
&lt;br /&gt;
Так как нижние строки из-за увеличения разрядности чисел расползались, то для представления появилась необходимость уменьшить их&lt;br /&gt;
геометрические размеры. В коде так же использовались циклы, которые&lt;br /&gt;
будут разобраны позже. Команда show позволяет отлаживать код,&lt;br /&gt;
выдавая значения переменных на экран во время компиляции рисунка с&lt;br /&gt;
помощью mpost.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;latex&amp;quot;&amp;gt;&lt;br /&gt;
%Файл pic.mp&lt;br /&gt;
%Треугольник Паскаля&lt;br /&gt;
beginfig(5) ;&lt;br /&gt;
numeric u;&lt;br /&gt;
u = 1.mm;&lt;br /&gt;
numeric dy,dx,x,y,n[ ][ ],i,j,sy,ds,nlast;&lt;br /&gt;
dy:=5u;dx:=5u;x=0;y=0;&lt;br /&gt;
ds=0.04;sy=0.032;nlast=14;&lt;br /&gt;
picture z;&lt;br /&gt;
for i:=0 upto nlast:&lt;br /&gt;
dy:=dy*(1-sy);&lt;br /&gt;
y:=y-dy;&lt;br /&gt;
for j:=0 upto i:&lt;br /&gt;
if (j=0) or (j=i):&lt;br /&gt;
n[i][j]:=1;&lt;br /&gt;
else:&lt;br /&gt;
n[i][j]:=n[i-1][j-1]+n[i-1][j];&lt;br /&gt;
fi&lt;br /&gt;
% show i,j,n[i][j];&lt;br /&gt;
z:=thelabel(decimal(n[i][j]),(0,0));&lt;br /&gt;
x:=dx*(j-i/2);&lt;br /&gt;
label(z scaled (1-ds*i),(x,y));&lt;br /&gt;
endfor&lt;br /&gt;
z:=thelabel.lft(decimal(i)&amp;amp;”:”,(0,0));&lt;br /&gt;
label(z scaled (1-ds*i),(dx*(-nlast/2-1),y));&lt;br /&gt;
endfor&lt;br /&gt;
label.rt(btex \((a+b)^n=\) etex,(5u,-5u));&lt;br /&gt;
label.rt(btex \(=\sum C^k_na^kb^{n-k}\) etex,&lt;br /&gt;
(10u,-10u));&lt;br /&gt;
label.lft(btex Треугольник Паскаля etex&lt;br /&gt;
rotated 56,(-5u,-20u));&lt;br /&gt;
endfig ;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Команда decimal делает из переменной типа numeric строку. Две&lt;br /&gt;
строки можно слить с помощью операнда «&amp;amp;».&lt;br /&gt;
&lt;br /&gt;
Для того чтобы вставить текстовую метку в рисунок, необходимо&lt;br /&gt;
получить на входе текстовую строку, которую, возможно, надо будет&lt;br /&gt;
преобразовать с помощью LaTeX, и точку где эту строку следует&lt;br /&gt;
расположить:&lt;br /&gt;
 label(“text string”,A);&lt;br /&gt;
Полезно ещё уточнить с какой стороны от указанной точки расположить текстовую метку. Уточнение производится с помощью суффикса,&lt;br /&gt;
который добавляется макросу label через точку. Всего существует&lt;br /&gt;
восемь стандартных суффиксов: «.rt» – расположить справа, «.lft» –&lt;br /&gt;
слева, «.top» – сверху, «.bot» – снизу, «.llft» – расположить снизу и&lt;br /&gt;
слева по диагонали, «.lrt» – снизу и справа, «.ulft» – сверху и слева,&lt;br /&gt;
«.urt» – сверху и справа.&lt;br /&gt;
&lt;br /&gt;
Если label передаётся просто строка (тип string), то текст обрабатывается силами MetaPost и всё, что выходит за пределы ASCII-таблицы с&lt;br /&gt;
большой вероятностью не отобразится. Для того чтобы строка была&lt;br /&gt;
обработана LaTeX, необходимо указать это с помощью разделителей&lt;br /&gt;
btex и etex. Строка между этими разделителями обрабатывается LaTeX,&lt;br /&gt;
при этом в качестве заголовка используются инструкции перечисленные&lt;br /&gt;
в начале mp-файла между verbatimtex и etex. Таким образом можно&lt;br /&gt;
использовать кириллицу и любую конструкцию, которую понимает&lt;br /&gt;
LaTeX.&lt;br /&gt;
&lt;br /&gt;
В некоторых случаях команде label удобно передавать не строку, а&lt;br /&gt;
картинку picture. В нашем случае это было необходимо, так как надпись&lt;br /&gt;
надо было масштабировать. Объект picture представляет из себя совокупность примитивов типа путей и точек, поэтому его можно трансформировать. Команда thelabel создаёт такую картинку. Объект, заключённый между btex и etex так же является картинкой.&lt;br /&gt;
&lt;br /&gt;
=== Заливка ===&lt;br /&gt;
[[Изображение:Img 77 99 1.png|right|frame]]&lt;br /&gt;
Кроме рисования кривых часто бывает необходимо закрасить какую-либо замкнутую область.&lt;br /&gt;
Для этого сущест-&lt;br /&gt;
вует команда fill. На&lt;br /&gt;
вход команды fill&lt;br /&gt;
подаётся объект типа&lt;br /&gt;
path, при этом путь&lt;br /&gt;
должен быть замкну-&lt;br /&gt;
тым, то есть оканчи-&lt;br /&gt;
ваться командой cycle. Команда cycle автоматически замыкает&lt;br /&gt;
кривую.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;latex&amp;quot;&amp;gt;&lt;br /&gt;
%Файл pic.mp&lt;br /&gt;
%Рис к 1.6.20 а) струя под углом, разбивающаяся о пол&lt;br /&gt;
beginfig(10) ;&lt;br /&gt;
numeric u;&lt;br /&gt;
u = 1mm;&lt;br /&gt;
numeric st;st:=u/(sqrt 3);&lt;br /&gt;
path p;&lt;br /&gt;
p:=(0,10u)--(18u,10u){dir 0}..{dir 30}(22u,10u+2st)--&lt;br /&gt;
(50u,10u+30st){dir -90}..{dir -90}(60u,5u+20st)--&lt;br /&gt;
(42u,5u+2st){dir -150}..{dir 0}(42u,5u)--&lt;br /&gt;
(60u,5u){dir -120}..{dir -120}(60u,0u)--&lt;br /&gt;
(0u,0u){dir 60}..{dir 60}cycle;&lt;br /&gt;
fill p withcolor 0.8 white;&lt;br /&gt;
draw ((40u,5u)+10u*dir 30){dir -60}..{dir -90}(50u,5u);&lt;br /&gt;
label(btex \(\alpha\) etex,(53u,8u));&lt;br /&gt;
draw (0u,0)--(60u,0u) withpen pencircle scaled 0.8u;&lt;br /&gt;
numeric R,alpha;R:=12u;alpha=30;&lt;br /&gt;
drawarrow (25u+25u,5u+25st)--&lt;br /&gt;
((25u+25u,5u+25st)-R*dir alpha)&lt;br /&gt;
withpen pencircle scaled 0.6u;&lt;br /&gt;
label.ulft(btex \(\vec{v}\) etex,1/2[(25u+25u,5u+25st),&lt;br /&gt;
((25u+25u,5u+25st)-R*dir alpha)]);&lt;br /&gt;
drawarrow (20u,5u)--(20u-R,5u)&lt;br /&gt;
withpen pencircle scaled 0.6u;&lt;br /&gt;
label.top(btex \(\vec{v}\) etex,(20u-R/2,5u));&lt;br /&gt;
drawarrow (45u,2.5u)--(45u+R,2.5u)&lt;br /&gt;
withpen pencircle scaled 0.6u;&lt;br /&gt;
label.lft(btex \(\vec{v}\) etex,(45u,2.5u));&lt;br /&gt;
endfig ;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Для fill существует противоположная по смыслу команда unfill,&lt;br /&gt;
которая, соответственно, убирает заливку в выбранной окрестности.&lt;br /&gt;
Если вы планируете использовать эти команды, то изучите соответствующий раздел «Всё про METAFONT» Кнута, так как влияние этих команд&lt;br /&gt;
друг на друга не совсем тривиально. Дело в том, что при наложении&lt;br /&gt;
друг на друга двух заливок в месте пересечения образуется «двойной&lt;br /&gt;
слой краски» и для того чтобы убрать его необходимо дважды вызывать&lt;br /&gt;
команду unfill. Команда unfill действует схоже, только число «слоёв&lt;br /&gt;
краски» становится отрицательным. Для сведения всё к ситуации когда&lt;br /&gt;
краска либо есть (один слой), либо её нет используется команда&lt;br /&gt;
«выравнивания» cullit.&lt;br /&gt;
&lt;br /&gt;
Обратите внимание, что точку можно задать не только парой чисел:&lt;br /&gt;
«(x,y)» – Декартова система координат, но и радиусом с направлением&lt;br /&gt;
«R*dir » – полярные координаты.&lt;br /&gt;
&lt;br /&gt;
=== Цвета ===&lt;br /&gt;
Ещё одно важное отличие MetaPost от MetaFont – это наличие цвета.&lt;br /&gt;
Работа с цветом обычно сложнее, чем работа с чёрно-белым рисунком.&lt;br /&gt;
До сих пор процедура переноса электронного цветного рисунка на бумагу не является тривиальной. Но время идёт, и цветные принтеры становятся всё доступней. Кроме того, хорошие чисто электронные тексты, не&lt;br /&gt;
привязанные к твёрдой копии, так же становятся весьма распространёнными. Поэтому если необходимо, то следует пользоваться цветом,&lt;br /&gt;
естественно, если вы знаете что делать. В случае простого рисунка цвет,&lt;br /&gt;
как правило, только отвлекает.&lt;br /&gt;
&lt;br /&gt;
В MetaPost управление цветом реализовано на довольно низком&lt;br /&gt;
уровне. Цвет определяется объектом типа color и представляет из себя&lt;br /&gt;
тройку чисел принимающих значение от 0 до 1: «(r,g,b)», где r соответствует красной, g – зелёной, а b – голубой компоненте. Существует&lt;br /&gt;
пять предопределённых цветовых констант: red (1,0,0), green (0,1,0),&lt;br /&gt;
blue (0,0,1), а так же black (1,1,1) и white (0,0,0).&lt;br /&gt;
&lt;br /&gt;
Нарисовать объект, выбранным цветом, можно с помощью инструкции withcolor за которой следует сам цвет. Цвета можно складывать,&lt;br /&gt;
вычитать, умножать на число. Пользуясь базовыми определениями&lt;br /&gt;
можно создать более сложные объекта. Например как этот спектр:&lt;br /&gt;
&lt;br /&gt;
[[Изображение:Img 77 99 2.jpg|Img 77 99 2.jpg]]&lt;br /&gt;
&lt;br /&gt;
Код, создающий эту картинку, далёк от совершенства, но он прост,&lt;br /&gt;
и его можно улучшать в случае необходимости.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;latex&amp;quot;&amp;gt;&lt;br /&gt;
%Файл colors.mp&lt;br /&gt;
def spectrline(expr ic,c,l,w,dw) =&lt;br /&gt;
begingroup&lt;br /&gt;
save i,ifirst,ilast,istep,icc;&lt;br /&gt;
color icc;&lt;br /&gt;
if (ic&amp;gt;0):istep:=1;ifirst:=0;ilast=255;&lt;br /&gt;
else:istep:=-1;ifirst=0;ilast:=-255; fi;&lt;br /&gt;
if (abs(ic)=1):icc:=red;fi;&lt;br /&gt;
if (abs(ic)=2):icc:=green;fi;&lt;br /&gt;
if (abs(ic)=3):icc:=blue;fi;&lt;br /&gt;
for i:=ifirst step istep until ilast:&lt;br /&gt;
draw ((0u,0u)--(0u,l)) shifted (w+(dw/2*abs(i),0))&lt;br /&gt;
withpen pencircle scaled dw withcolor (c+i/255*icc);&lt;br /&gt;
endfor;&lt;br /&gt;
endgroup;&lt;br /&gt;
enddef;&lt;br /&gt;
%спектр&lt;br /&gt;
beginfig(1) ;&lt;br /&gt;
color current;&lt;br /&gt;
u:=1mm;w:=200u;dw:=w/512;l:=5u;&lt;br /&gt;
current:=(1,0,0);&lt;br /&gt;
spectrline(2,current,l,(1/4w,0u),dw)&lt;br /&gt;
current:=(1,1,0);&lt;br /&gt;
spectrline(-1,current,l,(1/2w,0u),dw)&lt;br /&gt;
current:=(0,1,0);&lt;br /&gt;
spectrline(3,current,l,(3/4w,0u),dw)&lt;br /&gt;
current:=(0,1,1);&lt;br /&gt;
spectrline(-2,current,l,(w,0u),dw)&lt;br /&gt;
endfig ;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
В примере используется макрос spectrline для уменьшения&lt;br /&gt;
размера кода.&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF76:MetaPost</id>
		<title>LXF76:MetaPost</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF76:MetaPost"/>
				<updated>2008-05-16T19:14:36Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: {{Цикл/MetaPost}}&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/MetaPost}}&lt;br /&gt;
== Введение в MetaPost ==&lt;br /&gt;
''Каждая иллюстрация – это целая история. '''Евгений Балдин''' начинает урок рисования для закоренелых ТеХнарей.''&lt;br /&gt;
&lt;br /&gt;
Люди делятся на тех, кто умеет рисовать, и тех, кто не умеет.&lt;br /&gt;
Причём вторых большинство. В этом нет ничего плохого или&lt;br /&gt;
хорошего – такова жизнь. Хороший иллюстратор – редкость.&lt;br /&gt;
&lt;br /&gt;
Компьютерные технологии дают возможность создавать высококачественные документы особенно не концентрируясь на проблеме оформления. Всю черновую работу делает за вас компьютер. Например,&lt;br /&gt;
система LaTeX фактически заменяет собой электронную типографию,&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;br /&gt;
но с другой – очень тяжело объяснить, как же я этого достиг. Цель этого текста – популяризовать создание иллюстраций с помощью&lt;br /&gt;
MetaPost.&lt;br /&gt;
&lt;br /&gt;
Желание контролировать всё в процессе создания книги привело&lt;br /&gt;
Дональда Э. Кнута (Donald E. Knuth) к созданию программ TeX и&lt;br /&gt;
METAFONT.&lt;br /&gt;
&lt;br /&gt;
Изначально METAFONT предназначался для создания шрифтов и&lt;br /&gt;
результатом его работы был растр с изображением шрифта. Позже&lt;br /&gt;
аспирант Д. Э. Кнута Джон Хобби (John Hobby) модифицировал&lt;br /&gt;
METAFONT таким образом, что результатом работы программы стала&lt;br /&gt;
картинка в формате EPS (Encusulated PostScript).&lt;br /&gt;
MetaPost – это программа для тех, кто может объяснить компьютеру, что он хочет. MetaPost чрезвычайно полезен в тех случаях, когда&lt;br /&gt;
картинку проще описать логически, нежели образно. Даже если Вы не&lt;br /&gt;
умеете рисовать, результат может получиться вполне приличный, потому что «виртуальный карандаш» под управлением компьютера дрожать не будет.&lt;br /&gt;
&lt;br /&gt;
MetaPost проектировался как простая программа, которую можно&lt;br /&gt;
относительно быстро настроить под свои нужды. Он вполне обозрим и&lt;br /&gt;
компактен. Многие «правильные» программы, работающие с векторной графикой, такие как gnuplot и xfig, умеют экспортировать в формат MetaPost.&lt;br /&gt;
&lt;br /&gt;
=== Здравствуй, мир ===&lt;br /&gt;
Когда изучается новая программная технология первое, что надо сделать – это сказать: «Здравствуй мир!». Что мы и сделаем, правда,&lt;br /&gt;
пока на английском. Для этого следует создать файл helloworld.mp&lt;br /&gt;
со следующим содержанием:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;latex&amp;quot;&amp;gt;&lt;br /&gt;
%Для просмотра&lt;br /&gt;
prologues := 1;&lt;br /&gt;
%Простой Hello World&lt;br /&gt;
beginfig(1);&lt;br /&gt;
label(“Hello World! “,(0,0));&lt;br /&gt;
endfig;&lt;br /&gt;
% «конец обработки» – необходимо вставить в конце файла&lt;br /&gt;
end.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Далее скомпилируем этот код:&lt;br /&gt;
 &amp;gt; mpost helloworld.mp&lt;br /&gt;
В результате полученный файл helloworld.1 можно посмотреть с&lt;br /&gt;
помощью любой программой понимающей PostScript, например, с&lt;br /&gt;
помощью gv:&lt;br /&gt;
&lt;br /&gt;
[[Изображение:Img 76 116 1.png|center|frame|Первый Hello World на MetaPost]]&lt;br /&gt;
&lt;br /&gt;
Разнообразим пример. Создадим файл linuxformat.mp со следующим содержимым:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;latex&amp;quot;&amp;gt;&lt;br /&gt;
% А теперь мы его завращали и раскрасили&lt;br /&gt;
beginfig(1);&lt;br /&gt;
for alpha:=90 step -3 until 0:&lt;br /&gt;
label(btex Linux Format etex&lt;br /&gt;
scaled (5*(1-alpha/100)) rotated alpha,(0,0))&lt;br /&gt;
withcolor (max(1-alpha/45,0)*red+&lt;br /&gt;
min(alpha/45,2-alpha/45)*green+&lt;br /&gt;
max(alpha/45-1,0)*blue);&lt;br /&gt;
endfor;&lt;br /&gt;
endfig;&lt;br /&gt;
end.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Скомпилируем код и результат преобразуем в pdf:&lt;br /&gt;
 &amp;gt; mpost linuxformat.mp&lt;br /&gt;
 &amp;gt; pstopdf linuxformat.1&lt;br /&gt;
Полученный в результате этой операции файл linuxformat-1.pdf&lt;br /&gt;
можно посмотреть, например, с помощью программы acroread или&lt;br /&gt;
xpdf.&lt;br /&gt;
&lt;br /&gt;
[[Изображение:Img 76 117 1.jpg|center|frame|«Продвинутый» Hello World на MetaPost]]&lt;br /&gt;
&lt;br /&gt;
Всё, что находится между btex и etex обрабатываются внешней&lt;br /&gt;
программой. По умолчанию это TeX. Чтобы воспользоваться возможностями LaTeX, надо в самом начале linuxformat.mp строчки вида:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;latex&amp;quot;&amp;gt;&lt;br /&gt;
verbatimtex \documentclass{article}&lt;br /&gt;
\begin{document}&lt;br /&gt;
etex;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Эти строчки указывают mpost, что при обработке любых текстовых&lt;br /&gt;
вставок им должны предшествовать команды&lt;br /&gt;
\documentclass{article} и \begin{document}.&lt;br /&gt;
&lt;br /&gt;
Добавим в linuxformat.mp ещё один рисунок. Для этого скопируем уже имеющийся код первого рисунка, вставим его до заключительной команды «end.» и немного подправим первые три строчки:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;latex&amp;quot;&amp;gt;&lt;br /&gt;
%Математика вместо Hello World&lt;br /&gt;
beginfig(2);&lt;br /&gt;
for alpha:=90 step -9 until 0:&lt;br /&gt;
label(btex \(f(x)=\frac{1}{\sqrt{2\pi}\,\sigma}&lt;br /&gt;
\int\limits_{-\infty}^{\infty}&lt;br /&gt;
e^{-\frac{x^2}{2\sigma^2}}dx\) etex&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Создание новых картинок на базе уже имеющегося кода в MetaPost –&lt;br /&gt;
обычное дело. Со временем накапливается своя библиотечка примитивов, что сильно облегчает создание новых иллюстраций. Кажущаяся&lt;br /&gt;
сложность выражений компенсируется исключительной гибкостью&lt;br /&gt;
&lt;br /&gt;
[[Изображение:Img 76 117 2.jpg|center|frame|Математическая вставка]]&lt;br /&gt;
&lt;br /&gt;
Вместо того чтобы запускать mpost с опцией -tex=latex, можно&lt;br /&gt;
установить переменную окружения TEX равную latex. В bash это можно&lt;br /&gt;
сделать так:&lt;br /&gt;
 &amp;gt; export TEX=latex&lt;br /&gt;
Как видно из предыдущего примера, MetaPost и LaTeX умеют&lt;br /&gt;
неплохо работать вместе. Усовершенствуем немного linuxformat.mp.&lt;br /&gt;
Заменим первые три строчки в файле на следующий код:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;latex&amp;quot;&amp;gt;&lt;br /&gt;
verbatimtex \input{preheader}&lt;br /&gt;
\begin{document}&lt;br /&gt;
etex;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
и создадим файл preheader.tex с примерно следующим&lt;br /&gt;
содержанием:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;latex&amp;quot;&amp;gt;&lt;br /&gt;
\documentclass[12pt]{article}&lt;br /&gt;
% стандартная простейшая русификация&lt;br /&gt;
\usepackage[warn]{mathtext}&lt;br /&gt;
\usepackage[T2A]{fontenc}&lt;br /&gt;
\usepackage[koi8-r]{inputenc}&lt;br /&gt;
\usepackage[english,russian]{babel}&lt;br /&gt;
\usepackage{indentfirst}%first paragraph indent&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Это стандартный заголовок для файлов LaTeX. Если Вы набираете&lt;br /&gt;
свои тексты в LaTeX, то можете поместить в preheader.tex всю свою&lt;br /&gt;
преамбулу и включить её с помощью команды \input. Это позволит&lt;br /&gt;
создавать текстовые вставки в картинках MetaPost тем же шрифтом,&lt;br /&gt;
что и в обычном тексте, а также позволит пользоваться любыми предопределёнными вами командами.&lt;br /&gt;
&lt;br /&gt;
Следует обратить внимание, что чем больше будет разрастаться&lt;br /&gt;
заголовок, тем дольше будет обрабатываться META-код. Для увеличения скорости лучше всего воспользоваться классом minimal вместо&lt;br /&gt;
article и убрать все ненужные для рисования картинок пакеты.&lt;br /&gt;
&lt;br /&gt;
Добавим третью картинку в linuxformat.mp, чуть изменив первоначальный код:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;latex&amp;quot;&amp;gt;&lt;br /&gt;
verbatimtex \input{preheader}&lt;br /&gt;
\begin{document}&lt;br /&gt;
etex;&lt;br /&gt;
...&lt;br /&gt;
%изменим направление вращения&lt;br /&gt;
beginfig(3) ;&lt;br /&gt;
for alpha:=-90 step 3 until 0:&lt;br /&gt;
label(btex LinuxFormat в России etex&lt;br /&gt;
scaled (5*(1+alpha/100)) rotated alpha,(0,0))&lt;br /&gt;
withcolor (max(1+alpha/45,0)*red+&lt;br /&gt;
min(-alpha/45,2+alpha/45)*green+&lt;br /&gt;
max(-alpha/45-1,0)*blue);&lt;br /&gt;
endfor;&lt;br /&gt;
endfig ;&lt;br /&gt;
end.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Теперь мы можем говорить по русски.&lt;br /&gt;
&lt;br /&gt;
[[Изображение:Img 76 117 3.jpg|center|frame|Говорим по русски]]&lt;br /&gt;
&lt;br /&gt;
=== MetaPost-конвейер ===&lt;br /&gt;
[[Изображение:Img 76 118 1.png|center|]]&lt;br /&gt;
Чуть подробнее остановимся на том, что же происходит. На вход программы MetaPost подаётся «META-картинка». «META-картинка» — это текстовый mp-файл с инструкциями на языке META. В одном mp-файле можно хранить несколько описаний картинок. При компиляции с помощью mpost создаются файлы с тем же именем, что и у исходного файла, но с расширениями в виде чисел, которые указываются в декларации beginfig. Результирующие файлы сразу можно вставлять в LaTeX-тексты с помощью обычного \includegraphics. Для этого достаточно в заголовок tex-файла добавить команду&lt;br /&gt;
&amp;lt;source lang=&amp;quot;latex&amp;quot;&amp;gt;\DeclareGraphicsRule{*}{eps}{*}{}&amp;lt;/source&amp;gt;&lt;br /&gt;
От «правильных» eps-файлов они отличаются только тем, что в&lt;br /&gt;
них не «внедрены» шрифты, поэтому просмотреть их без дополнительной обработки не удастся.&lt;br /&gt;
&lt;br /&gt;
Шрифты можно внедрить посредством программ latex и dvips с&lt;br /&gt;
результатом в виде eps-файла или скрипта mptopdf с результатом в&lt;br /&gt;
виде pdf-файла. Эти картинки уже можно просматривать любой программой, которая поддерживает данные векторные форматы.&lt;br /&gt;
&lt;br /&gt;
=== Среда разработки ===&lt;br /&gt;
Удобная среда разработки – понятие весьма относительное. Удобство&lt;br /&gt;
зависит исключительно от ваших предпочтений. Здесь будет представлена среда удобная для меня. Подробности настройки и установки упоминаемых здесь пакетов выходят за рамки этого текста.&lt;br /&gt;
&lt;br /&gt;
В качестве базовой операционной системы я использую Linux. Это&lt;br /&gt;
предоставляет в мое распоряжение стандартные средства обработки&lt;br /&gt;
текстовых данных, которые поставляются с этой системой. Например,&lt;br /&gt;
ниже будет упомянута утилита make, которая позволяет автоматизировать ряд стандартных действий.&lt;br /&gt;
&lt;br /&gt;
В качестве базового дистрибутива LaTeX я использую дистрибутив&lt;br /&gt;
TeX Live. На сегодня этот дистрибутив является наиболее полным из&lt;br /&gt;
дистрибутивов LaTeX. Установочный образ для CD можно взять на&lt;br /&gt;
любом из CTAN-архивов (Comprehensive TeX Archive Network).&lt;br /&gt;
В качестве базового редактора я использую emacs. Если вы работаете с текстами в LaTeX-формате, то при настройке этого редактора&lt;br /&gt;
следует включить пакеты auctex&amp;lt;ref&amp;gt;Продвинутая система для работы с проектами LaTeX.&amp;lt;/ref&amp;gt; и reftex&amp;lt;ref&amp;gt;Автоматизация работы со ссылками.&amp;lt;/ref&amp;gt; . Emacs имеет простейшую встроенную поддержку для редактирования файлов в формате&lt;br /&gt;
MetaPost.&lt;br /&gt;
&lt;br /&gt;
Для автоматизации создания eps-картинок я использую Makefile&lt;br /&gt;
примерно следующего вида:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#временный файл&lt;br /&gt;
tmp_file := tmp_file&lt;br /&gt;
#программы&lt;br /&gt;
LATEX := latex&lt;br /&gt;
MPOST := mpost -tex=latex&lt;br /&gt;
DVIPS := dvips&lt;br /&gt;
all:&lt;br /&gt;
@echo “run: make mpfile.n.eps”&lt;br /&gt;
%.eps: % preheader.tex&lt;br /&gt;
@echo “\input{preheader}”&amp;gt;$(tmp_file).tex&lt;br /&gt;
@echo “\DeclareGraphicsRule{*}{eps}{*}{}”&amp;gt;&amp;gt;\&lt;br /&gt;
$(tmp_file).tex&lt;br /&gt;
@echo “\nofiles”&amp;gt;&amp;gt;$(tmp_file).tex&lt;br /&gt;
@echo “\begin{document}”&amp;gt;&amp;gt; $(tmp_file).tex&lt;br /&gt;
@echo “\thispagestyle{empty}”&amp;gt;&amp;gt; $(tmp_file).tex&lt;br /&gt;
@echo “\includegraphics{$(basename $@)}”&amp;gt;&amp;gt;\&lt;br /&gt;
$(tmp_file).tex&lt;br /&gt;
@echo “\end{document}”&amp;gt;&amp;gt; $(tmp_file).tex&lt;br /&gt;
@$(LATEX) $(tmp_file)&lt;br /&gt;
@$(DVIPS) -E -o $@ $(tmp_file)&lt;br /&gt;
@rm $(tmp_file).*&lt;br /&gt;
clean:&lt;br /&gt;
@rm -f mpx* *~ *.log *.mpx&lt;br /&gt;
@rm -f $(tmp_file).*&lt;br /&gt;
#Зависимости для mpost-картинок.&lt;br /&gt;
#По одной для каждого числа из beginfig&lt;br /&gt;
%.1: %.mp preheader.tex preheader.mp&lt;br /&gt;
$(MPOST) $&amp;lt;&lt;br /&gt;
...&lt;br /&gt;
%.64: %.mp preheader.tex preheader.mp&lt;br /&gt;
$(MPOST) $&amp;lt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Чтобы на выходе получить готовую eps-картинку с уже «внедрёнными» шрифтами, которую можно вставить уже куда угодно достаточно выполнить следующую команду:&lt;br /&gt;
 &amp;gt; make &amp;lt;имя mp-файлы&amp;gt;.&amp;lt;номер картинки&amp;gt;.eps&lt;br /&gt;
Обычно, mp-файлам даются короткие имена.&lt;br /&gt;
Если в качестве результирующего формата картинок вас интересует PDF, то в Makefile можно добавить что-то вроде:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
MPTOPDF := mptopdf&lt;br /&gt;
MV := mv&lt;br /&gt;
%.pdf: % preheader.tex&lt;br /&gt;
@$(MPTOPDF) $&amp;lt;&lt;br /&gt;
@$(MV) `echo $&amp;lt; | sed -e \&lt;br /&gt;
“s/\.\([0-9]\+\)$$/-\1.pdf/”` $&amp;lt;.pdf&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Чуть-чуть о META ===&lt;br /&gt;
В качестве базового языка, инструкции которого подаются на вход программы MetaPost используется язык META.&lt;br /&gt;
&lt;br /&gt;
Язык META поддерживает следующие типы данных:&lt;br /&gt;
* boolean объект булева типа, то есть либо true, либо false,&lt;br /&gt;
* numeric обычное число (по умолчанию, если переменная не описана, то она имеет тип numeric),&lt;br /&gt;
* pair точка – пара чисел (x, y) в случае декартовых координат или (R*dir ) в случае полярных координат,&lt;br /&gt;
* pen перо – то, чем компьютер рисует (в подавляющем большинстве случаев используется круглое перо pencircle),&lt;br /&gt;
* color цвет – тройка чисел (r, g, b),&lt;br /&gt;
* path путь – совокупность точек с описанием соединения между ними,&lt;br /&gt;
* picture картинка – совокупность путей и точек,&lt;br /&gt;
* string строка – ASCII-строка,&lt;br /&gt;
* transform преобразования – линейные преобразования, которые можно применять к объектам типа pair, pen, path и picture.&lt;br /&gt;
Имена переменных в META могут состоять из нескольких лексем.&lt;br /&gt;
Лексемы могут быть либо буквенными, либо числовыми. Например,&lt;br /&gt;
переменная x1l состоит из трёх лексем. Её можно переписать более&lt;br /&gt;
понятным способом x[1].l, то есть числовая лексема по сути указывает&lt;br /&gt;
на номер элемента в массиве, а следующая за ней буква уточняет элемент структуры. Возможность упускать «[].» в написании имён переменных упрощает в некоторых случаях восприятие кода (x1l – это x-координата границы линии слева по направлению движения для первой точки пути z[]) и сокращает объём программы. В замен, если Вам&lt;br /&gt;
нужны просто переменные без подобных особенностей, то Вам придётся ограничиться только буквенными комбинациями.&lt;br /&gt;
&lt;br /&gt;
Все переменные необходимо объявлять перед использованием.&lt;br /&gt;
Исключением являются переменные типа numeric. Массивы объявляются и используются следующим образом:&lt;br /&gt;
 pair w[];&lt;br /&gt;
 w1:=(10,5);&lt;br /&gt;
 w[2]=w[1];&lt;br /&gt;
Взаимодействие переменных, чисел и операторов вполне естественно, но достаточно нетривиально. Описание этого достойно отдельного раздела. В любом случае следует действовать по правилу: если&lt;br /&gt;
сомневаетесь, то расставляйте скобки в нужных местах.&lt;br /&gt;
&lt;br /&gt;
В META можно опускать некоторые из операторов для сокращения&lt;br /&gt;
записей, например, 2*x соответствует записи 2x. Но будьте осторожны: 1/2x это 0.5x, что более естественно с точки зрения математики,&lt;br /&gt;
но не программирования. В META сначала обрабатываются числовые&lt;br /&gt;
лексемы.&lt;br /&gt;
&lt;br /&gt;
Набор стандартных вычислительных операций расширен с учётом&lt;br /&gt;
специализации языка. В частности, например, поддерживаются операции пифагорова сложения a++b=(a&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;+b&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;)1/2, пифагорова вычитания&lt;br /&gt;
a+-+b=(a&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;-b&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;)1/2, целочисленное деление div и возведение в степень&lt;br /&gt;
x**y=xy.&lt;br /&gt;
&lt;br /&gt;
В языке присутствуют операторы цикла, условных переходов и&lt;br /&gt;
тому подобное. Отличительной особенностью META является возможность решать линейные уравнения. Например, выражение вида&lt;br /&gt;
C=1/2[A,B] означает, что точка C находится ровно посередине между&lt;br /&gt;
точками A и B.&lt;br /&gt;
&lt;br /&gt;
Программу MetaPost можно использовать в режиме калькулятора&lt;br /&gt;
для вычислений на языке META. Это позволяет проверить правильность ваших предположений относительно языка. Пример сеанса представлен ниже:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
baldin@evgueni:~$ mpost&lt;br /&gt;
This is MetaPost, Version 0.901 (Web2C 7.5.5)&lt;br /&gt;
**\relax&lt;br /&gt;
*a:=10;&lt;br /&gt;
*b:=8;&lt;br /&gt;
*c:=a+-+b;&lt;br /&gt;
*show c;&lt;br /&gt;
&amp;gt;&amp;gt; 6&lt;br /&gt;
*show (3-sqrt 5)/2;&lt;br /&gt;
&amp;gt;&amp;gt; 0.38197&lt;br /&gt;
*show angle(1,sqrt 3);&lt;br /&gt;
&amp;gt;&amp;gt; 60.00008&lt;br /&gt;
*show 2**10;&lt;br /&gt;
&amp;gt;&amp;gt; 1024.00003&lt;br /&gt;
*show infinity;&lt;br /&gt;
&amp;gt;&amp;gt; 4095.99998&lt;br /&gt;
*show epsilon;&lt;br /&gt;
&amp;gt;&amp;gt; 0.00002&lt;br /&gt;
*show infinity-infinity;&lt;br /&gt;
&amp;gt;&amp;gt; 0&lt;br /&gt;
*end&lt;br /&gt;
Transcript written on mpout.log.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
После вывода приглашения ** следует набрать команду \relax.&lt;br /&gt;
Далее можно вводить команды MetaPost. Делать это надо аккуратно,&lt;br /&gt;
так как этот режим не поддерживает «истории команд» – в начале не&lt;br /&gt;
предполагалось, что MetaPost можно будет использовать и так. С помощью команды show можно вывести результат на экран. Закончить&lt;br /&gt;
сеанс можно с помощью команды end.&lt;br /&gt;
&lt;br /&gt;
Обратите внимание, что на просьбу вывести бесконечность (infinity)&lt;br /&gt;
MetaPost выдал 4095.99998 — это максимальное значение, которое&lt;br /&gt;
может принимать переменная типа numeric. Причём в процессе&lt;br /&gt;
вычисления результат может превышать «бесконечность», но ответ&lt;br /&gt;
должен быть меньше или равен её, иначе будет выдана ошибка.&lt;br /&gt;
Минимальный шаг изменения типа numeric равен epsilon, или точнее&lt;br /&gt;
1/256/256. При создании рисунка эти ограничения не существенны, так&lt;br /&gt;
как диапазон изменения чисел вполне велик, чтобы вместить все элементы. Но в любом случае это тоже необходимо учитывать.&lt;br /&gt;
&lt;br /&gt;
Если Вы хотите вычислить однострочное выражение, то на первоначальное приглашение ** можно ввести expr. В этом случае mpost&lt;br /&gt;
считает файл expr.mf и на любое ваше действие будет выдаваться&lt;br /&gt;
ответ:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;latex&amp;quot;&amp;gt;&lt;br /&gt;
baldin@evgueni:~$ mpost&lt;br /&gt;
This is MetaPost, Version 0.901 (Web2C 7.5.5)&lt;br /&gt;
**expr&lt;br /&gt;
(/usr/local/texlive/2005/texmf-dist/metafont/base/expr.mf&lt;br /&gt;
gimme an expr: 2(a+3b)-2b&lt;br /&gt;
&amp;gt;&amp;gt; 4b+2a&lt;br /&gt;
gimme an expr: 1/3[a,b]&lt;br /&gt;
&amp;gt;&amp;gt; 0.33333b+0.66667a&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Литература ===&lt;br /&gt;
Язык META, который используется в MetaPost за некоторыми исключениями полностью соответствует диалекту META, который используется&lt;br /&gt;
в программе создания шрифтов METAFONT.&lt;br /&gt;
&lt;br /&gt;
Основной книгой по языку META является «Всё про METAFONT»&lt;br /&gt;
Дональда Э. Кнута. В 2003 году издательством Вильямс был выпущен&lt;br /&gt;
русский перевод этой классической книги (ISBN 5-8459-0442-0).&lt;br /&gt;
Исходники англоязычного оригинала «The METAFONT book» можно&lt;br /&gt;
найти на любом CTAN архиве. Эта книга, как и другие произведения Д.&lt;br /&gt;
Э. Кнута имеет несколько уровней сложностей. Даже с нулевым&lt;br /&gt;
начальным уровнем знания предмета вы можете прочитать книгу полностью — её строение это позволяет, но для дальнейшего продвижения эту книгу придётся перечитывать не один раз. Каждое прочтение&lt;br /&gt;
приносит новое понимание. Если Вы имеете хоть какое-то отношение к&lt;br /&gt;
программированию, то книги Д.Э. Кнута надо читать. Именно благодаря подобным людям информатика может претендовать на&lt;br /&gt;
фундаментальность.&lt;br /&gt;
&lt;br /&gt;
На русском языке информацию о MetaPost можно найти в&lt;br /&gt;
«Путеводителе по пакету LaTeX и его графическим расширениям»&lt;br /&gt;
М.Гуссенса, С.Ратца и Ф.Миттельбаха от издательства Мир (ISBN 5-03-003388-2).&lt;br /&gt;
&lt;br /&gt;
Все остальные источники в основном англоязычные. Прежде всего&lt;br /&gt;
это «A User’s Manual for MetaPost» Джона Хобби (Jhon D. Hobby) –&lt;br /&gt;
файл mpman.pdf. Этот текст можно найти в документации к дистрибутиву MetaPost. Этому тексту предшествовало несколько «основополагающих» статей, которые при желании можно легко найти в интернете.&lt;br /&gt;
Очень качественным руководством пользователя отметился Андрэ Хек&lt;br /&gt;
(Andr Heck)&lt;br /&gt;
http://remote.science.uva.nl/~heck/Courses/mptut.pdf&lt;br /&gt;
Также представляет интерес книга «Metafun» от Ганса Хагена (Hans&lt;br /&gt;
Hagen) – она находится в открытом доступе, имя файла metafun-p.pdf.&lt;br /&gt;
&lt;br /&gt;
В интернете можно найти интересный ресурс под названием&lt;br /&gt;
«MetaPost : examples» от Vincent Zoonekynd&lt;br /&gt;
http://zoonek.free.fr/LaTeX/.&lt;br /&gt;
Это страничка с огромным количеством простых примеров. Небольшое&lt;br /&gt;
неудобство состоит в том, что это франкоговорящий ресурс, с другой&lt;br /&gt;
стороны, текста там немного. Зеркало примеров расположено, например, здесь http://tex.loria.fr/prod-graph/zoonekynd/MetaPost/MetaPost.html.&lt;br /&gt;
&lt;br /&gt;
Ко всей перечисленной электронной документации можно&lt;br /&gt;
получить доступ через страничку CTAN, посвящённую&lt;br /&gt;
MetaPost: http://www.tug.org/MetaPost.html.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/%D0%A8%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD:%D0%A6%D0%B8%D0%BA%D0%BB/MetaPost</id>
		<title>Шаблон:Цикл/MetaPost</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/%D0%A8%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD:%D0%A6%D0%B8%D0%BA%D0%BB/MetaPost"/>
				<updated>2008-05-16T19:10:53Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: Новая: {{Цикл|MetaPost| * Введение в MetaPost * Базовые элементы * Начала автоматизации *...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл|MetaPost|&lt;br /&gt;
* [[LXF76:MetaPost|Введение в MetaPost]]&lt;br /&gt;
* [[LXF77:MetaPost|Базовые элементы]]&lt;br /&gt;
* [[LXF78:MetaPost|Начала автоматизации]]&lt;br /&gt;
* [[LXF79:MetaPost|Графики и диаграммы]]&lt;br /&gt;
* [[LXF80:MetaPost|Дополнительные главы]]&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF74-75:Slackware_10.2</id>
		<title>LXF74-75:Slackware 10.2</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF74-75:Slackware_10.2"/>
				<updated>2008-05-16T18:09:44Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: Новая: ''За годы эволюции этот дистрибутив стал совершенным или превратился в живое ископаемое? &amp;lt;br /&amp;gt;Том Вилки...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;''За годы эволюции этот дистрибутив стал совершенным или превратился в живое ископаемое? &amp;lt;br /&amp;gt;Том Вилкинсон (Tom Wilkinson) пытается разузнать правду.''&lt;br /&gt;
&lt;br /&gt;
{{Врезка|left|Ширина=225px|&lt;br /&gt;
Заголовок = Самое главное |&lt;br /&gt;
Содержание =Дистрибутив предназначен специально для опытных пользователей. &amp;lt;br /&amp;gt;&lt;br /&gt;
См. также: Debian и Gentoo &lt;br /&gt;
* '''РАЗРАБОТЧИК:''' Патрик Фолькердинг (Patrick Volkerding)&lt;br /&gt;
* '''WEB:''' [http://www.slackware.com  www.slackware.com]&lt;br /&gt;
* '''ЦЕНА:''' Выпускается под лицензией GPL}}&lt;br /&gt;
&lt;br /&gt;
Выпуск Slackware 1.0 состоялся 16 июля 1993 года, так что его можно по праву считать самым старым из ныне существующих дистрибутивов Linux. У него есть верные последователи, поскольку он больше всех похож на Unix, и поскольку он не пытается скрыть сложности настройки под огромным множеством графических инструментов (которые зачастую только добавляют своих собственных проблем).&lt;br /&gt;
&lt;br /&gt;
Доказательством способностей Патрика Волькердинга служит то, что будучи ведущим разработчиком и практически единственным участником работы над Slackware, он при этом продолжает привлекать внимание и новых пользователей, хотя над другими дистрибутивами работают большие команды.&lt;br /&gt;
&lt;br /&gt;
=== Назад во времени. ===&lt;br /&gt;
[[Изображение:LXF74-75 Slackware 10.2.png|thumb|KDE вытеснил Gnome, хотя пакеты с Gnome 2.12 существуют для Slackware, Slamd64 и Slackintosh.]]&lt;br /&gt;
Установка Slackware может оказаться похожа на путешествие в прошлое на десять лет. Отсутствие какого бы то ни было графического инсталлятора выглядит ужасно примитивно по сравненю с Fedora или SUSE. Но ведь внешний вид — это еще не всё. Инсталлятор делает все, что полагается, а отсутствие «бантиков» и «рюшечек» позволяет ему великолепно справляться со своей задачей вне зависимости от спецификации и возраста обородования, на котором он работает.&lt;br /&gt;
&lt;br /&gt;
В процедуре инсталляции осталась одна рудиментарная особенность, от которой хотелось бы избавиться — это устаревший метод создания разделов на жестком диске. Пользователю предлагается на выбор Cfdisk и Fdisk, оба они работают только в текстовом режиме и не имеют никаких средств для изменения размеров существующих разделов. Возможно, у вас это не вызовет никаких проблем, но многим пользователям придется обратиться к приложениям третьих фирм, чтобы подготовить жесткий диск. Может показаться, что Slackware стреляет себе в ногу, создавая пользователям трудности на самом раннем этапе, но это укладывается в стратегию Slackware продемонстрировать пользователю всё, что происходит внутри. Даже если вы когда-нибудь выберете другой дистрибутив, вы теперь будете представлять, какую сложную работу выполняет для вас большинство инсталляторов.&lt;br /&gt;
&lt;br /&gt;
После того, как вы создали соответствующие разделы, инсталлятор поведёт вас к их форматированию и выбору пакетов. Пакеты в Slackware поставляются в сериях, называемых дисковыми наборами (disk set). Название, как вы можете догадаться, образовалось во те времена, когда CD-ROMы еще не были широко распространены, и программы поставлялись на дискетах. Сейчас уже невозможно установить Slackware с такого архаичного носителя, но название сохранилось.&lt;br /&gt;
&lt;br /&gt;
Каждый дисковый набор содержит разные пакеты с разной функциональностью. Набор base содержит самый минимум, и это единственный набор, который совершенно необходимо установить — такой вариант полезен при создании крошечной инсталляции на узкоспециализированном компьютере.&lt;br /&gt;
&lt;br /&gt;
Система управления пакетами Slackware гораздо проще, чем аналоги у Debian и RedHat. По существу, каждый пакет — это просто Gzip-архив с файлами, которые нужно скопировать в систему. Хотя эта схема может породить сложности при работе с пакетами из разных источников, большинство пользователей не испытывает с нею никаких проблем.&lt;br /&gt;
&lt;br /&gt;
Вдобавок к стандартным утилитам существуют дополнительные пакеты, в том числе, Slackpkg на дополнительном диске, который делает управление пакетами гораздо проще. Системе пакетов Slackware не хватает изящества APT или Yum, но она потрясающе надёжна и отлично делает свою работу.&lt;br /&gt;
&lt;br /&gt;
Кому-то может показаться анахронизмом предложение инсталлятора настроить модем. Многие сейчас пользуются широкополосным доступом в интернет, но ведь и в наше время модем может пригодиться.&lt;br /&gt;
&lt;br /&gt;
В самом конце устанавливается менеджер загрузки Lilo. В отличие от других версий Slackware сейчас нет сложностей с использованием загрузочного ReiserFS-раздела. Я был очень рад увидеть, что эта маленькая, но неприятная проблема решена.&lt;br /&gt;
&lt;br /&gt;
=== Gnome не явился ===&lt;br /&gt;
После установки и перезагрузки Slackware показывает вам стандартное текстовое приглашение для входа в систему. Настройка всего оборудования полностью зависит от вас; впрочем в дистрибутив включено несколько текстовых утилит, которые могут в этом помочь. Сложнее всего для нас было запустить графическую оболочку, хотя для большинства пользователей будет достаточно выполнить сценарий конфигурации X.org.&lt;br /&gt;
&lt;br /&gt;
Одним из основных изменений по сравнению с предыдущей версией Slackware является исключение Gnome из дистрибутива — теперь из «высококалорийных» оболочек остался только KDE. Это можно понять. Поддержка полной инсталляции Gnome в Slackware — огромная работа, и кажется вполне логичным поручить её третьим лицам.&lt;br /&gt;
&lt;br /&gt;
Конечно, ничего не помешает вам самостоятельно поставить любую версию Gnome, и это будет вполне в духе Slackware. Дистрибутив поощряет эксперименты и изучение всего, что находится под поверхностью. Если вы хотите узнать свой Linux вдоль и поперек — поставьте Slackware.&lt;br /&gt;
&lt;br /&gt;
=== Вердикт Linux Format ===&lt;br /&gt;
* Функциональность — 7/10&lt;br /&gt;
* Производительность — 9/10&lt;br /&gt;
* Простота использования — 4/10&lt;br /&gt;
* Документация — 8/10&lt;br /&gt;
&lt;br /&gt;
Если вы хотите узнать, как всё было раньше, или стремитесь быть поближе к ядру Linux, Slackware должен быть одним из первых в вашем списке.&lt;br /&gt;
* '''Рейтинг — 7/10''&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF74-75:Ubuntu_5.10</id>
		<title>LXF74-75:Ubuntu 5.10</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF74-75:Ubuntu_5.10"/>
				<updated>2008-05-16T17:54:07Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: Новая: __NOTOC__''Обновление компилятора сделало дистрибутив еще более беззаботным. Энди Хадсон (Andy Hudson) расскаж...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__''Обновление компилятора сделало дистрибутив еще более беззаботным. Энди Хадсон (Andy Hudson) расскажет и о других новинках.''&lt;br /&gt;
&lt;br /&gt;
{{Врезка|left|Ширина=220px|&lt;br /&gt;
Заголовок = Самое главное |&lt;br /&gt;
Содержание = Настольный дистрибутив на базе Debian. &lt;br /&gt;
Альтернативы: Mandriva, openSUSE.&lt;br /&gt;
* '''РАЗРАБОТЧИК''' The Ubuntu Foundation &lt;br /&gt;
* '''WEB''' [http://www.ubuntu.com  www.ubuntu.com]&lt;br /&gt;
* '''ЦЕНА''' Бесплатно, по лицензии GPL}}&lt;br /&gt;
&lt;br /&gt;
[[Изображение:LXF74-75 Ubuntu 5.10-1.png|thumb|Музыка, карты… И верная ищейка Beagle усердно трудится на благо хозяина. С такими удобствами, зачем нам Mac OS X?]]&lt;br /&gt;
Ubuntu — это действительно загадка в мире Linux. Релиз октября 2004 года на удивление стремительно взлетел на вершину рейтинга DistroWatch. Все это благодаря тому, что команда Марка Шаттлворта взяла за основу Debian — дистрибутив, который вряд ли можно назвать дружественным — и придала ему человеческое обличие. Версия 5.10 (кодовое название Breezy Badger) — последний релиз, и, судя по предыдущим версиям, он обещает быть очень популярным.&lt;br /&gt;
&lt;br /&gt;
Фонд Ubuntu Foundation много работал над процессом инсталляции Ubuntu. Благодаря новому инсталлятору процесс установки очень упростился, и теперь, например, из строки состояния можно точно знать, на каком этапе вы находитесь и с чем конкретно сейчас работаете. Добавился и графический экран загрузки, где под надписью Ubuntu выводятся сообщения о текущем статусе. Это достаточно просто, но все же лучше, чем ничего.&lt;br /&gt;
&lt;br /&gt;
=== Linux стал проще ===&lt;br /&gt;
[[Изображение:LXF74-75 Ubuntu 5.10-2.png|thumb|Немного назойливое pop-up окно обновлений — шаг навстречу тем, кто во главу угла ставит безопасность.]]&lt;br /&gt;
[[Изображение:LXF74-75 Ubuntu 5.10-3.png|thumb|Утилита ''Add/Remove Application'' облегчает работу с Synaptic.]]&lt;br /&gt;
[[Изображение:LXF74-75 Ubuntu 5.10-4.png|thumb|Serpentine позволяет легко создавать аудио-CD из любых OGG или MP3-файлов.]]&lt;br /&gt;
На первый взгляд, особых изменений по сравнению с Hoary Hedgehog (5.04) нет. Gnome 2.12 заменил версию 2.10, но на самом деле изменения (и не малые) есть — просто они не сразу бросаются в глаза, достаточно вызвать меню щелком правой кнопки мыши и вы сразу все поймете. Если вы уже знакомы с Ubuntu, то, несомненно, знаете, что он сам выбирает для вас многие приложения. Мы склонны считать это плюсом для Ubuntu, поскольку пользователь не теряется в бесконечных меню. В программы, поставляющихся по умолчанию, входят OpenOffice.org 2.0 (1.9.125), Evolution 2.4, клиент BitTorrent для Gnome, GnomeMeeting, Rhythmbox, Totem, Sound Juicer и Serpentine. В последних релизах можно создавать аудио-CD из файлов различных форматов, включая OGG и MP3.&lt;br /&gt;
&lt;br /&gt;
=== Новые инструкции ===&lt;br /&gt;
Есть также и скрытые изменения. В Ubuntu теперь включен GCC 4.0, что принесет соответствующие выгоды, однако ядро по прежнему откомпилировано при помощи GCC 3.4. Breezy использует ядро 2.6.12, но, естественно, вам никто не запрещает установить свое ядро с нужными параметрами оптимизации. Не стоит забывать, что в Ubuntu не входит ни одно из средств разработки, и для их установки необходимо будет использовать Synaptic. Не удивительно, что отсутствует и Mono, но Ubuntu-оптимизированные пакеты доступны все в том же Synaptic. В дистрибутив теперь включен PHP 5, а любителей Bluetooth порадует поддержка клавиатур и мышей прямо из коробки.&lt;br /&gt;
&lt;br /&gt;
=== Врага нужно знать в лицо ===&lt;br /&gt;
С выпуском Breezy, Марк Шаттлворт назвал кодовое имя следующей версии Ubuntu — 6.04. Она будет называться Dapper Duck («Проворная утка»). «Проворная», потому что она будет уводить пользователей у Windows Vista, а «утка», потому что… она начинается с буквы «D» (в английском языке, разумеется). Шаттлворт уже кинул боевой клич и намерен переманить пользователей стремительно стареющей Windows XP в стан сторонников версии 6.04.&lt;br /&gt;
&lt;br /&gt;
Все это хорошо, но стремление Ubuntu к тому, чтобы все «просто работало» наводит нас на мысль, что оно находится куда ближе к Apple, чем к Microsoft. Философия Apple заключается в предоставлении программ, с которыми люди хотят работать, а не переделывать их, и можно смело сказать, что Ubuntu к этому и стремится.&lt;br /&gt;
&lt;br /&gt;
Кстати, обратите внимание на дистрибутив Edubuntu, который поддерживает Linux Terminal Server Project и нацелен на школы. LTSP поддерживается в Ubuntu как стандарт, и будет весьма интересно узнать, где это будет применяться. Большинство школ и вузов Microsoft-ориентированы, хотя некоторые действительно используют Linux как файл- или принт-сервер.&lt;br /&gt;
&lt;br /&gt;
В целом релиз получился довольно удачным. С каждой версией Ubuntu становится все лучше и лучше и мы с нетерпением будем ждать выхода релиза 6.04.&lt;br /&gt;
&lt;br /&gt;
=== Вердикт Linux Format ===&lt;br /&gt;
{{врезка|Ширина=200px|Заголовок = Грэм считает…&lt;br /&gt;
|Содержание = «Команда Ubuntu проделала большую работу, чтобы настроить ACPI для многих марок ноутбуков. Это один из лучших вариантов мобильного Linux»}}&lt;br /&gt;
&lt;br /&gt;
* Возможности — 9/10&lt;br /&gt;
* Функционирование — 9/10&lt;br /&gt;
* Простота использования — 10/10&lt;br /&gt;
* Документация — 8/10&lt;br /&gt;
&lt;br /&gt;
Простой, понятный дистрибутив, который стоит попробовать всем. Даже набор приложений по умолчанию весьма разумен.&lt;br /&gt;
* '''Рейтинг — 9/10'''&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF87/88</id>
		<title>LXF87/88</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF87/88"/>
				<updated>2008-05-15T15:28:24Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: Перенаправление на LXF87-88&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[LXF87-88]]&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF87-88</id>
		<title>LXF87-88</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF87-88"/>
				<updated>2008-05-15T15:27:59Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: слэш означает вложенность&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Linux Format 1 (87-88), Январь 2007 ==&lt;br /&gt;
&lt;br /&gt;
=== Обзоры ===&lt;br /&gt;
* [[LXF87-88:Fedora Core 6 vs Ubuntu 6.10|Fedora Core 6 vs Ubuntu 6.10]]&lt;br /&gt;
Ubuntu одержит верх — ведь так? Интегрированные Xen и Xgl убеждают, что нет.&lt;br /&gt;
* [[LXF87-88:FreeBSD 6.2|FreeBSD 6.2]]&lt;br /&gt;
Грядущие трудности не пугают бравых ребят из FreeBSD. С включением FreeBSD Update, аудита безопасности и пр. — чего им опасаться?&lt;br /&gt;
* [[LXF87-88:Mandriva Powerpack_2007|Mandriva Powerpack 2007]]&lt;br /&gt;
Что значит включение Cedega и Xgl?&lt;br /&gt;
* [[LXF87-88:Oxygen|Oxygen]]&lt;br /&gt;
Стоит ли платить за XML-редактор, если все можно сделать в Emacs и Kate?&lt;br /&gt;
* [[LXF87-88:Valgrind|Valgrind]]&lt;br /&gt;
Новая версия искрометного отладчика со встроенной виртуальной машиной&lt;br /&gt;
&lt;br /&gt;
=== Сравнение ===&lt;br /&gt;
* [[LXF87-88:Сравнение|Сравнение: web-браузеры]]&lt;br /&gt;
&lt;br /&gt;
=== Что за штука… ===&lt;br /&gt;
* [[LXF87-88:Микроформаты|Микроформаты?]]&lt;br /&gt;
Новый смысл старых сайтов&lt;br /&gt;
&lt;br /&gt;
=== Спецрепотраж ===&lt;br /&gt;
* [[LXF87-88:KDE 4|KDE 4: вкус будущего]]&lt;br /&gt;
Linux Format расследует, куда движется популярная рабочая среда&lt;br /&gt;
&lt;br /&gt;
=== Интервью LXF ===&lt;br /&gt;
* [[LXF87-88:Интервью|Интервью]]&lt;br /&gt;
Джефф Во сделал то, о чем мечтают многие: ушел с престижной работы, чтобы посвящать Linux все свое время. Почему — он расскажет сам.&lt;br /&gt;
&lt;br /&gt;
=== Учебники ===&lt;br /&gt;
* [[LXF87-88:QuiteInsane|QuiteInsane: Учимся сканировать]]&lt;br /&gt;
Сдуйте пыль со сканера и отправьте бумажные документы на чердак.&lt;br /&gt;
* [[LXF87-88:Mono|Mono: И снова Hello World]]&lt;br /&gt;
Хотите научиться программировать? Начните сегодня — на самой современной платформе.&lt;br /&gt;
* [[LXF87-88:Безопасность|Безопасность: Собираем брандмауэр]]&lt;br /&gt;
Установите свои правила с netfilter и iptables — или оставьте черную работу графическим инструментам.&lt;br /&gt;
* [[LXF87-88:DocBook|DocBook: Качественная документация]]&lt;br /&gt;
Хорошая порция XML — и мы покажем, что настоящие мужчины умеют писать не только код.&lt;br /&gt;
* [[LXF87-88:GTK+|GTK+: Интернационализация]]&lt;br /&gt;
Учим наши приложения разговаривать по-русски.&lt;br /&gt;
* [[LXF87-88:Unix API|Unix API: Синхронизация потоков]]&lt;br /&gt;
Как сделать так, чтобы все эти thread_func() не мешали друг другу?&lt;br /&gt;
* [[LXF87-88:Java|Java: Снова о потоках]]&lt;br /&gt;
Не удивляйтесь — программисты Java тоже хо тят выполнять много задач одновременно.&lt;br /&gt;
* [[LXF87-88:PostgreSQL|PostgreSQL: Возможности]]&lt;br /&gt;
Вот и пришла пора узнать, за что PostgreSQL называют самой мощной открытой СУБД.&lt;br /&gt;
* [[LXF87-88:LaTeX|LaTeX: Код и алгоритмы]]&lt;br /&gt;
TeX — это не только математика. Это код, алгоритмы, ЖК-индикаторы — все, что вы только пожелаете.&lt;br /&gt;
* [[LXF87-88:Blender|Blender: Знакомство с интерфейсом]]&lt;br /&gt;
Пускай на первый взгляд он выглядит сложнее синхрофазотрона — разобраться в Blender не так уж и тяжело.&lt;br /&gt;
* [[LXF87-88:VideoLAN|VideoLAN: 10 минут на запуск трансляции]]&lt;br /&gt;
Организовать свое вещание в Сети может каждый!&lt;br /&gt;
&lt;br /&gt;
=== А также… ===&lt;br /&gt;
* [[LXF87-88:Мастер на все руки|Мастер на все руки: сегодня — Tcl]]&lt;br /&gt;
Новая серия: изучаем экзотические языки программирования&lt;br /&gt;
&lt;br /&gt;
* [[LXF87-88:Музыкальный Linux|Музыкальный Linux: трекеры]]&lt;br /&gt;
Новая серия: создаем музыкальные произведения на свободных инструментах&lt;br /&gt;
&lt;br /&gt;
* [[LXF87-88:Wikipedia|Wikipedia]]&lt;br /&gt;
Стать энциклопедистом теперь может любой желающий&lt;br /&gt;
&lt;br /&gt;
* [[LXF87-88:Ответы|Ответы]]&lt;br /&gt;
Решаем проблемы с оборудованием, командами оболочки, разделами и т. д.&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF87/88:Java</id>
		<title>LXF87/88:Java</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF87/88:Java"/>
				<updated>2008-05-15T15:26:55Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: «LXF87/88:Java» переименована в «LXF87-88:Java»: слэш означает вложенность&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[LXF87-88:Java]]&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF87-88:Java</id>
		<title>LXF87-88:Java</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF87-88:Java"/>
				<updated>2008-05-15T15:26:55Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: «LXF87/88:Java» переименована в «LXF87-88:Java»: слэш означает вложенность&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/Java}}&lt;br /&gt;
&lt;br /&gt;
=== Потоки в Java ===&lt;br /&gt;
''ЧАСТЬ 4: Завершая курс молодого Java-бойца, '''Антон Черноусов''' научит вас управлять потоками… Жаль, что не денежными.''&lt;br /&gt;
&lt;br /&gt;
C каждым днем появляются все более мощные процессоры, многоядерная архитектура которых стала основной темой ушедшего года, поэтому двухядерный процессор в ноутбуке уже никого не удивляет. С одной стороны — это обстоятельство приближает возможности простого пользователя к возможностям «понастоящему» больших систем. С другой (и рекламные буклеты об этом обычно молчат) — для того, чтобы использовать весь потенциал современных компьютеров, приложение должно «уметь» просчитать задачу фактически на двух или более процессорах.&lt;br /&gt;
&lt;br /&gt;
Создание эффективных алгоритмов для работы на многопроцессорных станциях — это большая и сложная работа. Несмотря на это, для любого программиста актуальна задача организации взаимодействия с медленными ресурсами (например, чтения, записи или копирования файлов, работы с принтером, сетью), так как немногие пользователи смирятся с тем, что их любимая программа «замирает» в момент выполнения какой-либо операции.&lt;br /&gt;
&lt;br /&gt;
Во избежание описанных проблем программа должна использовать потоки или процессы. Под процессом понимается заявка на потребле-&lt;br /&gt;
ние всех видов ресурсов системы, кроме одного — процессорного времени, или иначе говоря, процесс — это запущенная на выполнение программа (такое определение дается в [[LXF87/88:Java#Литература|[1]]]). Поток рассматривается как самостоятельная активность внутри процесса, хотя существуют другие трактовки этого понятия, которые зависят от используемой операционной системы (см., например, [[LXF87/88:Java#Литература|[2]]]). Поток получил свое название по аналогии с потоком команд, поступающих в процессор; при выполнении потоки делят адресное пространство и выделенную память внутри одного процесса. Процессорное время распределяется между различными потоками операционной системой, точнее, одним из компонентов ее ядра — планировщиком. Более полно с понятием процессов и потоков и механизмов работы с ними с точки зрения операционной системы вы можете ознакомиться в книге [[LXF87/88:Java#Литература|[3]]].&lt;br /&gt;
&lt;br /&gt;
Давайте завершим наш экскурс в теорию и окунемся в реальность Java. Под процессом здесь принято понимать всеобъемлющий контекст выполнения, обеспечивающий высокий уровень изоляции охватываемых им данных от внешнего мира, а под потоком — более «легковесный» активный агент; в контексте одного процесса может функционировать целое множество потоков [[LXF87/88:Java#Литература|[4]]]. Планирование потоков в Java обеспечивается внутренними механизмами JVM.&lt;br /&gt;
&lt;br /&gt;
=== Поток, он же thread ===&lt;br /&gt;
В Java существует два способа работы с потоками: первый заключается в реализации интерфейса Runnable, второй связан с наследованием&lt;br /&gt;
класса Thread, который уже реализует данный интерфейс. В обоих случаях класс должен предоставлять реализацию метода run(). Ниже&lt;br /&gt;
приведен пример класса, реализующего поток через наследование класса Thread:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class FirstThread extends Thread {&lt;br /&gt;
  public void run(){&lt;br /&gt;
    for (int i = 1 ; i &amp;lt; 30; i++)&lt;br /&gt;
      System.out.println(&amp;quot;It is in thread &amp;quot;+ i);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Собственно, метод run() и должен содержать некоторый набор инструкций (разумеется, на языке Java), которые вы хотите выполнить&lt;br /&gt;
в отдельном потоке. Например, если вы реализуете функцию копирования файла (а пользователь, скажем, копирует ISO-образ объемом&lt;br /&gt;
600 Мб), желательно, чтобы эта операция выполнялась в отдельном потоке, запуск которого можно производить следующим образом:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class ConsoleToThread {&lt;br /&gt;
  public static void main(String[] args) {&lt;br /&gt;
    FirstThread thread = new FirstThread();&lt;br /&gt;
    thread.start();&lt;br /&gt;
    for (int i = 1; i &amp;lt; 20; i++) {&lt;br /&gt;
      System.out.println(&amp;quot;It is in main &amp;quot; + i);&lt;br /&gt;
    }&lt;br /&gt;
    try {&lt;br /&gt;
      thread.join();&lt;br /&gt;
    } &lt;br /&gt;
    catch (InterruptedException ex) {&lt;br /&gt;
      System.out.println(&amp;quot;Exception in stop thread&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
При выполнении метода main() класса ConsoleToThread создается объект-поток FirstThread, который запускается на выполнение методом start() [заметьте — метод run() никогда не вызывается явно, — прим.ред.]. Метод join() используется в случае, когда необходимо «дождаться» завершения потока. Завершение работы потока происходит при выходе из метода run(), как явном (например, посредством return), так и неявном (если внутри метода возникло и не было обработано какое-то исключение).&lt;br /&gt;
&lt;br /&gt;
Имейте в виду (это важно!): повторный запуск уже отработавшего потока приведет к исключению IllegalThreadStateException.&lt;br /&gt;
&lt;br /&gt;
=== Реализация потока через Runnable ===&lt;br /&gt;
Давайте теперь рассмотрим пример работы с потоками через интерфейс Runnable. Если, допустим, класс SameRunnable реализует интерфейс Runnable, то запустить поток на основе этого класса на выполнение можно следующим образом:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
Runnable run = new SameRunnable();&lt;br /&gt;
Thread thread = new Thread(run);&lt;br /&gt;
thread.start();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
В следующем примере в методе main() класса ConsoleToThreadTwo создается массив threadArray, состоящий из объектов-потоков. При&lt;br /&gt;
этом используется конструктор класса Thread, принимающий два параметра: ссылку на объект, реализующий интерфейс Runnable и&lt;br /&gt;
имя потока:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
Thread thread = new Thread(Runnable, ThreadName);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Метод getName() объекта, реализующего поток, возвращает указанное при создании имя. Обратите внимание, что в нем используется&lt;br /&gt;
статический метод Thread.currentThread(), возвращающий ссылку на объект Thread, соответствующий выполняющемуся в текущий момент&lt;br /&gt;
потоку:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class SecondThread implements Runnable {&lt;br /&gt;
  public String getName() {&lt;br /&gt;
    return Thread.currentThread().getName();&lt;br /&gt;
  }&lt;br /&gt;
  public void run() {&lt;br /&gt;
    for (int i = 1; i &amp;lt; 100000; i++) {&lt;br /&gt;
      if ((i % 10000) == 0) {&lt;br /&gt;
        System.out.println(getName() + &amp;quot; counts &amp;quot; + i / 10000);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public class ConsoleToThreadTwo {&lt;br /&gt;
  public static void main(String[] args) {&lt;br /&gt;
    Thread[] threadArray = new Thread[3];&lt;br /&gt;
      for (int i=0; i&amp;lt;threadArray.length; i++){&lt;br /&gt;
        threadArray[i] = new Thread(new SecondThread(), &amp;quot;Thread &amp;quot; + i);&lt;br /&gt;
      }&lt;br /&gt;
      for (int i=0; i&amp;lt;threadArray.length; i++){&lt;br /&gt;
        threadArray[i].start();&lt;br /&gt;
        System.out.println(threadArray[i].getName() + &amp;quot; started&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Проследив за выводом этой программы, можно заметить, что процессорное время распределяется между потоками практически равномерно, однако порядок их выполнения во многом случаен.&lt;br /&gt;
&lt;br /&gt;
=== Приоритеты потоков ===&lt;br /&gt;
Для управления величиной процессорного времени, выделяемого потоку, можно воспользоваться приоритетами. Установка приоритетов происходит с помощью метода Thread.setPriority(), узнать текущий приоритет позволяет метод getPriority(). В классе Thread определены&lt;br /&gt;
три константы:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
MIN_PRIORITY = 1&lt;br /&gt;
NORM_PRIORITY = 5&lt;br /&gt;
MAX_PRIORITY = 10&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Важно понимать, что значение приоритета потока предназначено для Java-машины и не соответствует реальным приоритетам потоков&lt;br /&gt;
в операционной системе.&lt;br /&gt;
&lt;br /&gt;
Давайте немного изменим код метода main() класса ConsoleToThreadTwo:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public static void main(String[] args) {&lt;br /&gt;
  Thread[] threadArray = new Thread[3];&lt;br /&gt;
  int pr = 0;&lt;br /&gt;
  for (int i=0; i&amp;lt;threadArray.length; i++){&lt;br /&gt;
    threadArray[i] = new Thread(new SecondThread(), &amp;quot;Thread &amp;quot; + i);&lt;br /&gt;
    if (pr == 10) &lt;br /&gt;
      pr = 0; &lt;br /&gt;
    threadArray[i].setPriority(Thread.MIN_PRIORITY + pr);&lt;br /&gt;
    pr++;&lt;br /&gt;
  }&lt;br /&gt;
  for (int i=0; i&amp;lt;threadArray.length; i++){&lt;br /&gt;
    threadArray[i].start();&lt;br /&gt;
    System.out.println(threadArray[i].getName() + &amp;quot; started&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Анализ результатов работы класса показывает, что потоки, получившие более высокий приоритет, выполняются чаще. Также, благодаря&lt;br /&gt;
условию на значение переменной pr, setPriority() никогда не будет передан приоритет, превышающий 10 (MAX_PRIORITY). Если бы это про-&lt;br /&gt;
изошло, система выбросила бы исключение IllegalArgumentException.&lt;br /&gt;
&lt;br /&gt;
=== Потоки-демоны ===&lt;br /&gt;
Сделаем еще одно важное замечание: программа будет выполняться до тех пор, пока выполняется хотя бы один запущенный в ней поток;&lt;br /&gt;
единственным исключением являются потоки-демоны.&lt;br /&gt;
&lt;br /&gt;
Что же это такое? Демон отличается от «простого смертного» потока вызовом метода setDeamon(true), который необходимо сделать до&lt;br /&gt;
начала работы. Например, так:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
FirstThread thread = new FirstThread();&lt;br /&gt;
thread.setDeamon(true);&lt;br /&gt;
thread.start();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Узнать, является ли поток демоном, можно с помощью метода isDeamon(). Обычно потоки-демоны создаются для обслуживания&lt;br /&gt;
некритичных задач, так как при завершении работы программа не дожидается их остановки, а прерывает их самостоятельно.&lt;br /&gt;
&lt;br /&gt;
=== Где искать потоки? ===&lt;br /&gt;
В большинстве случаев бывает необходимо отслеживать ранее запущенные на выполнение потоки. Использование массива потоков,&lt;br /&gt;
как в предыдущем примере, не всегда оправданно. Для хранения и обработки потоков в Java существует класс ThreadGroup. Группа,&lt;br /&gt;
к которой принадлежит создаваемый поток, опять-таки передается конструктору Thread():&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
ThreadGroup tg = new ThreadGroup(&amp;quot;NameThreadGroup&amp;quot;);&lt;br /&gt;
Thread thread = new Thread(tg, new SecondThread(), &amp;quot;ThreadName&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Если группа не указана явно, поток будет помещен в тот же ThreadGroup, что и его родитель.&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
ThreadGroup tg = new ThreadGroup(&amp;quot;NameThreadGroup&amp;quot;);&lt;br /&gt;
Thread thread = new Thread(tg, new SecondThread(), &amp;quot;ThreadName&amp;quot;);&lt;br /&gt;
Thread thread1 = new Thread(tg, new SecondThread(), &amp;quot;ThreadName2&amp;quot;);&lt;br /&gt;
Thread thread2 = new Thread(tg, new SecondThread(), &amp;quot;ThreadName3&amp;quot;);&lt;br /&gt;
System.out.println(&amp;quot;active thread in group &amp;quot; + tg.activeCount());&lt;br /&gt;
thread.start();&lt;br /&gt;
thread1.start();&lt;br /&gt;
System.out.println(&amp;quot;active thread in group &amp;quot; + tg.activeCount());&lt;br /&gt;
Thread[] threads = new Thread[tg.activeCount()];&lt;br /&gt;
int m = tg.enumerate(threads);&lt;br /&gt;
System.out.println(&amp;quot;taked threads from group : &amp;quot; + m);&lt;br /&gt;
for (int i = 0; i &amp;lt; threads.length; i++) {&lt;br /&gt;
  System.out.println(threads[i].getName());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
В представленном выше примере в экземпляр класса ThreadGroup помещаются три потока, два из которых запускаются на выполнение.&lt;br /&gt;
Количество активных потоков в группе определяется с помощью метода activeCount(), а в результате выполнения метода enumerate() формируется перечень всех активных потоков.&lt;br /&gt;
&lt;br /&gt;
=== Управление потоками ===&lt;br /&gt;
При запуске потоков следует учитывать и то, что их иногда приходится останавливать, причем как штатно, так и экстренно. Для того, чтобы&lt;br /&gt;
приостановить работу потока изнутри, допустим, в тот момент, когда закончилась доступные для обработки данные, можно использовать&lt;br /&gt;
два метода: sleep() и wait().&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class ThirdThread extends Thread {&lt;br /&gt;
  public void run() {&lt;br /&gt;
    for (int i = 1; i &amp;lt; 110; i++) {&lt;br /&gt;
      if (i == 10) {&lt;br /&gt;
        try {&lt;br /&gt;
          sleep(10000);&lt;br /&gt;
        } &lt;br /&gt;
        catch (InterruptedException e) {&lt;br /&gt;
          System.out.println(&amp;quot;the thread was awaken there (just a moment ago)&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
      if (i == 100) {&lt;br /&gt;
        try {&lt;br /&gt;
          synchronized (this) { wait();}&lt;br /&gt;
        }&lt;br /&gt;
        catch (InterruptedException e) {&lt;br /&gt;
          System.out.println(&amp;quot;the thread was awaken there (just a moment ago)again&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
      } &lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Методу sleep() передается переменная типа long, соответствующая количеству миллисекунд, в течении которых поток будет «спать». В&lt;br /&gt;
случае wait() поток ждет пробуждения снаружи. Применение методов sleep() и wait() требует обработки исключительной ситуации, которая возникают при пробуждении потока. В представленном ниже классе ConsoleToThreadThree потоки пробуждаются с помощью метода interrupt():&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class ConsoleToThreadThree {&lt;br /&gt;
  public static void main(String[] args) {&lt;br /&gt;
    ThirdThread thread = new ThirdThread();&lt;br /&gt;
    thread.start();&lt;br /&gt;
    for (int i = 1; i &amp;lt; 20; i++) {&lt;br /&gt;
      System.out.println(&amp;quot;It is in main &amp;quot; + i);&lt;br /&gt;
    }&lt;br /&gt;
    thread.interrupt();&lt;br /&gt;
    for (int i = 1; i &amp;lt; 20; i++) {&lt;br /&gt;
      System.out.println(&amp;quot;It is in main &amp;quot; + i);&lt;br /&gt;
    }&lt;br /&gt;
    thread.interrupt();&lt;br /&gt;
    try {&lt;br /&gt;
      thread.join();&lt;br /&gt;
    } &lt;br /&gt;
    catch (InterruptedException ex) {&lt;br /&gt;
      System.out.println(&amp;quot;Exception in stop thread&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Отметим, что вызов метода wait() без блока синхронизации (synchronized), о котором мы поговорим чуть ниже, приводит к исключению IllegalMonitorStateException. Возникшая ошибка свидетельствует об отсутствии монитора у объекта (понятие монитора и синхронизация&lt;br /&gt;
тесно связаны, о чем мы тоже поговорим ниже). Если для приостановления потока был применен метод wait(), то для «пробуждения» потока&lt;br /&gt;
можно воспользоваться методом notify() или notifyAll(). Первый пробуждает один случайно выбранный спящий поток, а второй пытается&lt;br /&gt;
пробудить их всех.&lt;br /&gt;
&lt;br /&gt;
Кроме рассмотренных выше методов, иногда бывает целесообразно использовать метод yield(), который приостанавливает работу текущего потока. Метод yield() не переводит поток в режим ожидания, как wait(), но предоставляет другим потокам возможность начать работать&lt;br /&gt;
раньше, чем допустила бы Java-машина [фактически, поток, вызвавший yield() добровольно отдает свой квант процессорного времени, -&lt;br /&gt;
прим. ред.]. Метод yield() статичный, так что прекратить с его помощью работу другого потока не получится.&lt;br /&gt;
&lt;br /&gt;
Методов остановки потоков тоже нет (ранее присутствовали методы stop(), resume(), suspend(), но сейчас они объявлены как «deprecated» -&lt;br /&gt;
то есть нерекомендованными к использованию). На сегодня в Java принят уведомительный стиль остановки потока с помощью пары методов:&lt;br /&gt;
уже известного нам interrupt(), применяемого снаружи, чтобы выставить флаг завершения и метода isInterrupted(), вызываемого изнутри&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;
Если перейти к реалиям Java, то объектов типа монитор в явном виде просто нет! С каждым объектом связан неявный монитор, и чтобы&lt;br /&gt;
завладеть им, необходимо вызвать метод или блок, помеченный ключевым словом synchronized. Как только поток входит в такой блок, он&lt;br /&gt;
завладевает монитором объекта, переданного synchronized в качестве параметра. Так происходит и в классе ThirdThread, однако, в момент&lt;br /&gt;
вызова метода wait(), монитор отпускается. Пример synchronized-метода представлен ниже:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public synchronized boolean sameCheck() {&lt;br /&gt;
  if (a) {&lt;br /&gt;
    a = false; return true;&lt;br /&gt;
  } &lt;br /&gt;
  else {&lt;br /&gt;
    a = true; &lt;br /&gt;
    return false;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
В целом, синхронизация — это механизм, обеспечивающий монопольный доступ участка кода к некоторому объекту. Одним из первых&lt;br /&gt;
способов, предложенных для синхронизации работы потоков, были семафоры, концепцию которых описал Дейкстра [Dijkstra] в 1965 году&lt;br /&gt;
(часто говорят, что семафор — это классический синхронизированный примитив). Семафор используется для предоставления доступа к огра-&lt;br /&gt;
ниченному количеству ресурсов. Как правило, у семафора есть две операции: P — занять ресурс и V — освободить ресурс. Он может быть&lt;br /&gt;
реализован следующим образом:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class SimpleSemaphore {&lt;br /&gt;
  int counter;&lt;br /&gt;
  public SimpleSemaphore() {&lt;br /&gt;
    this.counter = 1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public synchronized void p() throws InterruptedException {&lt;br /&gt;
    while (counter == 0) {&lt;br /&gt;
      wait();&lt;br /&gt;
    }&lt;br /&gt;
    counter = counter + 1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public synchronized void v() throws InterruptedException {&lt;br /&gt;
    counter = counter - 1;&lt;br /&gt;
    notify();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Можно, конечно, реализовывать семафоры самостоятельно, но проще воспользоваться специальной библиотекой java.util.concurrent.&lt;br /&gt;
Кроме семафоров, она включает в себя еще много чего интересного.&lt;br /&gt;
&lt;br /&gt;
Отметим, что программа, в принципе, может не использовать ни один из методов синхронизации, обходясь методами wait() и notify().&lt;br /&gt;
&lt;br /&gt;
=== Взаимные блокировки ===&lt;br /&gt;
На этом наш рассказ можно было бы и завершить, но чтобы у вас не сложилось впечатление, что в мире многопоточных приложений все&lt;br /&gt;
так радужно, мы поговорим о неприятных последствиях синхронизации. Как только количество потоков начинает стремительно расти и&lt;br /&gt;
возникает необходимость синхронизированного доступа к ограниченному кругу объектов в различной последовательности, будьте готовы к&lt;br /&gt;
ошибкам типа deadlock — взаимным блокировкам.&lt;br /&gt;
&lt;br /&gt;
Взаимная блокировка — это ошибка, которая лучше всего описывается простой формулой: «Поток A держит монитор a и хочет захватить&lt;br /&gt;
монитор b, а поток B держит монитор b и хочет захватить монитор a». В результате оба засыпают «мертвым сном».&lt;br /&gt;
&lt;br /&gt;
Ошибка очень противная и возникает обычно в нетривиальных алгоритмах. Лечится взаимная блокировка грамотным проектированием и профилактическими мерами, вроде следующей: всегда захватывайте мониторы в одном и том же порядке.&lt;br /&gt;
&lt;br /&gt;
Сегодня мы поговорили о двух способах создания потоков Java, разобрались с приоритетами, познакомились со средствами управления работой потоков и демонами, а также сделали небольшой обзор методов синхронизации. Для того, чтобы начать практическую работу с потоками, этого вполне достаточно. Желающим разобраться во всем этом глубже я рекомендую ознакомится с книгой «Concurrent Programming in Java: Design Principles and Patterns», автором которой является Дуг Ли [Doug Lea] — она считается одной из лучших по данной тематике.&lt;br /&gt;
&lt;br /&gt;
На этом мы заканчиваем обзор основ программирования на Java и в [[LXF89:Java_EE|следующий раз]] поговорим о серверных приложениях — приготовьтесь&lt;br /&gt;
к Java Enterprise Edition!&lt;br /&gt;
&lt;br /&gt;
=== Литература ===&lt;br /&gt;
* 1. П. Кью «Использование UNIX», ISBN 5-8275-0019-4&lt;br /&gt;
* 2. В. Г. Олифер, Н. А. Олифер «Сетевые операционные системы», ISBN 5-272-00120-6&lt;br /&gt;
* 3. Д. Бэкон, Т. Харрис «Операционные системы», ISBN 5-94723-969-8&lt;br /&gt;
* 4. М. Фаулер «Архитектура корпоративных программных приложений», ISBN 5-8459-0579-6&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/%D0%A8%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD:%D0%A6%D0%B8%D0%BA%D0%BB/Java</id>
		<title>Шаблон:Цикл/Java</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/%D0%A8%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD:%D0%A6%D0%B8%D0%BA%D0%BB/Java"/>
				<updated>2008-05-15T15:26:19Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: -&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл|Java|&lt;br /&gt;
* [[LXF84:Java|Сказка Java]]&lt;br /&gt;
* [[LXF85:Java|Считалочки]]&lt;br /&gt;
* [[LXF86:Java|Хранение данных ]]&lt;br /&gt;
* [[LXF87-88:Java|Потоки в Java ]]&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF87/88</id>
		<title>LXF87/88</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF87/88"/>
				<updated>2008-05-15T15:25:44Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: {{delete}}&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{delete}}&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF73:Gambas</id>
		<title>LXF73:Gambas</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF73:Gambas"/>
				<updated>2008-05-15T15:21:47Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: унесите кавычки!&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Построение приложения ==&lt;br /&gt;
''часть 3 Эдисон ошибался. Забудьте об упорном труде: с точки зрения '''доктора Марка Александра Бэйна''' (Dr Mark alexander Bain), гений на 100 % состоит из перекладывания работы на других. Так что садитесь, складывайте ноги на стол и позвольте Gambas сделать за вас всю работу…''&lt;br /&gt;
&lt;br /&gt;
Я, вероятно, уже упоминал об этом, но повторюсь: все хорошие программисты — ленивы. Это не значит, что они ничего&lt;br /&gt;
не делают, нет, но они используют свой мозг, а не пальцы.&lt;br /&gt;
Мы начали постигать это в прошлом месяце, когда рассматривали&lt;br /&gt;
модули и классы. Сегодня мы продолжим превращение в идеального&lt;br /&gt;
ленивого программиста, рассмотрев, как можно заставить Gambas сделать нечто, что будет хорошо выглядеть, с минимальными затратами.&lt;br /&gt;
&lt;br /&gt;
Первое, что надо запомнить: обычно кто-то уже делал то, что вы&lt;br /&gt;
пытаетесь сделать сейчас. Особенно это верно, если вы имеете дело с&lt;br /&gt;
Linux. Предположим, например, что вы ищите владельца web-сайта. Это&lt;br /&gt;
очень просто — откройте командную строку и наберите whois&lt;br /&gt;
linuxformat.ru. Вы увидите большой список, содержащий море информации вроде названия домена, имени того кто его регистрировал, его&lt;br /&gt;
физический адрес, дату регистрации и IP-адрес серверов Linux Format.&lt;br /&gt;
&lt;br /&gt;
=== как сделать то же самое при помощи gambas? ===&lt;br /&gt;
если вы начали отвечать, что нужно поискать в доменных базах данных&lt;br /&gt;
или начать поиск NIC-записи — остановитесь! Вероятно, вы не слушали&lt;br /&gt;
того, что я вам говорил. если же вы ответили «надо схитрить» — купите&lt;br /&gt;
себе пива, вы уже думаете как хороший программист. Главный вопрос:&lt;br /&gt;
«как именно можно схитрить?».&lt;br /&gt;
&lt;br /&gt;
Ответ: используйте оператор Gambas ShELL, чтобы заставить Linux&lt;br /&gt;
сделать за вас всю тяжелую работу и использовать её результат в своей&lt;br /&gt;
программе. Итак, давайте начнём с создания формы, на которой содержатся поле ввода, многострочное поле ввода и пара кнопок. Не забывайте, что имена объектов имеют значение. Сейчас я назвал поле ввода&lt;br /&gt;
txtUrl, многострочное поле ввода txtResult и одну из кнопок btnWhois.&lt;br /&gt;
код, обрабатывающий нажатие этой кнопки, таков:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
PUBLIC SUB btnWhois_Click()&lt;br /&gt;
DIM filename AS String&lt;br /&gt;
filename = &amp;quot;/tmp/whois.tmp&amp;quot;&lt;br /&gt;
IF (txtUrl.Text) THEN&lt;br /&gt;
SHELL &amp;quot;whois &amp;quot; &amp;amp; txtUrl.Text &amp;amp; &amp;quot;&amp;gt;&amp;quot; &amp;amp; filename WAIT&lt;br /&gt;
txtResult.Text = File.Load(filename)&lt;br /&gt;
ELSE&lt;br /&gt;
txtResult.Text = &amp;quot;&amp;quot;&lt;br /&gt;
END IF&lt;br /&gt;
END&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Он очень простой. Сначала мы определяем имя файла&lt;br /&gt;
(/tmp/whois/tmp), а затем запускаем команду оболочки, которая берёт&lt;br /&gt;
адрес из txtUrl и выполняет для него whois, а затем сохраняет результат в текстовом файле. Так что если вы ввели linuxformat.ru, то в результате будет выполнена следующая команда:&lt;br /&gt;
 whois linuxformat.ru &amp;gt; /tmp/whois.tmp&lt;br /&gt;
Затем содержимое файла /tmp/whois.tmp помещается в многострочное поле ввода при помощи команды File.Load. Оператор IF&lt;br /&gt;
просто гарантирует, что если вы оставите поле ввода пустым, то ошибки&lt;br /&gt;
не произойдёт. Такой стиль кодирования не позволяет использовать&lt;br /&gt;
ошибочные данные, что предотвращает падение программы.&lt;br /&gt;
&lt;br /&gt;
другой способ состоит в обработке возникающих ошибок:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
PUBLIC SUB btnWhois_Click()&lt;br /&gt;
DIM filename AS String&lt;br /&gt;
filename = &amp;quot;/tmp/whois.tmp&amp;quot;&lt;br /&gt;
TRY SHELL &amp;quot;whois &amp;quot; &amp;amp; txtUrl.Text &amp;amp; &amp;quot;&amp;gt;&amp;quot; &amp;amp; filename WAIT&lt;br /&gt;
IF ERROR THEN&lt;br /&gt;
txtResult.Text = &amp;quot;&amp;quot;&lt;br /&gt;
END IF&lt;br /&gt;
txtResult.Text = File.Load(filename)&lt;br /&gt;
END&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Тут команда whois выполняется вне зависимости от того, что вы&lt;br /&gt;
ввели, но результат обрабатывается по-разному в зависимости от того,&lt;br /&gt;
была ошибка или нет. какой из методов лучше использовать — это ваш&lt;br /&gt;
выбор, плюсы и минусы есть у обоих вариантов. Первый влечет необходимость обдумать и предотвратить все возможные ошибки, но зато даёт&lt;br /&gt;
уверенность, что указание некорректных данных просто невозможно.&lt;br /&gt;
Второй гарантирует, что все ошибки будут обработаны, но от программиста требуется позаботиться об удачном сообщении для пользователя.&lt;br /&gt;
Но какой бы вы способ ни выбрали — важно, чтобы он был, и чтобы программа не рушилась.&lt;br /&gt;
&lt;br /&gt;
Вторая кнопка нужна для закрытия формы, каждая форма нуждается в такой. Итак, если вы назвали кнопку btnClose, то код будет&lt;br /&gt;
следующим:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
PUBLIC SUB btnClose_Click()&lt;br /&gt;
ME.Close&lt;br /&gt;
END&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Нужно упомянуть о значении параметра WAIT оператора ShELL.&lt;br /&gt;
если вы использовали WAIT, то программа будет ожидать завершения&lt;br /&gt;
команды перед тем, как продолжить работу. если же WAITE не был&lt;br /&gt;
использован, то команда оболочки будет работать в фоновом режиме,&lt;br /&gt;
одновременно с вашим приложением. Фоновый режим полезен, если&lt;br /&gt;
вы хотите запустить команду оболочки и оставить её в работающем&lt;br /&gt;
состоянии. как всегда, лучше всего рассмотреть это на примере из&lt;br /&gt;
реальной жизни.&lt;br /&gt;
&lt;br /&gt;
{{Врезка&lt;br /&gt;
|Заголовок=Права достуПа дЛя TCPduMP&lt;br /&gt;
|Содержание=&lt;br /&gt;
как правило tcpdump может быть&lt;br /&gt;
запущен только пользователем&lt;br /&gt;
root. если вы хотите запустить его&lt;br /&gt;
от имени другого пользователя,&lt;br /&gt;
вам потребуется изменить файл&lt;br /&gt;
sudo (/etc/sudo), добавив в него&lt;br /&gt;
строку подобную следующей&lt;br /&gt;
 bainm ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
|Ширина=250px}}&lt;br /&gt;
Представьте, что вам надо создать приложение с графическим&lt;br /&gt;
интерфейсом пользователя, которое отслеживает сетевой трафик.&lt;br /&gt;
Практически это значит, что вы хотите читать заголовки всех пакетов&lt;br /&gt;
данных, путешествующих по вашей сети. Я надеюсь, что теперь вы&lt;br /&gt;
точно не спросите «как мне это сделать?». Вместо этого вы зададите&lt;br /&gt;
вопрос «Существует ли приложение Linux, которое уже делает всё,&lt;br /&gt;
что нужно?». В нашем случае ответ: tcpdump.&lt;br /&gt;
&lt;br /&gt;
как правило, вы запускаете tcpdump и наблюдаете вывод в консольном окне. Сделаем то же самое при помощи Gambas. как всегда,&lt;br /&gt;
нам потребуется форма, в этот раз — с многострочным полем ввода&lt;br /&gt;
(txtResult) и двумя кнопками (назовём их btnUpdate и btnClose).&lt;br /&gt;
&lt;br /&gt;
добавим немножко кода&lt;br /&gt;
&amp;lt;source lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
PUBLIC SUB tcpdump_update()&lt;br /&gt;
DIM command AS String&lt;br /&gt;
command = &amp;quot;if [ ! \&amp;quot;$(ps -ef | grep /usr/sbin/tcpdump | grep -v grep)\&amp;quot; ];&lt;br /&gt;
then&amp;quot; &amp;amp;&lt;br /&gt;
&amp;quot; sudo /usr/sbin/tcpdump &amp;gt; /tmp/bainm_tcpdump.tmp;&amp;quot; &amp;amp;&lt;br /&gt;
&amp;quot; fi&amp;quot;&lt;br /&gt;
SHELL command&lt;br /&gt;
txtResult.Text = File.Load(&amp;quot;/tmp/bainm_tcpdump.tmp&amp;quot;)&lt;br /&gt;
END&lt;br /&gt;
PUBLIC SUB btnUpdate_Click()&lt;br /&gt;
tcpdump_update&lt;br /&gt;
END&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
В этом примере команда, которая будет запущена в командной&lt;br /&gt;
строке Linux, хранится в переменной command и выглядит следующим&lt;br /&gt;
образом:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
if [ ! &amp;quot;$(ps -ef | grep /usr/sbin/tcpdump | grep -v grep)&amp;quot; ]&lt;br /&gt;
then&lt;br /&gt;
sudo /usr/sbin/tcpdump &amp;gt; /tmp/bainm_tcpdump.tmp&lt;br /&gt;
fi&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Вы спросите, почему бы мне просто не запустить&lt;br /&gt;
 sudo /usr/sbin/tcpdump &amp;gt; /tmp/bainm_tcpdump.tmp&lt;br /&gt;
Ответ: потому, что команда запускается при каждом нажатии на&lt;br /&gt;
кнопку. Так что в этом случае окажется запущено множество версий&lt;br /&gt;
tcpdump. Мой скрипт выполняет проверку, запущено ли уже это приложение, перед тем как пытаться активировать его снова. Вы также можете спросить, что значит код grep -v grep. его задача проста — он удаляет ID дополнительных процессов, запущенных самим grep.&lt;br /&gt;
&lt;br /&gt;
=== надоело нажимать на кнопку? ===&lt;br /&gt;
{{Врезка&lt;br /&gt;
|Заголовок=настроЙка своЙств обЪекта&lt;br /&gt;
|Содержание=&lt;br /&gt;
Свойства объекта можно изменить двумя способами. Первый – через окно&lt;br /&gt;
свойств объекта в Gambas. Второй – установкой нужных значений прямо из&lt;br /&gt;
программы. Например, следующий код включает таймер и задаёт интервал&lt;br /&gt;
срабатывания равным пяти секундам:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
PUBLIC SUB Form_Open()&lt;br /&gt;
tcpdumpTimer.Enabled = TRUE&lt;br /&gt;
tcpdumpTimer.Delay = 5000&lt;br /&gt;
END&amp;lt;/source&amp;gt;&lt;br /&gt;
|Ширина=250px}}&lt;br /&gt;
Наше приложение работает точно так, как заказывали — запускает&lt;br /&gt;
tcpdump и показывает его вывод, но вот только пользователь должен&lt;br /&gt;
всё время нажимать на кнопку, чтобы видеть результат. Мы можем&lt;br /&gt;
автоматизировать этот процесс, добавив в программу таймер. Выберите&lt;br /&gt;
таймер (его иконка похожа на часы) из панели инструментов и нарисуйте на своей форме. Не важно, где именно, поскольку таймер всё равно&lt;br /&gt;
не отображается, когда программа запущена. Не забывайте сменить&lt;br /&gt;
имя таймера на нечто полезное (я назвал его tcpdumpTimer). если&lt;br /&gt;
дважды щелкните на этом объекте, Gambas откроет окно кода, и вы&lt;br /&gt;
увидите:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
PUBLIC SUB tcpdumpTimer_Timer()&lt;br /&gt;
END&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Отредактируйте его следующим образом:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
PUBLIC SUB tcpdumpTimer_Timer()&lt;br /&gt;
tcpdump_update&lt;br /&gt;
END&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Если вы сейчас запустите программу, ничего не изменится, так как&lt;br /&gt;
таймер по умолчанию отключен. Д ля того, чтобы его включить, перейдите к окну свойств и измените значение свойства Enable c False на&lt;br /&gt;
True. Обратите внимание на параметр Delay. Это время в миллисекундах между запусками процедуры таймера. Задайте его равным 5000&lt;br /&gt;
(пять секунд), это позволит вам постоянно видеть изменения, но не&lt;br /&gt;
перегружать процессор. Вы даже можете удалить кнопку btnUpdate,&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;br /&gt;
хотите начать работу приложения,&lt;br /&gt;
и выберите пункт меню «Startup&lt;br /&gt;
Class». Или же вы можете создать&lt;br /&gt;
модуль, указать его в качестве&lt;br /&gt;
запускаемого класса и добавить&lt;br /&gt;
примерно такой код:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
PUBLIC SUB Main()&lt;br /&gt;
frmWebBrowser.Show&lt;br /&gt;
END&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Конечно, вам нужно будет заменить&lt;br /&gt;
имя формы на то, которое&lt;br /&gt;
используется в вашем проекте.&lt;br /&gt;
|Ширина=250px}}&lt;br /&gt;
Если вы закроете приложение Gambas и наберёте в консоли следующую команду,&lt;br /&gt;
 ps -ef|grep tcpdump&lt;br /&gt;
то вероятно увидите в результате нечто вроде этого:&lt;br /&gt;
 root 1443 1437 0 15:37 ? 00:00:00 /usr/sbin/tcpdump&lt;br /&gt;
Это произошло потому, что наше приложение запустило tcpdump и&lt;br /&gt;
оставило его работать в фоновом режиме. Б ыло бы правильнее выключать его после того, как мы закончили.&lt;br /&gt;
&lt;br /&gt;
Это можно сделать в процедуре Form_Close:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
PUBLIC SUB Form_Close()&lt;br /&gt;
DIM command AS String&lt;br /&gt;
DIM filename AS String&lt;br /&gt;
DIM tmp_process_id AS String&lt;br /&gt;
filename = &amp;quot;/tmp/bainm_tcpdump_process.tmp&amp;quot;&lt;br /&gt;
command =&lt;br /&gt;
&amp;quot;ps -ef | grep /usr/sbin/tcpdump|grep -v grep&amp;quot; &amp;amp;&lt;br /&gt;
&amp;quot;| awk '{print $2}' &amp;gt; &amp;quot; &amp;amp; filename&lt;br /&gt;
SHELL command WAIT&lt;br /&gt;
tmp_process_id = file.Load(filename)&lt;br /&gt;
SHELL &amp;quot;sudo kill -9 &amp;quot; &amp;amp; tmp_process_id WAIT&lt;br /&gt;
END&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
В этой подпрограмме выполняются два SHELL-оператора. Первый&lt;br /&gt;
определяет ID процесса tcpdump. Второй убивает процесс. К расота этой&lt;br /&gt;
технологии в том, что вы можете использовать любые команды Linux.&lt;br /&gt;
Например, вы можете создать графическую оболочку для программы&lt;br /&gt;
top, используя таймер и запуская top -n1 &amp;gt; /tmp/top.tmp для выполнения одной итерации, читая затем результаты при помощи file.load.&lt;br /&gt;
&lt;br /&gt;
Рассмотрев некоторые вещи, которые Linux может сделать для нас,&lt;br /&gt;
вернёмся к встроенным возможностям Gambas.&lt;br /&gt;
&lt;br /&gt;
=== Меню Gambas ===&lt;br /&gt;
До сих пор мы использовали кнопки для того, чтобы выполнить любые&lt;br /&gt;
действия с нашей формой. Это работает хорошо, но приводит к загромождению экрана и вызывает проблемы корректной модификации расположения кнопок при изменении размера формы. Д ля решения этих&lt;br /&gt;
проблем существуют меню Gambas.&lt;br /&gt;
&lt;br /&gt;
Откройте форму в режиме дизайнера, щелкните на ней правой&lt;br /&gt;
кнопкой и выберите Menu Editor (или просто наберите Ctrl+E). Теперь&lt;br /&gt;
вы можете построить структуру меню вашего приложения, добавляя в&lt;br /&gt;
него элементы. К ак всегда, не забывайте давать им осмысленные имена&lt;br /&gt;
вместо Menu1, Menu2 и так далее. Д ля создания подменю «сдвигайте» нужные элементы. К огда вы закончите и закроете редактор, новое&lt;br /&gt;
меню отобразится на форме.&lt;br /&gt;
&lt;br /&gt;
Теперь, когда главное меню находится на своем месте, надо придать&lt;br /&gt;
ему немного функциональности. Д ля начала добавим пункт для закрытия формы. Предположим, вы создали меню с названием Close и именем mnuClose. Тогда его код будет выглядеть следующим образом:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
PUBLIC SUB mnuClose_Click()&lt;br /&gt;
ME.Close&lt;br /&gt;
END&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Итак, мы получили чистую, красивую, профессионально выглядящую форму, которая действительно выполняет некоторые довольно&lt;br /&gt;
сложные задачи (или как минимум управляет процессами, которые&lt;br /&gt;
делают всё грязную работу). Вы увидели, как все Linux и Unix программисты, работавшие до нас, помогают нам хорошо жить и выглядеть.&lt;br /&gt;
Посмотрим теперь, как разработчики Gambas могут нам помочь стать&lt;br /&gt;
настоящими ленивыми программистами.&lt;br /&gt;
&lt;br /&gt;
=== Компоненты Gambas ===&lt;br /&gt;
Немного [[LXF71:Gambas|раньше, в LXF71]], вы видели, как полезны могут быть компоненты Gambas, и как легко с их помощью получить доступ к базе данных. Я хочу напомнить, что для использования компонентов вы должны&lt;br /&gt;
для начала подключить их, открыв окно Project Properties (в окне&lt;br /&gt;
проекта щелкните на слове Project, за которым идёт Properties), и&lt;br /&gt;
перейдя на вкладку Components. Вы увидите список всех компонентов,&lt;br /&gt;
доступных для вас. Чтобы увидеть, как полезны они могут быть, давайте напишем свой собственный web-браузер! Отметьте компонент gb.qt.kde.html. К огда вы вернётесь обратно, то в панели инструментов&lt;br /&gt;
обнаружите новую вкладку KDE. Щ елкнув по ней, вы увидите новые&lt;br /&gt;
объекты, которые теперь можно использовать на любой форме.&lt;br /&gt;
&lt;br /&gt;
Создайте новую форму (с названием frmWebBrowser) и добавьте&lt;br /&gt;
на нее поле ввода (txtUrl), кнопку (btnGo) и объект web-браузер&lt;br /&gt;
(webBrowser). Вам так же понадобится создать или кнопку [Close],&lt;br /&gt;
или пункт меню для закрытия формы. К ак только закончите, напишите&lt;br /&gt;
следующий код:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
PUBLIC SUB btnGo_Click()&lt;br /&gt;
IF (txtUrl.text) THEN&lt;br /&gt;
webBrowser.Path = &amp;quot;http://&amp;quot; &amp;amp; txtUrl.Text&lt;br /&gt;
END IF&lt;br /&gt;
END&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Если вы запустите получившееся приложение, то увидите, что&lt;br /&gt;
создали работающий (хотя и очень простой) интернет-браузер.&lt;br /&gt;
&lt;br /&gt;
Мы можем расширить его функциональность с помощью других&lt;br /&gt;
компонентов Gambas. Включите gb.net (компонент для работы с сетью)&lt;br /&gt;
и добавьте текстовую метку txtIP на форму. К огда закончите, перепишите ваш код, чтобы он выглядел примерно так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
PRIVATE dns AS DnsClient&lt;br /&gt;
PUBLIC SUB btnGo_Click()&lt;br /&gt;
IF (txtUrl.text) THEN&lt;br /&gt;
webBrowser.Path = &amp;quot;http://&amp;quot; &amp;amp; txtUrl.Text&lt;br /&gt;
END IF&lt;br /&gt;
txtIp.Text=&amp;quot;&amp;quot;&lt;br /&gt;
dns.HostName = txtUrl.text&lt;br /&gt;
dns.GetHostIP&lt;br /&gt;
txtIp.Text = dns.HostIP&lt;br /&gt;
END&lt;br /&gt;
PUBLIC SUB Form_Open()&lt;br /&gt;
dns = NEW DnsClient&lt;br /&gt;
END&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Запустив приложение на этот раз, вы увидите что кроме web-сайта&lt;br /&gt;
отображается его IP-адрес. Очень важно, что вам не надо знать, каким&lt;br /&gt;
образом работает тот или иной компонент. достаточно уметь использовать его.&lt;br /&gt;
&lt;br /&gt;
=== сделаем web-браузер богаче ===&lt;br /&gt;
{{Врезка&lt;br /&gt;
|Заголовок=Подсказки&lt;br /&gt;
|Содержание=&lt;br /&gt;
* Нажатие кнопки F4 открывает окно свойств. F5 запускает приложение. F6 отображает панель инструментов Gambas.&lt;br /&gt;
* если вы не помните точно, какие события можно обработать в Gambas, щелкните правой кнопкой на объекте и выберите пункт меню Events. Вы получите список событий, для которых можно написать обработчики.&lt;br /&gt;
* Спрятать текст в поле ввода можно, если установить свойство Password равным True.&lt;br /&gt;
|Ширина=250px}}&lt;br /&gt;
Мы управились с созданием простого web-браузера, но цена ему -&lt;br /&gt;
грош. Он стал чуть-чуть интереснее после добавления IP-адреса сервера, на котором находится та или иная страница. а теперь мы можем&lt;br /&gt;
сделать простой редактор HTML. его принцип работы будет немного&lt;br /&gt;
отличаться от работы браузера — вместо простого просмотра страницы&lt;br /&gt;
мы скачаем её, просмотрим и отредактируем текст, а потом загрузим&lt;br /&gt;
обратно на сервер. конечно, мы используем компоненты Gambas, чтобы&lt;br /&gt;
они сделали за нас всю грязную работу.&lt;br /&gt;
&lt;br /&gt;
Создайте новую форму (я назвал её frmHtmlEditor) и сделайте её&lt;br /&gt;
запускаемым классом или измените ваш модуль, чтобы он открывал&lt;br /&gt;
именно её. Не забудьте добавить кнопку или меню для закрытия формы.&lt;br /&gt;
Поскольку мы собираемся делать три совершенно разные вещи, давайте добавим из панели инструментов область вкладок (tab strip) и&lt;br /&gt;
назовём её tbsEditor, чтобы явно разделить три различных операции.&lt;br /&gt;
Вы увидите, что по умолчанию присутствует только одна вкладка&lt;br /&gt;
(Tab 0), используйте окно свойств, чтобы это исправить (измените параметр count). а теперь щелкните на каждой вкладке по отдельности, чтобы изменить их заголовки на что-то полезное (например, Viewer, Editor&lt;br /&gt;
и Upload).&lt;br /&gt;
&lt;br /&gt;
Вкладка Viewer очень похожа на web-браузер, который мы уже&lt;br /&gt;
делали, но код слегка отличается. Создайте объекты txtUrl, btnGo и&lt;br /&gt;
webBrowser (не забудьте подключить компонент gb.qt.kde.html).&lt;br /&gt;
кроме того, вам понадобится компонент gb.net.curl, чтобы пользоваться протоколами HTTP и FTP. код для просмотра страницы таков:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
PRIVATE http AS HttpClient&lt;br /&gt;
PRIVATE htmlfile AS String&lt;br /&gt;
PUBLIC SUB btnGo_Click()&lt;br /&gt;
http.URL = &amp;quot;http://&amp;quot; &amp;amp; txtUrl.Text&lt;br /&gt;
http.Get(htmlfile)&lt;br /&gt;
loadFile&lt;br /&gt;
END&lt;br /&gt;
PRIVATE SUB loadFile()&lt;br /&gt;
webBrowser.Path = &amp;quot;file:///&amp;quot; &amp;amp; htmlfile&lt;br /&gt;
END&lt;br /&gt;
PUBLIC SUB Form_Open()&lt;br /&gt;
http = NEW HttpClient&lt;br /&gt;
htmlfile = &amp;quot;/tmp/test.html&amp;quot;&lt;br /&gt;
END&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Обратите внимание, мы сначала скачиваем страницу и только потом&lt;br /&gt;
отдаём ей браузеру для отображения.&lt;br /&gt;
&lt;br /&gt;
На вкладке Editor создайте многострочное поле ввода txtHtml и&lt;br /&gt;
кнопку btnSave. Затем добавьте следующий код:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
PUBLIC SUB tbsEditor_Click()&lt;br /&gt;
SELECT CASE tbsEditor.Text&lt;br /&gt;
CASE &amp;quot;Viewer&amp;quot;&lt;br /&gt;
loadFile&lt;br /&gt;
CASE &amp;quot;Editor&amp;quot;&lt;br /&gt;
txtHtml.Text = File.Load(htmlfile)&lt;br /&gt;
END SELECT&lt;br /&gt;
END&lt;br /&gt;
PUBLIC SUB btnSave_Click()&lt;br /&gt;
file.Save(htmlfile,txtHtml.text)&lt;br /&gt;
END&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Нам осталось модифицировать вкладку Upload, добавив к ней три&lt;br /&gt;
поля ввода (txtTarget, txtUsername и txtPassword) и кнопку&lt;br /&gt;
btnUpload. Нам понадобится глобальный параметр&lt;br /&gt;
&amp;lt;source lang=&amp;quot;vb&amp;quot;&amp;gt;PRIVATE ftp AS FtpClient&amp;lt;/source&amp;gt;&lt;br /&gt;
и его инициализация в процедуре form_open:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;vb&amp;quot;&amp;gt;ftp = NEW FtpClient&amp;lt;/source&amp;gt;&lt;br /&gt;
В конце напишем процедуру для загрузки файла на сервер&lt;br /&gt;
&amp;lt;source lang=&amp;quot;vb&amp;quot;&amp;gt;&lt;br /&gt;
PUBLIC SUB btnUpload_Click()&lt;br /&gt;
ftp.URL = txtTarget.Text&lt;br /&gt;
ftp.User = txtUsername.Text&lt;br /&gt;
ftp.Password = txtPassword.Text&lt;br /&gt;
ftp.Put(htmlfile)&lt;br /&gt;
END&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
конечно, это очень простой редактор, в нём нет никаких проверок&lt;br /&gt;
или подсветки синтаксиса. Вы также обнаружите, что это приложение&lt;br /&gt;
может загружать на сервер только один файл (подумайте об этом на&lt;br /&gt;
досуге). Однако оно является прекрасной демонстрацией того, как много и как быстро вы можете сделать, используя компоненты Gambas.&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF76:Python</id>
		<title>LXF76:Python</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF76:Python"/>
				<updated>2008-05-15T15:19:27Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: унесите кавычки!&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{цикл/Python}}&lt;br /&gt;
''Часть 2. Возможность выводить строку на экран и делить целые числа — огромный шаг вперед по сравнению с началом прошлого века. Но в наши дни от языка программирования требуется несколько большее, так что сегодня мы продолжаем осваивать Python вместе с '''Сергеем Супруновым'''.''&lt;br /&gt;
&lt;br /&gt;
== Подробнее о типах данных ==&lt;br /&gt;
Как мы увидели на прошлом уроке, Python различает строки, целые числа и числа с плавающей запятой. Естественно, на этом его возможности не заканчиваются. Сегодня мы подробнее остановимся на оставшихся типах данных,&lt;br /&gt;
чтобы в дальнейшем знать, с чем мы имеем дело. Начнем с последовательностей — списков, кортежей и строк.&lt;br /&gt;
&lt;br /&gt;
Список — это набор переменных различных типов, упорядоченный&lt;br /&gt;
по мере добавления новых элементов. Доступ к элементу осуществляется по его порядковому номеру в последовательности (индексу). Если&lt;br /&gt;
проводить аналогию с другими языками программирования, то этот&lt;br /&gt;
тип данных наиболее близок к массивам.&lt;br /&gt;
&lt;br /&gt;
Задается список с помощью квадратных скобок, в которых элементы перечислены через запятую: [0, 1, 'два', 3.0, «четыре»]. Причем в&lt;br /&gt;
отличие, скажем, от языка Pascal, вы вполне можете смешивать в&lt;br /&gt;
одном списке данные разных типов. Индекс элемента, который вы&lt;br /&gt;
хотите получить, задается также в квадратных скобках:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; a = [0, 1, 'two', 3.0]&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; print a[1]&lt;br /&gt;
1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Как видите, первому элементу списка соответствует индекс 0.&lt;br /&gt;
Специального синтаксиса для аналога многомерных массивов не предусмотрено, но вы вполне можете «конструировать» их с помощью&lt;br /&gt;
вложенных списков, когда элементом списка является другой список:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; a = [[1,2,3],[4,5,6]]&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; a[0]&lt;br /&gt;
[1, 2, 3]&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; a[0][0]&lt;br /&gt;
1&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; a[0][0] = 1234&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; a&lt;br /&gt;
[[1234, 2, 3], [4, 5, 6]]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Для изменения списка существует ряд методов (почти все элементы в Python являются объектами классов, о чем мы поговорим в&lt;br /&gt;
одном из следующих уроков; к терминологии же начнем привыкать&lt;br /&gt;
уже сейчас). Например, append() позволяет добавлять новые элементы в конец списка:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; a = []&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; a.append('q')&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; a.append(123)&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; a.append(a)&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; print a&lt;br /&gt;
['q', 123, [...]]&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; print a[2]&lt;br /&gt;
['q', 123, [...]]&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; print a[2][2][2][2][0]&lt;br /&gt;
q&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Интересно, не правда ли? Тут мы столкнулись со специальным&lt;br /&gt;
типом данных — Ellipsis (отображается как троеточие). Он «зацикливает» последовательность саму на себя (обратите внимание, оператор print a[2] дал точно такой же результат, как и print a), в итоге&lt;br /&gt;
получается своего рода бесконечная последовательность. Обычно&lt;br /&gt;
используется при обработке многомерных матриц.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим еще несколько часто используемых методов:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; a = [1,2]&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; a.insert(0,5)&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; a&lt;br /&gt;
[5, 1, 2]&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; a.remove(1)&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; a&lt;br /&gt;
[5, 2]&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; a.extend(a)&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; a&lt;br /&gt;
[5, 2, 5, 2]&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; a.pop()&lt;br /&gt;
2&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; a&lt;br /&gt;
[5, 2, 5]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Разберемся, что делает этот код. Метод insert() вставляет элемент, значение которого задано во втором аргументе, начиная с&lt;br /&gt;
позиции, заданной первым (в примере вставляем число 5 в начало&lt;br /&gt;
списка). С помощью remove() вы можете удалить элемент по значению (если в списке несколько элементов с одним значением, удаляется первый из них). Метод extend() расширяет список заданной&lt;br /&gt;
последовательностью (заметьте, как это отличается от append()), ну&lt;br /&gt;
и pop() «выталкивает» из списка последний элемент. Удалить элемент по индексу можно оператором del, который справляется с&lt;br /&gt;
любыми переменными: del a[1].&lt;br /&gt;
&lt;br /&gt;
Помимо этого, вы можете использовать методы sort() и&lt;br /&gt;
reverse(). Оставим их вам для самостоятельного изучения.&lt;br /&gt;
&lt;br /&gt;
Для работы со списками в Python существует непревзойденный&lt;br /&gt;
по гибкости механизм — так называемые срезы. Например, операция&lt;br /&gt;
ar[2:5] возвратит список, содержащий элементы списка ar начиная с&lt;br /&gt;
третьего (нумерация — с нуля!) и до шестого (исключительно).&lt;br /&gt;
Пропуск того или иного индекса означает «с начала» или «до конца»,&lt;br /&gt;
отрицательный индекс — «с конца списка». А с помощью ar[1:8:2]&lt;br /&gt;
будут выбраны только четные элементы (каждый второй) из диапазона 1-7. Внимательно рассмотрите приведенные ниже примеры, поэкспериментируйте сами, и вам все станет понятно:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; a = [0,1,2,3,4,5,6,7,8,9]&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; a[3:5]&lt;br /&gt;
[3, 4]&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; a[4:], a[:2]&lt;br /&gt;
([4, 5, 6, 7, 8, 9], [0, 1])&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; a[-2:]&lt;br /&gt;
[8, 9]&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; a[:]&lt;br /&gt;
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; a[1:9:3]&lt;br /&gt;
[1, 4, 7]&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; a[::2]&lt;br /&gt;
[0, 2, 4, 6, 8]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Следует также сказать про так называемые списковые включения — специальные синтаксические конструкции, позволяющие генерировать список на базе другого:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; a = [b**2 for b in [1,2,3,4,5] if b &amp;gt; 2]&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; print a&lt;br /&gt;
[9, 16, 25]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Оператор «**» — это возведение в степень. Секция if спискового&lt;br /&gt;
включения может быть опущена (в ней задается фильтрующее условие). Вместо явного указания списка (после in) вы, естественно,&lt;br /&gt;
можете использовать и переменную, содержащую последовательность. Поэкспериментируйте со списковыми включениями — с их&lt;br /&gt;
помощью можно достигать удивительных результатов.&lt;br /&gt;
&lt;br /&gt;
Кортеж — это неизменяемый список. Элементы в нем упорядочены по индексам, обращаться вы можете к ним так же, как и в списке,&lt;br /&gt;
но методы, изменяющие кортеж, отсутствуют. Содержимое кортежа&lt;br /&gt;
записывается в круглых скобках — tuple = (1, 2, «three»). Если&lt;br /&gt;
вам нужно задать кортеж из одного элемента, поставьте после него&lt;br /&gt;
запятую — ('5',).&lt;br /&gt;
&lt;br /&gt;
Замечу, что операции среза применимы и к кортежам (поскольку&lt;br /&gt;
сам кортеж при этом не изменяется, а просто создается новая переменная, тоже кортеж, на его основе).&lt;br /&gt;
&lt;br /&gt;
Кортежи работают быстрее списков, поэтому, если вы не планируете изменять последовательность, то лучше использовать именно их.&lt;br /&gt;
&lt;br /&gt;
Вы можете складывать списки со списками или кортежи с кортежами — результат будет содержать элементы последовательностей-&amp;quot;слагаемых&amp;quot;, причем обратите внимание, что порядок элементов&lt;br /&gt;
всегда строго сохраняется:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; b = [3,4,5]&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; c = [1,2]&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; d = b + c + [9,8,7]&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; print d&lt;br /&gt;
[3, 4, 5, 1, 2, 9, 8, 7]&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; d = [9,8,7] + c + b&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; print d&lt;br /&gt;
[9, 8, 7, 1, 2, 3, 4, 5]&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; (1,2) + (3,4)&lt;br /&gt;
(1, 2, 3, 4)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Теперь самое время познакомиться с циклом for. Он позволяет&lt;br /&gt;
проходить по каждому элементу последовательности, выполняя те&lt;br /&gt;
или иные действия:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; a = [1,2,3,4,5]&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; for i in a:&lt;br /&gt;
... print i * 2,&lt;br /&gt;
...&lt;br /&gt;
2 4 6 8 10&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Про отступы, думаю, вы помните. Запятая после операнда в операторе print отменяет перевод строки, благодаря чему выводимые&lt;br /&gt;
значения располагаются на одной строке. Для организации привычного многим цикла «от X до Y» используется функция range(X, Y),&lt;br /&gt;
генерирующая нужную последовательность:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; for i in range(3, 8):&lt;br /&gt;
... print i,&lt;br /&gt;
...&lt;br /&gt;
3 4 5 6 7&lt;br /&gt;
&amp;lt;/source&amp;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;
цикле for для прохода по каждой букве, и так далее.&lt;br /&gt;
&lt;br /&gt;
Помимо скалярных типов данных и последовательностей, Python&lt;br /&gt;
поддерживает так называемые словари. Словарь — это набор пар&lt;br /&gt;
«ключ — значение» (в Perl это называется хэшем, можно встретить и&lt;br /&gt;
термин «ассоциативный массив»). Ключ должен быть уникален в&lt;br /&gt;
пределах словаря (именно по нему выполняется поиск нужного элемента), и в отличие от рассмотренных выше последовательностей,&lt;br /&gt;
порядок элементов в словаре не определен. Синтаксис и основные&lt;br /&gt;
операции, которые вы можете выполнять над словарями, продемонстрированы в примере:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; dict = {&lt;br /&gt;
... 'ru': 'Russia',&lt;br /&gt;
... 'uk': 'United Kingdom',&lt;br /&gt;
... }&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; print dict&lt;br /&gt;
{'ru': 'Russia', 'uk': 'United Kingdom'}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; dict.pop('uk')&lt;br /&gt;
'United Kingdom'&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; print dict&lt;br /&gt;
{'ru': 'Russia'}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; dict['us'] = 'USA'&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; print dict&lt;br /&gt;
{'ru': 'Russia', 'us': 'USA'}&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; print dict['ru']&lt;br /&gt;
Russia&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; dict.keys()&lt;br /&gt;
['ru', 'us']&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; dict.values()&lt;br /&gt;
['Russia', 'USA']&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; dict.items()&lt;br /&gt;
[('ru', 'Russia'), ('us', 'USA')]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Запись присвоения переменной dict выполнена на нескольких&lt;br /&gt;
строках для удобства представления (внутри фигурных скобок вы&lt;br /&gt;
можете переносить строки и устанавливать любые отступы; аналогично можно поступать и со списками и кортежами). Но вы вполне&lt;br /&gt;
можете записывать все в одной строке. Обращение к элементу словаря по ключу выполняется так же, как вы выбор элемента списка по&lt;br /&gt;
индексу (с той разницей, что ключ не обязан быть целым числом).&lt;br /&gt;
Если присвоить значение несуществующему элементу, то он добавится в словарь. Последние три метода, показанные в примере, позволяют получить соответствующие списки (ключей, значений и кортежей&lt;br /&gt;
«ключ-значение»), которые могут быть использованы, например, для&lt;br /&gt;
обработки словаря в цикле:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; arkeys = dict.keys()&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; arkeys.sort()&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; for domain in arkeys:&lt;br /&gt;
... print &amp;quot;%s = %s&amp;quot; % (domain, dict[domain])&lt;br /&gt;
...&lt;br /&gt;
ru = Russia&lt;br /&gt;
us = USA&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Кстати, переменные, значением которых заполняются знакоместа&lt;br /&gt;
%s при выводе текста, если таковых две и больше, должны передаваться как кортеж, то есть в круглых скобках. Может использоваться&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;
В первой статье цикла мы уже встречались с функцией float(),&lt;br /&gt;
которая преобразует целое число или строку, переданные ей в качестве аргумента, в число с плавающей запятой. Как вы видели, вызов&lt;br /&gt;
функции происходит по имени, а в скобках передаются аргументы,&lt;br /&gt;
над которыми функция выполняет действия. Функция может не иметь&lt;br /&gt;
аргументов, однако указывать скобки после ее имени необходимо.&lt;br /&gt;
Результат своей работы функция возвращает основной программе&lt;br /&gt;
(причем вызов функции трактуется в выражениях именно как это возвращаемое значение; например, в выражении sum = z + float(b) к&lt;br /&gt;
переменной z добавится результат, возвращенный функцией, а не&lt;br /&gt;
сама функция). Функция может и не возвращать значения явно — в&lt;br /&gt;
этом случае возвращается результат специального типа None.&lt;br /&gt;
&lt;br /&gt;
Вернемся к типам данных. Полный список поддерживаемых&lt;br /&gt;
типов можно получить с помощью следующего кода (не пугайтесь,&lt;br /&gt;
ниже я все объясню):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; import types&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; for t in [t for t in dir(types) if t[0:2] != '__']:&lt;br /&gt;
... print t&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Первой строкой мы подключаем один из системных модулей -&lt;br /&gt;
types. Модуль — это программа на Python, содержащая функции,&lt;br /&gt;
переменные, классы и т. д., которые вы можете в дальнейшем&lt;br /&gt;
использовать в своих сценариях. Подробнее о них разговор у нас&lt;br /&gt;
пойдет в следующий раз. Пока достаточно знать, что здесь мы подгружаем модуль types и получаем доступ к его функциям, служащим&lt;br /&gt;
для преобразования типов. Их полный список выводит функция dir(),&lt;br /&gt;
ну а про списковые включения вы уже знаете. Поясню только фрагмент if — с его помощью мы исключаем из вывода специальные функции и переменные, которые начинаются двумя символами подчеркивания (здесь мы применяем операцию среза к строке t).&lt;br /&gt;
&lt;br /&gt;
В результате выполнения этого кода вы получите список из 35&lt;br /&gt;
функций преобразования, соответствующих типам Python. Можно&lt;br /&gt;
увидеть, что и функции, и классы являются допустимыми типами&lt;br /&gt;
данных, что позволяет присваивать их переменным: например, вы&lt;br /&gt;
можете записать mydirfunc = dir, и в дальнейшем mydirfunc можно&lt;br /&gt;
будет использовать точно так же, как и функцию dir: print&lt;br /&gt;
mydirfunc(types).&lt;br /&gt;
&lt;br /&gt;
Типов данных существует достаточно много, но для начала работы с Python достаточно тех, что были описаны выше.&lt;br /&gt;
&lt;br /&gt;
Подведем итог. Сегодня мы не написали ничего полезного, но&lt;br /&gt;
заложили фундамент для дальнейшей работы.&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF74-75:Python</id>
		<title>LXF74-75:Python</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF74-75:Python"/>
				<updated>2008-05-15T15:17:26Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: унесите кавычки!&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{цикл/Python}}&lt;br /&gt;
''ЧАСТЬ 1 Язык программирования Python становится достаточно популярным и уже практически на равных может бороться за благосклонность пользователей с таким бывалым соперником, как Perl. Поэтому с ним стоит познакомиться, считает '''Сергей Супрунов'''.''&lt;br /&gt;
&lt;br /&gt;
== Немного истории ==&lt;br /&gt;
Началось все в далеком 1990 году, когда Гвидо ван Россум&lt;br /&gt;
(Guido van Rossum) разработал первую версию языка Python,&lt;br /&gt;
который появился в свободном доступе в 1991 году. Первоначально созданный как язык сценариев для разрабатываемой Россумом системы&lt;br /&gt;
Amoeba, он оказался настолько хорош и переносим, что достаточно быстро получил распространение на самых различных операционных системах.&lt;br /&gt;
&lt;br /&gt;
Сейчас этот язык входит в поставку практически всех популярных&lt;br /&gt;
дистрибутивов Linux; его, наряду с Perl, поддерживают Apache&lt;br /&gt;
(модуль mod_python), PostgreSQL (процедурный язык PL/Python) и&lt;br /&gt;
многие другие программы.&lt;br /&gt;
&lt;br /&gt;
== Отличительные особенности ==&lt;br /&gt;
Почему же Python столь стремительно завоевывает популярность?&lt;br /&gt;
&lt;br /&gt;
Прежде всего, будучи интерпретируемым языком, Python не требует компиляции, компоновки и прочих «премудростей» — сценарий на&lt;br /&gt;
Python может быть запущен практически сразу же после редактирования. Это существенно снижает время разработки и делает Python весьма удобным для таких задач как создание прототипов программ, проверка работоспособности того или иного алгоритма, а также для администрирования, где время исполнения — гораздо менее важный фактор,&lt;br /&gt;
чем удобство модификации сценария.&lt;br /&gt;
&lt;br /&gt;
Вторым большим плюсом этого языка является уже упоминавшаяся&lt;br /&gt;
переносимость между различными системами. Если вы не используете&lt;br /&gt;
специфические особенности платформы (например, команду fork для&lt;br /&gt;
ветвления процессов), то с большой долей вероятности ваш код, разработанный в Linux, сможет работать и во FreeBSD, и даже в Windows.&lt;br /&gt;
&lt;br /&gt;
Далее, поскольку Python — язык высокого уровня, он позволяет&lt;br /&gt;
вам сосредоточиться на алгоритме, на логике программы, не отвлекаясь на описание переменных, выделение памяти и т. п.&lt;br /&gt;
&lt;br /&gt;
Ну и самое главное — Python разрабатывается как проект opensource,&lt;br /&gt;
то есть вы можете не только использовать его в своей работе&lt;br /&gt;
без каких-либо ограничений, но и активно участвовать в его развитии.&lt;br /&gt;
&lt;br /&gt;
Все это делает Python хорошим выбором для самого широкого&lt;br /&gt;
спектра задач — от автоматизации рутинных операций по администрированию и разработки графических «оберток» для консольных утилит&lt;br /&gt;
до web-программирования и разработки прототипов в крупных&lt;br /&gt;
проектах.&lt;br /&gt;
&lt;br /&gt;
== Где его взять? ==&lt;br /&gt;
Большинству пользователей Linux об этом беспокоиться не нужно -&lt;br /&gt;
Python входит почти во все популярные дистрибутивы. Откройте окно&lt;br /&gt;
терминала, наберите там команду python, и если в ответ увидите сообщение о версии интерпретатора и приглашение «&amp;gt;&amp;gt;&amp;gt;», значит, он у вас&lt;br /&gt;
уже есть. Если же вам не повезло и вы увидели сообщение «Command&lt;br /&gt;
not found», то придется озаботиться его установкой.&lt;br /&gt;
&lt;br /&gt;
Свежую версию Python (архив с исходными кодами) всегда можно&lt;br /&gt;
найти на официальной странице: http://www.python.org/download/ .&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;
Так что вводите команду python в окне терминала, и — вперед! Для&lt;br /&gt;
начала потренируемся с математикой (после ввода команды в строке&lt;br /&gt;
приглашения, которая отмечается символами «&amp;gt;&amp;gt;&amp;gt;» следует нажимать&lt;br /&gt;
[Enter], чтобы увидеть результат):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; 1+3&lt;br /&gt;
4&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; a=5&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; 3 + a&lt;br /&gt;
8&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; a / 3&lt;br /&gt;
1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Ага, вот и первый сюрприз. Как и в языке C, при делении целого&lt;br /&gt;
числа на целое результат — тоже целое число, дробная часть отбрасывается. Чтобы обойти эту особенность, один из операндов нужно сделать числом с плавающей запятой:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; a / 3.0&lt;br /&gt;
1.6666666666666667&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; (a * 1.0) / 3&lt;br /&gt;
1.6666666666666667&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Этот пример показывает, что в Python существует понятие «тип&lt;br /&gt;
переменной», и если преобразование между типами не лишено смысла, то оно выполняется прозрачно для программиста. Впрочем, можно&lt;br /&gt;
использовать и явное преобразование:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; float(a) / 3&lt;br /&gt;
1.6666666666666667&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
В текущей версии языка для целочисленного деления существует&lt;br /&gt;
отдельный оператор — «//». Сейчас выражения 3/2 и 3//2 вернут один&lt;br /&gt;
и тот же результат, но в будущих версиях поведение «традиционного»&lt;br /&gt;
оператор деления («/») может быть приведено к привычному для человека, когда 3/2 = 1.5.&lt;br /&gt;
&lt;br /&gt;
Операция сложения допустима и для строк (которые могут быть&lt;br /&gt;
заключены как в апострофы, так и в кавычки):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; 'Hello, ' + &amp;quot;world!&amp;quot;&lt;br /&gt;
'Hello, world!'&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; &amp;quot;127&amp;quot; + 5&lt;br /&gt;
Traceback (most recent call last):&lt;br /&gt;
File &amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;, line 1, in ?&lt;br /&gt;
TypeError: cannot concatenate 'str' and 'int' objects&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
А вот смешивать символьные типы с числовыми нельзя — это вам&lt;br /&gt;
не Perl! Еще одна интересная операция для строк — повторение:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; '=' * 25&lt;br /&gt;
'========================='&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
При выводе динамически формируемых текстовых строк важное&lt;br /&gt;
значение имеют символы подстановки:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; language = 'Python'&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; print &amp;quot;I like %s&amp;quot; % language&lt;br /&gt;
I like Python&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Здесь мы в выводимом тексте создаем так называемое «знакоместо» %s, которое затем заполняется значением переменной, стоящей&lt;br /&gt;
после оператора %. В последующих статьях цикла мы познакомимся с&lt;br /&gt;
ними более подробно. Ну а оператор print, думаю, пояснять не нужно -&lt;br /&gt;
он просто выводит строку на экран (обратите внимание на отсутствие&lt;br /&gt;
апострофов в выводе команды).&lt;br /&gt;
&lt;br /&gt;
Чтобы выйти из командной оболочки, нажмите [Ctrl]+[D].&lt;br /&gt;
&lt;br /&gt;
== Первая программа ==&lt;br /&gt;
Настало время написать первую настоящую программу. Откройте ваш&lt;br /&gt;
любимый текстовый редактор. Я предпочитаю работать в vi, но вы&lt;br /&gt;
вполне можете выбрать и более привычный инструмент; кроме того,&lt;br /&gt;
существует немало редакторов, обладающих рядом сервисных функций, таких как подсветка синтаксиса, автоотступ и т. д. Один из них, Eric,&lt;br /&gt;
рассматривается в разделе HotPicks. Вы также можете обратить внимание на KDevelop и IDLE, редактор, поставляемый вместе с Python.&lt;br /&gt;
Наберите приведенный ниже код. Немного нарушив традицию, мы сразу приступим к сравнительно сложному примеру, который позволит&lt;br /&gt;
познакомиться с большинством синтаксических особенностей языка.&lt;br /&gt;
Да и «Hello, World!» мы фактически уже написали, когда были в интерактивной оболочке. Еще одна просьба — когда будете вводить код, не&lt;br /&gt;
спешите читать его описание далее в этой статье. Постарайтесь догадаться сами, что делает этот сценарий — это совсем не сложно. Итак,&lt;br /&gt;
код (сохраните его в файле test1.py):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python&lt;br /&gt;
prompt = '&amp;gt; '&lt;br /&gt;
cmd = 'nocmd'&lt;br /&gt;
while cmd != 'exit':&lt;br /&gt;
cmd = raw_input(prompt)&lt;br /&gt;
if cmd == 'about':&lt;br /&gt;
print 'It is my first python script'&lt;br /&gt;
elif cmd == 'help':&lt;br /&gt;
print '''Commands:&lt;br /&gt;
about – about this program&lt;br /&gt;
help – this information&lt;br /&gt;
exit – quit the program'''&lt;br /&gt;
elif cmd =='exit':&lt;br /&gt;
pass # пустая команда – не делает ничего&lt;br /&gt;
else:&lt;br /&gt;
print 'Command not found. Type &amp;quot;help&amp;quot;'&lt;br /&gt;
print 'Bye.'&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Для удобства чтения строковые константы выделены в тексте курсивом. Надеюсь, вы уже поняли, что приведенный скрипт должен&lt;br /&gt;
будет имитировать работу простейшей командной оболочки, запрашивая у пользователя команды и выводя результат их исполнения. Таких&lt;br /&gt;
команд три:&lt;br /&gt;
* about: вывести информацию о программе;&lt;br /&gt;
* help: напечатать краткую справку по работе с программой;&lt;br /&gt;
* exit: команда выхода из программы.&lt;br /&gt;
&lt;br /&gt;
В этом фрагменте мы встречаемся с одним из циклов (while, другой популярный цикл — for — рассмотрим в следующей статье) и оператором ветвления if-elif-else. Если вы знакомы с каким-нибудь языком программирования, то все вам будет понятно. Но обратите внимание на синтаксис: в Python неотъемлемой частью программы являются&lt;br /&gt;
отступы. Именно они показывают интерпретатору, где заканчивается&lt;br /&gt;
тот или иной блок кода. В приведенном выше примере последняя строка будет выполнена при выходе из цикла, поскольку она не имеет&lt;br /&gt;
отступа и потому телу цикла while не принадлежит.&lt;br /&gt;
&lt;br /&gt;
Особо следует пояснить отсутствие отступа в строках, заключенных&lt;br /&gt;
в тройные апострофы (фрагмент elif, отвечающий за выполнение&lt;br /&gt;
команды «help»). Такие строки могут содержать в себе и символы&lt;br /&gt;
перевода строки, и табуляцию. Интерпретатор воспринимает все это&lt;br /&gt;
как одну строковую константу — на экран все будет выведено именно&lt;br /&gt;
так, как набрано в коде сценария. (Чтобы было проще понять программу, замените на первых порах эту строку обычной, — тогда она не будет&lt;br /&gt;
сбивать вас с толку и лучше будет видно структуру сценария).&lt;br /&gt;
&lt;br /&gt;
На Unix-подобных системах очень важную роль играет самая первая строка сценария — в ней следует указать путь к интерпретатору&lt;br /&gt;
python (обычно это /usr/bin/python или /usr/local/bin/python). В&lt;br /&gt;
остальных строках символ «#» означает начало комментария — все,&lt;br /&gt;
что за ним следует, интерпретатором игнорируется.&lt;br /&gt;
&lt;br /&gt;
Осталось сделать наш файл исполняемым (chmod +x test1.py)&lt;br /&gt;
и убедиться, что все работает правильно:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
serg$ ./test1.py&lt;br /&gt;
&amp;gt; hello&lt;br /&gt;
Command not found. Type &amp;quot;help&amp;quot;&lt;br /&gt;
&amp;gt; help&lt;br /&gt;
Commands:&lt;br /&gt;
about – about this program&lt;br /&gt;
help – this information&lt;br /&gt;
exit – quit the program&lt;br /&gt;
&amp;gt; about&lt;br /&gt;
It is my first python script&lt;br /&gt;
&amp;gt; exit&lt;br /&gt;
Bye.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
В случае ошибок проверяйте синтаксис, особенно отступы. И не&lt;br /&gt;
забудьте убедиться, что вы используете именно тот путь к интерпретатору, который принят в вашем дистрибутиве.&lt;br /&gt;
&lt;br /&gt;
Ну что ж. Для первого урока, думаю, достаточно. В следующий раз&lt;br /&gt;
мы рассмотрим так называемые последовательности (списки, кортежи&lt;br /&gt;
и словари) — очень важные типы данных, делающие Python столь мощным языком программирования, а также затронем основы работы&lt;br /&gt;
с функциями и модулями.&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/%D0%A8%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD:%D0%92%D1%80%D0%B5%D0%B7%D0%BA%D0%B0</id>
		<title>Шаблон:Врезка</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/%D0%A8%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD:%D0%92%D1%80%D0%B5%D0%B7%D0%BA%D0%B0"/>
				<updated>2008-05-15T15:12:36Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: Параметр выравнивания&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div style=&amp;quot;background: #f9f9f9; border: 1px solid #aaaaaa; float: {{{1|right}}}; clear: {{{1|right}}}; margin: .5em {{#switch: {{{1}}} | left=1.4em | 0em}} .8em {{#switch: {{{1}}} | right = 1.4em | 0em}}; font-size: 90%; padding: .5em 1em; width: {{{Ширина|auto}}}; height: {{{Высота|auto}}};&amp;quot;&amp;gt;&lt;br /&gt;
{{#if:{{{Заголовок|}}}|&amp;lt;div style=&amp;quot;border-bottom: 1px solid #aaaaaa; padding-bottom: .4em; font-weight: bold; font-size: 120%;&amp;quot;&amp;gt;{{{Заголовок}}}&amp;lt;/div&amp;gt;}}&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-top: .4em;&amp;quot;&amp;gt;&lt;br /&gt;
{{{Содержание}}}&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Шаблон Врезка предназначен для добавления в статьи врезок с текстом и заголовком. Такие врезки могут «плавать» сбоку от основного текста.&lt;br /&gt;
&lt;br /&gt;
== Использование ==&lt;br /&gt;
Шаблону можно передавать следующие параметры:&lt;br /&gt;
* Параметр выравнивания: принимает значения right, left и both для выравнивания по правому, левому, и обоим краям соответственно. Если этот параметр не указан врезки выравниваются по правому краю.&lt;br /&gt;
* '''Заголовок''' (необязателен) — текст заголовка, который отображается крупным шрифтом над основным текстом врезки и отделяется от него чертой. Если заголовок не указан, черта не отображается (остаётся только основной текст врезки).&lt;br /&gt;
* '''Содержание''' — собственно текст врезки.&lt;br /&gt;
* '''Ширина''' (необязателен) — ширина врезки в формате CSS (например 200px). По умолчанию значение параметра равно auto.&lt;br /&gt;
* '''Высота''' (необязателен) — высота врезки в формате CSS (например 200px). По умолчанию значение параметра равно auto.&lt;br /&gt;
особенно подходит для стихотворений. По сути, альтернативный способ задания ширины («та ширина, которая нужна»).&lt;br /&gt;
&lt;br /&gt;
== Пример использования ==&lt;br /&gt;
{{Врезка&lt;br /&gt;
|Заголовок=А ещё…&lt;br /&gt;
|Содержание=Lockal считает Ubuntu лучшей операционной системой!&lt;br /&gt;
|Ширина=100px}}&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;{{&amp;lt;/nowiki&amp;gt;Врезка&lt;br /&gt;
|Заголовок=А ещё…&lt;br /&gt;
|Содержание=Lockal считает Ubuntu лучшей операционной системой!&lt;br /&gt;
|Ширина=100px}}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Врезка|left|&lt;br /&gt;
|Заголовок=И ещё…&lt;br /&gt;
|Содержание=Yaleks считает Gentoo лучшим дистрибутивом!&lt;br /&gt;
|Ширина=100px}}&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;{{&amp;lt;/nowiki&amp;gt;Врезка|left|&lt;br /&gt;
|Заголовок=И ещё…&lt;br /&gt;
|Содержание=Yaleks считает Gentoo лучшим дистрибутивом!&lt;br /&gt;
|Ширина=100px}}&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF74-75:VMware_Workstation_5.5</id>
		<title>LXF74-75:VMware Workstation 5.5</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF74-75:VMware_Workstation_5.5"/>
				<updated>2008-05-15T15:05:03Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: Новая: ''64 не работает в 32-х. Ну, если хорошенько виртуализироваться, то заработает, обнаружил Грэм Моррисон (Gr...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;''64 не работает в 32-х. Ну, если хорошенько виртуализироваться, то заработает, обнаружил Грэм Моррисон (Graham Morrison).''&lt;br /&gt;
&lt;br /&gt;
{{Врезка|left|Ширина=250px|&lt;br /&gt;
Заголовок = Самое главное |&lt;br /&gt;
Содержание = Выдержит столько виртуальных машин, сколько потянет ваша система. Подходит для запуска и Linux, и Windows.&lt;br /&gt;
* '''РАЗРАБОТЧИК:''' VMware Inc.&lt;br /&gt;
* '''САЙТ:''' www.vmware.com&lt;br /&gt;
* '''ЦЕНА:''' $189 или бесплатно для пользователей VMware Workstation 5.0&lt;br /&gt;
}}&lt;br /&gt;
[[Изображение:LXF74-75 VMware-1.png|thumb|Эмуляция двух процессоров на однопроцессорной машине. Даже KSysguard оставили в дураках.]]&lt;br /&gt;
Прошло 6 месяцев с последнего обзора VMware Workstation (см. LXF68). Для нас, смертных, это вроде не так уж и долго, но, похоже, авторы VMware работают с нечеловеческой скоростью: они внесли несколько важных дополнений в версию 5.5 их бесподобной виртуальной программной среды. Но будет ли этого достаточно, чтобы остаться впереди группы преследователей?&lt;br /&gt;
&lt;br /&gt;
Ярчайшей из новых возможностей является поддержка и запуск 64-битных гостевых операционных систем на 32-битных машинах. К сожалению, есть несколько серьезных ограничений, обусловленных совместимостью с хост-системой: необходимо иметь либо процессор AMD Opteron/Athlon 64, либо Intel с поддержкой VT.&lt;br /&gt;
&lt;br /&gt;
Единственный способ узнать, подходит ли ваш процессор для работы — это выбрать 64-битную операционную систему в мастере Новой Виртуальной Машины. К счастью, на сайте VMware вы можете найти отдельную небольшую утилиту, которая сможет проверить совместимость вашей системы до того, как вы купите VMware 5.5.&lt;br /&gt;
&lt;br /&gt;
=== Бит по зубам ===&lt;br /&gt;
[[Изображение:LXF74-75 VMware-2.png|thumb|VMware теперь поддерживает 64-битные гостевые ОС.]]&lt;br /&gt;
[[Изображение:LXF74-75 VMware-3.png|thumb|Запускайте один или два виртуальных процессора.]]&lt;br /&gt;
Среди 64-битных Windows-систем официально поддерживаются XP, Server 2003 и, что интересно, бета-версия Windows Vista. Более того, VMware предоставляет новые версии драйверов сетевых карт и мышей для ваших 64-битных «гостей». Распознается большинство 64-битных вариантов Linux, а также Solaris 10 и FreeBSD. Важно также отметить, что в отличие от Parallel Workstation, VMware прекрасно работает и на компьютерах с 64-битной ОС.&lt;br /&gt;
&lt;br /&gt;
Способность протестировать 64-битную операционную систему под управлением вашей 32-битной ОС — это просто прекрасно. Эта возможность поднимает VMware на новый уровень, когда можно перед выпуском или развертыванием приложений провести их тестирование в предельных режимах.&lt;br /&gt;
&lt;br /&gt;
Есть еще одно дополнение, которое продолжает тему эмулирования аппаратного обеспечениия, которое вы не можете купить — это способность эмулировать более одного процессора. В отличие от 64битных ОС, вы можете эмулировать двухпроцессорную систему на любом, достаточно быстром компьютере — невероятно, но это работает! Мы обнаружили, что установленная гостевая операционная система была безразлична к природе второго процессора, что является дополнительным плюсом в адрес VMware.&lt;br /&gt;
&lt;br /&gt;
Еще одна опция способна приковать взоры, прежде всего, пользователей Windows — это способность открывать виртуальные машины Microsoft и образы Norton Ghost 9. Последнее особенно полезно, ибо многие используют Norton Ghost для резервирования информации. Конвертирование образов Ghost 9 в виртуальную машину означает, что вы можете работать даже когда ваше оборудование находится в ремонте. Если вы являетесь системным администратором, это поможет избежать паники при выходе оборудования из строя.&lt;br /&gt;
&lt;br /&gt;
=== Попробуйте бесплатно ===&lt;br /&gt;
[[Изображение:LXF74-75 VMware-4.png|thumb|Поделитесь своей виртуальной машин, используя VMware Player.]]&lt;br /&gt;
Еще одной большой новостью для этой версии является проигрыватель виртуальных машин VMware Player (тоже бесплатный и доступный для загрузки отдельно). Слово «проигрыватель» может ввести в заблуждение. Это файл размером 34 Мб, позволяющий любому использовать виртуальные машины, созданные VMware Workstation, но не допускающий создания, изменения или сохранения снимков виртуальных машин — VMware Player подобен Adobe Reader для Adobe Acrobat. Это прекрасное добавление, возможности использования которого поистине безграничны. К примеру, разработчик может подключить виртуальную машину, выдающую сообщение об ошибке, вместо того, чтобы пытаться воспроизвести ситуацию ее возникновения у себя. Конфигурирование приложения/сервера также значительно упрощается — ведь вы можете без труда делать это на своем собственном компьютере.&lt;br /&gt;
&lt;br /&gt;
С другой стороны, все еще нет поддержки OpenGL для гостевых Linux-систем. Гостевые системы Windows обеспечиваются примитивной версией Direct 3D, поэтому, конечно же, следует обеспечить равные возможности и для гостевых ОС Linux. Это поможет нам запускать такие жизненно важные графические приложения, как Crack Attack с максимальной производительностью.&lt;br /&gt;
&lt;br /&gt;
Но пользователи Linux-версии имеют возможность создания виртуального беспроводного сетевого устройства, позволяющего виртуальной машине создавать собственные подключения к беспроводным сетям вместо использования Ethernet.&lt;br /&gt;
&lt;br /&gt;
VMware Workstation 5.5 содержит столько дополнений, что могла бы продаваться как VMware 6. Но пользователи версии 5 могут получить ее бесплатно как обновление — а ведь она уже включает прекрасный менеджер снимков состояния вместе с простым размещением образов и исключительной совместимостью виртуальных машин. Может быть, нечеловеческая скорость работы сохранится.&lt;br /&gt;
&lt;br /&gt;
=== Вердикт Linux Format ===&lt;br /&gt;
* Возможности — 8/10&lt;br /&gt;
* Функционирование — 8/10&lt;br /&gt;
* Простота использования 6/10&lt;br /&gt;
* Документация — 7/10&lt;br /&gt;
Благодаря своим новым впечатляющим возможностям, VMware оставила всех конкурентов далеко позади.&lt;br /&gt;
* ''Рейтинг — 8/10''&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF74-75:Parallel_Workstation_2.0</id>
		<title>LXF74-75:Parallel Workstation 2.0</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF74-75:Parallel_Workstation_2.0"/>
				<updated>2008-05-15T14:49:27Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: Новая: __NOTOC__''Перед обзором последней версии VMware Грэм Моррисон (Graham Morrison) решил взглянуть на более дешевую ал...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__''Перед обзором последней версии VMware Грэм Моррисон (Graham Morrison) решил взглянуть на более дешевую альтернативу.''&lt;br /&gt;
&lt;br /&gt;
{{Врезка|left|Ширина=200px|&lt;br /&gt;
Заголовок = Самое главное |&lt;br /&gt;
Содержание = Позволяет запускать виртуальную машину для тестирования или работы в другой операционной системе. Альтернативы: Qemu или Xen.&lt;br /&gt;
* '''РАЗРАБОТЧИК''' Parallels Inc&lt;br /&gt;
* '''САЙТ''' www.parallels.com&lt;br /&gt;
* '''ЦЕНА''' $99}}&lt;br /&gt;
&lt;br /&gt;
Использование виртуальных машин имеет много плюсов для бизнеса, и взлет VMware как серьезного промышленного продукта не прошел незамеченным. Почти на каждой выставке или публичном мероприятии за последний год мы встречали множество людей, говоривших об использовании VMware тем или иным способом, а успех GSX/ESX-сервера говорит сам за себя.&lt;br /&gt;
&lt;br /&gt;
Конечно, имитация — это наилучшая форма лести, и не секрет, что VMware — давно уже не единственная виртуальная программная среда в мире. Xen является одним из заметных Linux-проектов и даже Microsoft разрабатывает свой собственный Xen-подобный продукт для запуска множества операционных систем.&lt;br /&gt;
&lt;br /&gt;
Parallel Workstation — это новое направление развития ПО, стремящееся отвоевать свою долю у больших игроков на рынке виртуализации. Оно переняло многие технологии от старого продукта, производимого Parallels под названием Serenity Virtual Station. В то время как последняя версия ориентирована на настольные компьютеры, Parallels явно планирует создать на базе Workstation продукт, подходящий для зарождающегося корпоративного рынка приложений виртуализации.&lt;br /&gt;
&lt;br /&gt;
=== Одинаковые, но разные ===&lt;br /&gt;
{{Врезка|right|Ширина=400px|&lt;br /&gt;
Заголовок = Неудобные параллели|&lt;br /&gt;
Содержание = &lt;br /&gt;
{{{!}}&lt;br /&gt;
{{!}} [[Изображение:LXF74-75_Parallel_Workstation-1.png|200px]] {{!}}{{!}}[[Изображение:LXF74-75_Parallel_Workstation-2.png|200px]]&lt;br /&gt;
{{!}}}&lt;br /&gt;
Parallels пошли на хитрость при создании интерфейса своей системы. Он (справа) очень схож с интерфейсом VMware (слева). &lt;br /&gt;
&lt;br /&gt;
Первое, что бросается в глаза после запуска Parallels Workstation – до боли знакомый интерфейс, крайне схожий с интерфейсом VMware Workstation. Это было бы неплохо, если бы интерфейс VMware был идеальным, но это не так. Оба приложения содержат почти одинаковые элементы в меню File, Edit, View и VM, но Parallels переместила пункт «Устройства» из меню VM в отдельный элемент главного меню. Даже маленькие иконки, показывающие сетевую активность, идентичны. Это можно объяснить стремлением к универсализации, то есть чтобы пользователи, знакомые с VMware, не испытывали больших трудностей при использовании Parallel Workstation. Но это выглядит и как упущенная возможность создания реальных отличий в лучшую сторону по сравнению с конкурентом.}}&lt;br /&gt;
&lt;br /&gt;
Parallels Workstation напоминает раннюю версию VMware. Она очень похожа на нее внешне (смотри врезку «Неудобные параллели» справа), выполняет те же основные функции, что и VMware, и даже использует ту же комбинацию клавиш [Ctrl]+[Alt] для выхода в основную операционную систему.&lt;br /&gt;
&lt;br /&gt;
Есть и другие явные признаки сходства. Как и в VMware, перед запуском вам необходимо запустить утилиту конфигурации суперпользователя. Parallel Workstation значительно проще в использовании, но беднее функционально — это прямое следствие более низкой цены. Например, вы не найдете в нем сервера Samba для совместного использования файлов, и обнаружите только два режима для работы в сети: bridged и host-only. Мост работает удовлетворительно в большинстве ситуаций и обеспечивает полный доступ к сети без дополнительного конфигурирования.&lt;br /&gt;
&lt;br /&gt;
Мастер установки новой операционной системы представлен еще одним на удивление знакомым окном, практически идентичным VMware. Вы выбираете систему и расположение образа диска, но дополнительных опций намного меньше, нежели в VMware. Еще одним важным отличием является Parallel Workstation 2.0 является то, что жесткий диск и оптический привод можно эмулировать только в режиме IDE.&lt;br /&gt;
&lt;br /&gt;
Как только конфигурация будет создана, начнется установка операционной системы на виртуальной машине. При старте нельзя изменить настройки BIOS — вы видите только информацию о загрузке. Настройки, сосредоточенные обычно в BIOS, такие как порядок загрузки или MAC-адрес сетевой карты, можно изменить при помощи редактора конфигурации основного приложения.&lt;br /&gt;
&lt;br /&gt;
=== На периферии ===&lt;br /&gt;
[[Изображение:LXF74-75_Parallel_Workstation-1.png|thumb|right|Каждую машину можно загрузить отдельно, но не для одновременной работы]]&lt;br /&gt;
Мы без каких-либо проблем установили несколько дистрибутивов Linux в Parallel Workstation, включая последний SUSE 10. Видеокарта и сетевая карта эмулируются хорошо, но, посмотрев список подключенных устройств используя lspci, мы обнаружили весьма ограниченный список периферии. Нет USB- или SCSI-устройств, а графические возможности обеспечиваются стандартным VESA-драйвером. Эта ситуация разительным образом отличается от VMware, в которой реализована отличная совместимость со многими периферийными USB- и SCSI-устройствами.&lt;br /&gt;
&lt;br /&gt;
Вторым по важности фактором после совместимости является скорость. Для продукта, появившегося как гром среди ясного неба, быстродействие и эффективность виртуальной машины впечатляет. Система работает не так быстро, как в VMware, но только потому, что Parallel не использует каких-либо специальных драйверов для гостевой ОС. В работе мышь и интерфейс пользователя вели себя почти также быстро, как и на реальной машине.&lt;br /&gt;
&lt;br /&gt;
Что касается возможностей, Parallel Workstation не может конкурировать с VMware. Но VMware Workstation имеет один важный недостаток — цену. Для использования на обычном компьютере, когда вам необходимо протестировать ОС или выполнить какое-либо Windows-приложение, VMware слишком дорог.&lt;br /&gt;
&lt;br /&gt;
Parallel Workstation будет более уместна там, где ее продуманная цена позволит вполне успешно конкурировать со сложным и дорогим соперником.&lt;br /&gt;
&lt;br /&gt;
=== Вердикт Linux Format ===&lt;br /&gt;
* Возможности — 6/10&lt;br /&gt;
* Функционирование — 7/10&lt;br /&gt;
* Простота использования — 6/10&lt;br /&gt;
* Документация — 7/10&lt;br /&gt;
Новичок менее функционален и быстр, чем признанный лидер, но это отличный выбор за такие деньги!&lt;br /&gt;
* '''Рейтинг — 7/10'''&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF74-75:FireFox_1.5</id>
		<title>LXF74-75:FireFox 1.5</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF74-75:FireFox_1.5"/>
				<updated>2008-05-15T14:38:04Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: «LXF74-75:FireFox 1.5» переименована в «LXF74-75:Firefox 1.5»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[LXF74-75:Firefox 1.5]]&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF74-75:Firefox_1.5</id>
		<title>LXF74-75:Firefox 1.5</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF74-75:Firefox_1.5"/>
				<updated>2008-05-15T14:38:04Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: «LXF74-75:FireFox 1.5» переименована в «LXF74-75:Firefox 1.5»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__''Долой всплывающие окна! Команда разработчиков самого быстроразвивающегося браузера в мире вернулась. Репортаж ведет Алекс Кокс (Alex Cox).''&lt;br /&gt;
&lt;br /&gt;
{{Врезка|left|Ширина=200px|&lt;br /&gt;
Заголовок = Самое главное |&lt;br /&gt;
Содержание = Полнофункциональный браузер, быстро отвоевывающий позиции у конкурентов.&lt;br /&gt;
Альтернативы: Opera, Konqueror.&lt;br /&gt;
* '''РАЗРАБОТЧИК''' Mozilla Foundation&lt;br /&gt;
* '''WEB''' [http://www.mozilla.org www.mozilla.org]&lt;br /&gt;
* '''ЦЕНА''' Бесплатно, по лицензии Mozilla Public License}}&lt;br /&gt;
&lt;br /&gt;
Известно, что идеального браузера не существует, но версия 1.5 дала шанс Mozilla Foundation сосредоточиться на основных проблемах, обнаруженных пользователями версий 1.0.x. Одним из наиболее важных улучшений является процесс обновления. Ранее Firefox вообще не поддерживал заплатки (patches) — для того, чтобы воспользоваться обновлениями безопасности и исправлениями ошибок (bugfix), приходилось загружать и устанавливать новую версию программы целиком. Это не облегчало нагрузку сервера mozilla.org и его зеркал, зато положительно сказывалась на впечатляющих графиках количества закачек Firefox.&lt;br /&gt;
&lt;br /&gt;
Новый метод более практичен. Предупреждения об обновлениях, так же как и раньше, появляются на панели инструментов браузера в виде маленькой красной иконки. Эта иконка не всегда заметна, и мы полагаем, что Mozilla Foundation следует найти другой метод, но пока используется этот. Большие изменения произошли с размерами загрузок. Обновления стали значительно меньше по объему, нежели ранее (около полумегабайта) и загружаются непосредственно браузером. Один перезапуск приложения — и вы вновь можете работать.&lt;br /&gt;
&lt;br /&gt;
Эта возможность была впервые протестирована в промежутке между первыми двумя бета-версиями Firefox 1.5, и теперь, кажется, работает безупречно. При желании вы можете даже заставить свою копию Firefox загружать самые последние, пышущие жаром, «ночные» сборки (nightly builds).&lt;br /&gt;
&lt;br /&gt;
Однако, несмотря на то, что система обновления теперь более удобна, она все еще не избавлена от основной проблемы: в процессе бета-тестирования (как это было с версиями 1.0.x), выпуск очередных обновлений занимал несколько дней, прежде чем они автоматически отправлялись пользователям. Вот на чем следует сосредоточиться. Хорошо бы Mozilla Foundation избрать тактику, при которой продвинутые пользователи получали и опробовали новые версии первыми. Пока же мы видим только размышления. Такая тактика означает только одно: бреши в безопасности будут оставаться открытыми достаточно долго.&lt;br /&gt;
&lt;br /&gt;
=== Полный вперед ===&lt;br /&gt;
[[Изображение:LXF74-75-firefox-1.jpg|thumb|Постоянные посетители подпольных сайтов будут рады увидеть новые настройки приватности web-серфинга, представленные в этой версии.]]&lt;br /&gt;
Внешний вид и ощущения от работы браузера не очень отличаются от предыдущих версий, которые, в общем-то, и сами были не плохи. Где-то появилось дополнительное меню, где-то видны небольшие изменения, но в целом Firefox остался предельно простым. И только работа в сети показывает, где же находятся реальные изменения. Используется новая система кэширования страниц bfCacheing (Back-Forward cacheing — «кэширование назад-вперед») и она действительно хорошо работает: возвращение назад, а впоследствии и переход вперед, теперь происходят практически мгновенно.&lt;br /&gt;
&lt;br /&gt;
Это не слишком снизило требования к RAM — браузер по-прежнему жаден до оперативной памяти. В среднем Firefox потребляет 84 мегабайта, он более «тяжел» по сравнению с Opera или Galeon. Konqueror близок к нему по размеру, так что ни один из них не подходит для компьютеров, оснащенных 256 Мб оперативной памяти или ниже. (На самом деле, конечно, подходят оба, просто в этом случае нет того удовольствия от работы с браузером — прим.ред.)&lt;br /&gt;
&lt;br /&gt;
Значительно улучшенная система вкладок уменьшает время перехода от страницы к странице. Два ключевых обновления — это предпросмотр изображений в виде маленьких иконок при открытии картинок в отдельных вкладках и использование механизма Drag’n’Drop для упорядочивания вкладок, то есть теперь вкладки могут быть переупорядочены как удобно пользователю. Это, конечно, очевидная вещь, но ее наличие заметно меняет стиль использования Firefox.&lt;br /&gt;
&lt;br /&gt;
Улучшена также блокировка всплывающих окон (pop-ups). Когда Firefox достиг популярности, встроенный блокиратор был одним из наилучших доводов в его пользу, так как он использовал неизвестную технологию, и ее малоизвестность позволила проскользнуть мимо «радаров» большинства навязчивых web-рекламодателей. Прошло время, и многие из них нашли способы создания всплывающих окон, совместимых с Firefox, по крайней мере, с версией 1.0.x. Тесты работы версии 1.5 при посещении тех сайтов, которые ранее атаковали нас надоедливой рекламой, показали, что ни одно всплывающее окно не смогло пробиться сквозь Firefox 1.5.&lt;br /&gt;
&lt;br /&gt;
=== Будьте добры соответствовать! ===&lt;br /&gt;
Соответствие стандартам долго было одной из сильных сторон Firefox, поэтому мы решили устроить движку версии 1.5 хорошую проверку. Firefox использует движок Gecko для обеспечения корректного отображения HTML и других элементов, заставляющих web-страницы выглядеть соответственно форматированию. Наилучшим тестом совместимости для движков является тест Acid2 ([http://www.webstandards.org/files/acid2/test.html www.webstandards.org/files/acid2/test.html]), предложенный Web Standards Project. Это одна web-страница, на которой используется множество сложных и малоиспользуемых возможностей CSS2 (именно поэтому называть Acid2 «лучшим тестом» несколько некорректно, — прим.ред.), таких как прозрачные PNG-изображения.&lt;br /&gt;
[[Изображение:LXF74-75-acid-1.jpg|200px]]&lt;br /&gt;
{{врезка|both|Заголовок=Прохождение теста acid2 браузерами|&lt;br /&gt;
Содержание=Acid2 – это самый известный тест способности браузеров обращаться со сложными CSS элементами и плохо написанным кодом. &lt;br /&gt;
Чем ближе изображение в браузере к оригиналу (показанному справа), тем лучше. Мы обрезали страницу, чтобы показать только &lt;br /&gt;
рисунок. Как мы можем видеть, Firefox 1.5 справился с задачей лучше некоторых, хотя и он не идеален. &lt;br /&gt;
* Стоит отметить, что самая новая версия Konqueror (см. материал «Технологии Linux-2006») прошла-таки этот суровый тест.&lt;br /&gt;
{{{!}}&lt;br /&gt;
{{!}}[[Изображение:LXF74-75-acid-1.jpg|200px]]&amp;lt;br /&amp;gt;Так должен выглядеть тестовый рисунок Acid2&lt;br /&gt;
{{!}}[[Изображение:LXF74-75-acid-2.jpg|200px]]&amp;lt;br /&amp;gt;Firefox 1.5&lt;br /&gt;
{{!}}[[Изображение:LXF74-75-acid-3.jpg|200px]]&amp;lt;br /&amp;gt;Firefox 1.0.7&lt;br /&gt;
{{!}}[[Изображение:LXF74-75-acid-4.jpg|200px]]&amp;lt;br /&amp;gt;Konqueror 3.4&lt;br /&gt;
{{!}}[[Изображение:LXF74-75-acid-5.jpg|200px]]&amp;lt;br /&amp;gt;Opera 8&lt;br /&gt;
{{!}}[[Изображение:LXF74-75-acid-6.jpg|200px]]&amp;lt;br /&amp;gt;Internet Explorer 6&lt;br /&gt;
{{!}}}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
CSS быстро меняется: новые возможности добавляются постоянно, и полный стандарт HTML может быть изменен по желанию инициативных разработчиков. Браузеры должны уметь справляться с этим, но редко делают это хорошо. Firefox, как и многие современные браузеры, не справился с тестом. Но он отобразил рисунок с меньшими ошибками, чем остальные браузеры, не прошедшие тест, что можно увидеть во врезке, расположенной выше. Из открытых браузеров похвастаться прохождением Acid2 может лишь Konqueror, начиная с версии 3.5.&lt;br /&gt;
&lt;br /&gt;
После сравнения различных браузеров, мы использовали тест Acid2 для выяснения прогресса движка Gecko по сравнению со временами версии Firefox 1.0.x. Ответ немного разочаровал — прогресса почти нет. Действительно, если рассматривать самые последние версии Acid2, то нет никакого различия между текущей и предыдущей. Это означает, что только сравнив Firefox с браузерами, использующими более старую версию Gecko (например, самим Mozilla), вы сможете увидеть, насколько далеко продвинулся движок.&lt;br /&gt;
&lt;br /&gt;
Хотя мы и надеялись на безупречное выполнение теста, результаты Acid2 для Firefox не оказались сюрпризом. Известно, что в настоящее время внимание уделяется скорее не непосредственной совместимости с CSS2, а внедрению новых возможностей и новых стандартов (Ожидается, что Firefox будет проходить Acid2 в версии 2.0, — прим.ред.). Возможно, наиболее интересные и, для некоторых, спорные добавления — это CSS-колонки, часто запрашиваемая функция, поддерживаемая в настоящий момент лишь Gecko. Изменяемые колонки теперь могут быть созданы при помощи нового элемента -mozcolumn-count, а элементы -mozcolumn-width и -moz-columnheight используются для разделов фиксированных размеров.&lt;br /&gt;
&lt;br /&gt;
Эти новые элементы могут показаться не важными, но они могут означать, что больше сайтов будут использовать горизонтальный скроллинг вместо вертикального, а это было бы фундаментальным изменением в web-дизайне.&lt;br /&gt;
&lt;br /&gt;
=== Под капотом ===&lt;br /&gt;
[[Изображение:LXF74-75-firefox-2.jpg|thumb|Построение графиков в реальном времени, прозрачные перемещаемые объекты и клоны Тетриса это только некоторые возможности, доступные благодаря поддержке SVG в Firefox 1.5.]]&lt;br /&gt;
Встроенная поддержка SVG (Scalable Vector Graphics) долгое время развивалась отдельно под пристальным отеческим взглядом проекта Mozilla SVG Project, и до настоящего момента была доступна только в специальной версии Mozilla. Не законченная версия SVG включена по умолчанию в Firefox 1.5, таким образом, web-разработчики могут опробовать векторную графику на новых сайтах. Демонстрационные примеры, которые мы видели, включают в себя набор впечатляющих интерактивных демонстраций, связывающих SVG и XML файлы (см. слева) и вполне работоспособную версию Тетриса, которая размещена в одном SVG файле. Поддержка SVG еще не так хороша, как в SVG Viewer от Adobe, и есть некоторые проблемы с масштабированием изображений, но приятно видеть, что за нее все-таки взялись.&lt;br /&gt;
&lt;br /&gt;
Изящные графические дополнения на этом не заканчиваются. Новый элемент Canvas дает разработчикам возможность использовать программируемые библиотеки 2D-графики, способные формировать изображение (для игр, диаграмм и т. п.) «на лету». Реализация этого элемента в Firefox позаимствована из разработки компании Apple, созданной для использования в собственных виджетах Dashboard. С помощью Canvas Разработчики расширений могут даже отображать всю страницу как картинку, что может стать базой для замечательных дополнений в будущем. Представьте, например, графическая история перемещений, возможно даже с полноразмерными снимками экрана целых страниц. В этом есть огромный потенциал для нововведений, и ходят слухи, что в Firefox 2.0 будет поддержка 3D.&lt;br /&gt;
&lt;br /&gt;
{{Врезка|right|Ширина=200px|&lt;br /&gt;
Заголовок = Майк считает…|&lt;br /&gt;
Содержание = «Теперь, когда Opera можно скачать бесплатно, разработчикам Mozilla необходимо работать особенно упорно, чтобы сохранить привязанность пользователей к «огнелису». И, не считая требования FF к оперативной памяти, они делают все необходимое.»}}&lt;br /&gt;
&lt;br /&gt;
Несмотря на то, что новая версия Firefox является потомком версии 1.0, усовершенствование работы с вкладками и кэшированием страниц позволяют рассматривать Firefox 1.5 как значительный рывок вперед. Изменений недостаточно, чтобы поднимать шум, несмотря на то, что разработчики и представили несколько новых стандартов и кое-какие «штучки» для коллег — сам браузер остался практически неизменным. Из опубликованных Mozilla пресс-релизов становится ясно, что большие изменения появятся в версии 2.0, где-то в 2006 году.&lt;br /&gt;
&lt;br /&gt;
Следует отметить, что Firefox остается несовместимым со многими сайтами, преимущественно с чересчур инновационными, такими как сайты банков, и хотя поддержка обязательно будет реализована, вряд ли это произойдет скоро. Тем не менее, в целом Firefox 1.5 достаточно самостоятелен, и его простой интерфейс, строгое соответствие стандартам и насыщенность модными функциями означают, что мы просто не можем обойтись без него.&lt;br /&gt;
&lt;br /&gt;
=== Вердикт Linux Format ===&lt;br /&gt;
* Возможности — 8/10&lt;br /&gt;
* Функционирование — 8/10&lt;br /&gt;
* Простота использования — 7/10&lt;br /&gt;
* Документация — 6/10&lt;br /&gt;
Функциональный и аккуратно спроектированный, Firefox 1.5 действительно способен расширить границы привычного в Сети.&lt;br /&gt;
* '''Рейтинг — 8/10'''&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF74-75:Firefox_1.5</id>
		<title>LXF74-75:Firefox 1.5</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF74-75:Firefox_1.5"/>
				<updated>2008-05-15T14:13:10Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: Новая: __NOTOC__''Долой всплывающие окна! Команда разработчиков самого быстроразвивающегося браузера в мире вер...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__''Долой всплывающие окна! Команда разработчиков самого быстроразвивающегося браузера в мире вернулась. Репортаж ведет Алекс Кокс (Alex Cox).''&lt;br /&gt;
&lt;br /&gt;
{{Врезка|left|Ширина=200px|&lt;br /&gt;
Заголовок = Самое главное |&lt;br /&gt;
Содержание = Полнофункциональный браузер, быстро отвоевывающий позиции у конкурентов.&lt;br /&gt;
Альтернативы: Opera, Konqueror.&lt;br /&gt;
* '''РАЗРАБОТЧИК''' Mozilla Foundation&lt;br /&gt;
* '''WEB''' [http://www.mozilla.org www.mozilla.org]&lt;br /&gt;
* '''ЦЕНА''' Бесплатно, по лицензии Mozilla Public License}}&lt;br /&gt;
&lt;br /&gt;
Известно, что идеального браузера не существует, но версия 1.5 дала шанс Mozilla Foundation сосредоточиться на основных проблемах, обнаруженных пользователями версий 1.0.x. Одним из наиболее важных улучшений является процесс обновления. Ранее Firefox вообще не поддерживал заплатки (patches) — для того, чтобы воспользоваться обновлениями безопасности и исправлениями ошибок (bugfix), приходилось загружать и устанавливать новую версию программы целиком. Это не облегчало нагрузку сервера mozilla.org и его зеркал, зато положительно сказывалась на впечатляющих графиках количества закачек Firefox.&lt;br /&gt;
&lt;br /&gt;
Новый метод более практичен. Предупреждения об обновлениях, так же как и раньше, появляются на панели инструментов браузера в виде маленькой красной иконки. Эта иконка не всегда заметна, и мы полагаем, что Mozilla Foundation следует найти другой метод, но пока используется этот. Большие изменения произошли с размерами загрузок. Обновления стали значительно меньше по объему, нежели ранее (около полумегабайта) и загружаются непосредственно браузером. Один перезапуск приложения — и вы вновь можете работать.&lt;br /&gt;
&lt;br /&gt;
Эта возможность была впервые протестирована в промежутке между первыми двумя бета-версиями Firefox 1.5, и теперь, кажется, работает безупречно. При желании вы можете даже заставить свою копию Firefox загружать самые последние, пышущие жаром, «ночные» сборки (nightly builds).&lt;br /&gt;
&lt;br /&gt;
Однако, несмотря на то, что система обновления теперь более удобна, она все еще не избавлена от основной проблемы: в процессе бета-тестирования (как это было с версиями 1.0.x), выпуск очередных обновлений занимал несколько дней, прежде чем они автоматически отправлялись пользователям. Вот на чем следует сосредоточиться. Хорошо бы Mozilla Foundation избрать тактику, при которой продвинутые пользователи получали и опробовали новые версии первыми. Пока же мы видим только размышления. Такая тактика означает только одно: бреши в безопасности будут оставаться открытыми достаточно долго.&lt;br /&gt;
&lt;br /&gt;
=== Полный вперед ===&lt;br /&gt;
[[Изображение:LXF74-75-firefox-1.jpg|thumb|Постоянные посетители подпольных сайтов будут рады увидеть новые настройки приватности web-серфинга, представленные в этой версии.]]&lt;br /&gt;
Внешний вид и ощущения от работы браузера не очень отличаются от предыдущих версий, которые, в общем-то, и сами были не плохи. Где-то появилось дополнительное меню, где-то видны небольшие изменения, но в целом Firefox остался предельно простым. И только работа в сети показывает, где же находятся реальные изменения. Используется новая система кэширования страниц bfCacheing (Back-Forward cacheing — «кэширование назад-вперед») и она действительно хорошо работает: возвращение назад, а впоследствии и переход вперед, теперь происходят практически мгновенно.&lt;br /&gt;
&lt;br /&gt;
Это не слишком снизило требования к RAM — браузер по-прежнему жаден до оперативной памяти. В среднем Firefox потребляет 84 мегабайта, он более «тяжел» по сравнению с Opera или Galeon. Konqueror близок к нему по размеру, так что ни один из них не подходит для компьютеров, оснащенных 256 Мб оперативной памяти или ниже. (На самом деле, конечно, подходят оба, просто в этом случае нет того удовольствия от работы с браузером — прим.ред.)&lt;br /&gt;
&lt;br /&gt;
Значительно улучшенная система вкладок уменьшает время перехода от страницы к странице. Два ключевых обновления — это предпросмотр изображений в виде маленьких иконок при открытии картинок в отдельных вкладках и использование механизма Drag’n’Drop для упорядочивания вкладок, то есть теперь вкладки могут быть переупорядочены как удобно пользователю. Это, конечно, очевидная вещь, но ее наличие заметно меняет стиль использования Firefox.&lt;br /&gt;
&lt;br /&gt;
Улучшена также блокировка всплывающих окон (pop-ups). Когда Firefox достиг популярности, встроенный блокиратор был одним из наилучших доводов в его пользу, так как он использовал неизвестную технологию, и ее малоизвестность позволила проскользнуть мимо «радаров» большинства навязчивых web-рекламодателей. Прошло время, и многие из них нашли способы создания всплывающих окон, совместимых с Firefox, по крайней мере, с версией 1.0.x. Тесты работы версии 1.5 при посещении тех сайтов, которые ранее атаковали нас надоедливой рекламой, показали, что ни одно всплывающее окно не смогло пробиться сквозь Firefox 1.5.&lt;br /&gt;
&lt;br /&gt;
=== Будьте добры соответствовать! ===&lt;br /&gt;
Соответствие стандартам долго было одной из сильных сторон Firefox, поэтому мы решили устроить движку версии 1.5 хорошую проверку. Firefox использует движок Gecko для обеспечения корректного отображения HTML и других элементов, заставляющих web-страницы выглядеть соответственно форматированию. Наилучшим тестом совместимости для движков является тест Acid2 ([http://www.webstandards.org/files/acid2/test.html www.webstandards.org/files/acid2/test.html]), предложенный Web Standards Project. Это одна web-страница, на которой используется множество сложных и малоиспользуемых возможностей CSS2 (именно поэтому называть Acid2 «лучшим тестом» несколько некорректно, — прим.ред.), таких как прозрачные PNG-изображения.&lt;br /&gt;
[[Изображение:LXF74-75-acid-1.jpg|200px]]&lt;br /&gt;
{{врезка|both|Заголовок=Прохождение теста acid2 браузерами|&lt;br /&gt;
Содержание=Acid2 – это самый известный тест способности браузеров обращаться со сложными CSS элементами и плохо написанным кодом. &lt;br /&gt;
Чем ближе изображение в браузере к оригиналу (показанному справа), тем лучше. Мы обрезали страницу, чтобы показать только &lt;br /&gt;
рисунок. Как мы можем видеть, Firefox 1.5 справился с задачей лучше некоторых, хотя и он не идеален. &lt;br /&gt;
* Стоит отметить, что самая новая версия Konqueror (см. материал «Технологии Linux-2006») прошла-таки этот суровый тест.&lt;br /&gt;
{{{!}}&lt;br /&gt;
{{!}}[[Изображение:LXF74-75-acid-1.jpg|200px]]&amp;lt;br /&amp;gt;Так должен выглядеть тестовый рисунок Acid2&lt;br /&gt;
{{!}}[[Изображение:LXF74-75-acid-2.jpg|200px]]&amp;lt;br /&amp;gt;Firefox 1.5&lt;br /&gt;
{{!}}[[Изображение:LXF74-75-acid-3.jpg|200px]]&amp;lt;br /&amp;gt;Firefox 1.0.7&lt;br /&gt;
{{!}}[[Изображение:LXF74-75-acid-4.jpg|200px]]&amp;lt;br /&amp;gt;Konqueror 3.4&lt;br /&gt;
{{!}}[[Изображение:LXF74-75-acid-5.jpg|200px]]&amp;lt;br /&amp;gt;Opera 8&lt;br /&gt;
{{!}}[[Изображение:LXF74-75-acid-6.jpg|200px]]&amp;lt;br /&amp;gt;Internet Explorer 6&lt;br /&gt;
{{!}}}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
CSS быстро меняется: новые возможности добавляются постоянно, и полный стандарт HTML может быть изменен по желанию инициативных разработчиков. Браузеры должны уметь справляться с этим, но редко делают это хорошо. Firefox, как и многие современные браузеры, не справился с тестом. Но он отобразил рисунок с меньшими ошибками, чем остальные браузеры, не прошедшие тест, что можно увидеть во врезке, расположенной выше. Из открытых браузеров похвастаться прохождением Acid2 может лишь Konqueror, начиная с версии 3.5.&lt;br /&gt;
&lt;br /&gt;
После сравнения различных браузеров, мы использовали тест Acid2 для выяснения прогресса движка Gecko по сравнению со временами версии Firefox 1.0.x. Ответ немного разочаровал — прогресса почти нет. Действительно, если рассматривать самые последние версии Acid2, то нет никакого различия между текущей и предыдущей. Это означает, что только сравнив Firefox с браузерами, использующими более старую версию Gecko (например, самим Mozilla), вы сможете увидеть, насколько далеко продвинулся движок.&lt;br /&gt;
&lt;br /&gt;
Хотя мы и надеялись на безупречное выполнение теста, результаты Acid2 для Firefox не оказались сюрпризом. Известно, что в настоящее время внимание уделяется скорее не непосредственной совместимости с CSS2, а внедрению новых возможностей и новых стандартов (Ожидается, что Firefox будет проходить Acid2 в версии 2.0, — прим.ред.). Возможно, наиболее интересные и, для некоторых, спорные добавления — это CSS-колонки, часто запрашиваемая функция, поддерживаемая в настоящий момент лишь Gecko. Изменяемые колонки теперь могут быть созданы при помощи нового элемента -mozcolumn-count, а элементы -mozcolumn-width и -moz-columnheight используются для разделов фиксированных размеров.&lt;br /&gt;
&lt;br /&gt;
Эти новые элементы могут показаться не важными, но они могут означать, что больше сайтов будут использовать горизонтальный скроллинг вместо вертикального, а это было бы фундаментальным изменением в web-дизайне.&lt;br /&gt;
&lt;br /&gt;
=== Под капотом ===&lt;br /&gt;
[[Изображение:LXF74-75-firefox-2.jpg|thumb|Построение графиков в реальном времени, прозрачные перемещаемые объекты и клоны Тетриса это только некоторые возможности, доступные благодаря поддержке SVG в Firefox 1.5.]]&lt;br /&gt;
Встроенная поддержка SVG (Scalable Vector Graphics) долгое время развивалась отдельно под пристальным отеческим взглядом проекта Mozilla SVG Project, и до настоящего момента была доступна только в специальной версии Mozilla. Не законченная версия SVG включена по умолчанию в Firefox 1.5, таким образом, web-разработчики могут опробовать векторную графику на новых сайтах. Демонстрационные примеры, которые мы видели, включают в себя набор впечатляющих интерактивных демонстраций, связывающих SVG и XML файлы (см. слева) и вполне работоспособную версию Тетриса, которая размещена в одном SVG файле. Поддержка SVG еще не так хороша, как в SVG Viewer от Adobe, и есть некоторые проблемы с масштабированием изображений, но приятно видеть, что за нее все-таки взялись.&lt;br /&gt;
&lt;br /&gt;
Изящные графические дополнения на этом не заканчиваются. Новый элемент Canvas дает разработчикам возможность использовать программируемые библиотеки 2D-графики, способные формировать изображение (для игр, диаграмм и т. п.) «на лету». Реализация этого элемента в Firefox позаимствована из разработки компании Apple, созданной для использования в собственных виджетах Dashboard. С помощью Canvas Разработчики расширений могут даже отображать всю страницу как картинку, что может стать базой для замечательных дополнений в будущем. Представьте, например, графическая история перемещений, возможно даже с полноразмерными снимками экрана целых страниц. В этом есть огромный потенциал для нововведений, и ходят слухи, что в Firefox 2.0 будет поддержка 3D.&lt;br /&gt;
&lt;br /&gt;
{{Врезка|right|Ширина=200px|&lt;br /&gt;
Заголовок = Майк считает…|&lt;br /&gt;
Содержание = «Теперь, когда Opera можно скачать бесплатно, разработчикам Mozilla необходимо работать особенно упорно, чтобы сохранить привязанность пользователей к «огнелису». И, не считая требования FF к оперативной памяти, они делают все необходимое.»}}&lt;br /&gt;
&lt;br /&gt;
Несмотря на то, что новая версия Firefox является потомком версии 1.0, усовершенствование работы с вкладками и кэшированием страниц позволяют рассматривать Firefox 1.5 как значительный рывок вперед. Изменений недостаточно, чтобы поднимать шум, несмотря на то, что разработчики и представили несколько новых стандартов и кое-какие «штучки» для коллег — сам браузер остался практически неизменным. Из опубликованных Mozilla пресс-релизов становится ясно, что большие изменения появятся в версии 2.0, где-то в 2006 году.&lt;br /&gt;
&lt;br /&gt;
Следует отметить, что Firefox остается несовместимым со многими сайтами, преимущественно с чересчур инновационными, такими как сайты банков, и хотя поддержка обязательно будет реализована, вряд ли это произойдет скоро. Тем не менее, в целом Firefox 1.5 достаточно самостоятелен, и его простой интерфейс, строгое соответствие стандартам и насыщенность модными функциями означают, что мы просто не можем обойтись без него.&lt;br /&gt;
&lt;br /&gt;
=== Вердикт Linux Format ===&lt;br /&gt;
* Возможности — 8/10&lt;br /&gt;
* Функционирование — 8/10&lt;br /&gt;
* Простота использования — 7/10&lt;br /&gt;
* Документация — 6/10&lt;br /&gt;
Функциональный и аккуратно спроектированный, Firefox 1.5 действительно способен расширить границы привычного в Сети.&lt;br /&gt;
* '''Рейтинг — 8/10'''&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF74-75</id>
		<title>LXF74-75</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF74-75"/>
				<updated>2008-05-15T13:37:35Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: ++&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Изображение:Lxf74-75.jpg|right|Обложка журнала]]&lt;br /&gt;
&lt;br /&gt;
== LinuxFormat 74-75, Январь 2006 ==&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
=== Обзоры ===&lt;br /&gt;
* [[LXF74-75:FireFox 1.5|LXF74-75:FireFox 1.5]]&lt;br /&gt;
Mozilla поработала на славу!&lt;br /&gt;
&lt;br /&gt;
* [[LXF74-75:Parallel Workstation 2.0|LXF74-75:Parallel Workstation 2.0]]&lt;br /&gt;
Почти что VMWare или все-таки нет?!&lt;br /&gt;
&lt;br /&gt;
* [[LXF74-75:VMware Workstation 5.5|LXF74-75:VMware Workstation 5.5]]&lt;br /&gt;
Теперь – с бесплатным «пробником»&lt;br /&gt;
&lt;br /&gt;
* [[LXF74-75:Ubuntu 5.10|LXF74-75:Ubuntu 5.10]]&lt;br /&gt;
Это что за зверушка?&lt;br /&gt;
&lt;br /&gt;
* [[LXF74-75:Slackware 10.2|LXF74-75:Slackware 10.2]]&lt;br /&gt;
Этот Linux использовал еще ваш папа&lt;br /&gt;
&lt;br /&gt;
* [[LXF74-75:Cairo|LXF74-75:Cairo]]&lt;br /&gt;
Графика для фараонов&lt;br /&gt;
&lt;br /&gt;
* [[LXF74-75:Maya 7.0|LXF74-75:Maya 7.0]]&lt;br /&gt;
И что, она лучше Blender?&lt;br /&gt;
&lt;br /&gt;
* [[LXF74-75:ThinkFree Office 3|LXF74-75:ThinkFree Office 3]]&lt;br /&gt;
Думает быстрее, чем OOo.&lt;br /&gt;
&lt;br /&gt;
* Жизнь на рабочем столе&lt;br /&gt;
SuperKaramba, Gdesklets побери!&lt;br /&gt;
&lt;br /&gt;
=== Сравнение ===&lt;br /&gt;
* [[LXF74-75:Сравнение|Остановим вирусы!]]&lt;br /&gt;
&lt;br /&gt;
=== Что за штука…? ===&lt;br /&gt;
* [[LXF74-75:Что за штука...|Что такое... HIBERNATE?]]&lt;br /&gt;
Холодно, темно – пора спать!&lt;br /&gt;
&lt;br /&gt;
=== Специальный репортаж ===&lt;br /&gt;
* [[LXF74-75:Дистрибутив своими руками|LXF74-75:Дистрибутив своими руками]]&lt;br /&gt;
Возьмите полкило ядра и 100 грамм X.Org    &lt;br /&gt;
* [[LXF74-75:LXF READER AWARDS|LXF74-75:LXF READER AWARDS]]&lt;br /&gt;
Голосуйте или они никому не достанутся!&lt;br /&gt;
* [[LXF74-75:Технологии Linux-2006|LXF74-75:Технологии Linux-2006]]&lt;br /&gt;
Мы больше не можем скрывать это!&lt;br /&gt;
* [[LXF74-75:Linux обучающий|LXF74-75:Linux обучающий]]&lt;br /&gt;
Учитель! Прочти меня! &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Интервью ===&lt;br /&gt;
* [[LXF74-75:Эндрю Мортон|LXF74-75:Эндрю Мортон]]&lt;br /&gt;
Хранитель ядра в гостях у LinuxFormat&lt;br /&gt;
&lt;br /&gt;
* [[LXF74-75:В ожидании Ларри|LXF74-75:В ожидании Ларри]]&lt;br /&gt;
Лингвист-программист Ларри Уолл&lt;br /&gt;
&lt;br /&gt;
* [[LXF74-75:Первые шаги|Первые шаги в системе]]&lt;br /&gt;
Не теряйте важные файлы&lt;br /&gt;
&lt;br /&gt;
* [[LXF74-75:Gambas|Gambas напоследок]]&lt;br /&gt;
Отделяем креветок от панцирей&lt;br /&gt;
&lt;br /&gt;
* [[LXF74-75:Inkscape|Inkscape: Повелитель градиентов]]&lt;br /&gt;
Inkscape по-русски!&lt;br /&gt;
&lt;br /&gt;
* [[LXF74-75:PHP|PHP в 2 частях]]&lt;br /&gt;
# Колдуем над Google API&lt;br /&gt;
# Sprechen sie multibyte?&lt;br /&gt;
&lt;br /&gt;
* [[LXF74-75:Рython|Уроки Рython]]&lt;br /&gt;
Как амебе превратиться в удава?&lt;br /&gt;
&lt;br /&gt;
=== Ответы ===&lt;br /&gt;
* [[LXF74-75:Ответы|Ответы]]&lt;br /&gt;
Поможем пользователям Mandriva&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF90:Mono</id>
		<title>LXF90:Mono</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF90:Mono"/>
				<updated>2008-04-28T16:38:49Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: &amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/Mono}}&lt;br /&gt;
&lt;br /&gt;
== Mono: Связь с библиотеками ==&lt;br /&gt;
''Создать супер-поиск по файловой системе меньше чем за час? Наш штатный вождь обезьян '''Пол Хадсон''' делает невозможное не только возможным, но и простым...''&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
Ваша миссия, если вы за нее беретесь, состоит в написании консольной программы, которая индексирует файловую систему пользователя в фоновом режиме, сканирует почту, RSS-ленты, историю браузера и содержимое файлов, а затем позволяет производить во всем этом молниеносный поиск. Уловили? ОК, увидимся через час – удачи вам!&lt;br /&gt;
&lt;br /&gt;
Да, мы собрались создать шедевр менее чем за 60 минут; по-вашему, без чуда не обойтись? Но прикиньте: какое небезызвестное Linux-приложение умеет осуществлять поиск по всем источникам данных? Думайте, думайте! Ясное дело, ''Beagle''. А на какой платформе построен ''Beagle''? Mono! А о чем этот учебник? О Mono! Итак, мы позаимствуем возможности у проекта ''Beagle'' – точнее, у его библиотек.&lt;br /&gt;
&lt;br /&gt;
Что хорошо в .NET – это шанс встать на плечи гигантам, использовав их библиотеки. Конечно, С тоже такое допускает – например, программа ''Ark RPG'' имеет библиотеку ''libarkrpg0c2a'', позволяющую другим программам на С вызывать ее функции, а не реализовывать их заново. Но такой подход не лишен проблем: например, ''Gstreamer'' разделен на несколько библиотек, и у каждой собственный номер версии. Рядовой пример – ''libgstdataprotocol-0.10.so.0.8.1''. C не воспринимает новые версии библиотек без обновления самой программы, поэтому номера версий так важны – приложению подавай непременно ''libgstdataprotocol-0.10'', а не 0.9 или 0.11.&lt;br /&gt;
&lt;br /&gt;
Mono позволяет программистам просто потребовать «давай Beagle» и получить любую доступную версию. Такой подход не всегда срабатывает, особенно с некоторыми новыми Linux-приложениями, не достигшими версии 1.0. Причина, по которой у них такие маленькие номера версий (Beagle находится на стадии 0.2.14) – недостаточно стабильный программный интерфейс (application programming interface, API). API – это термин для обозначения имен функций, типов параметров и возвращаемых значений для данной библиотеки. Стабильность API означает, что если функция {{oncolor||green|DoFoo()}} в версии 1.0 принимает целый аргумент и возвращает строку, то любая использующая ее программа будет работать и с версией библиотеки 1.01, потому что функция не меняется.&lt;br /&gt;
&lt;br /&gt;
Самое главное в API – это 'I'-часть, собственно интерфейс (имя, параметры, возвращаемое значение): если он фиксирован, то неважно, как библиотека выполняет свою задачу, и пусть себе её версии меняются как угодно.&lt;br /&gt;
&lt;br /&gt;
Резюмирую:&lt;br /&gt;
* Мы используем Mono, и Beagle тоже – значит, нам доступны преимущества Beagle.&lt;br /&gt;
* Beagle имеет API, предоставляющий в наше распоряжение его функциональность, но он не стабилен и в будущем может измениться (в прошлом он менялся довольно круто).&lt;br /&gt;
* Чтобы использовать Beagle, достаточно знать имена его функций и как к ним обратиться.&lt;br /&gt;
&lt;br /&gt;
Вам это все еще кажется трудным? А так оно и есть. Но я ведь обещал научить вас всем навыкам, необходимым, чтобы к концу нашей серии уроков вы стали профессионалом, поэтому перейдем к делу...&lt;br /&gt;
&lt;br /&gt;
Начнем с имени нашего приложения. Приложениям Gnome на основе Mono уже приелись имена с буквой G, и я решил выбрать что-нибудь смешное и продвинутое. Предлагаю Poochy, это имя малоизвестного песьеголового персонажа игры Nintendo (даже Майк про него не слыхал!) – оно вполне подходит к собачьей теме, заданной Beagle {{oncolor||green|[англ. «гончий пес»]}}.&lt;br /&gt;
&lt;br /&gt;
Итак, запустите MonoDevelop, выберите {{oncolor||green|File &amp;gt; New Project}}, затем {{oncolor||green|C# &amp;gt; Console Project}}, уберите галочку с {{oncolor||green|Create Separate Solution Subdirectory}}, затем введите имя 'Poochy' в поле {{oncolor||green|Name}} и нажмите кнопку {{oncolor||green|New}} внизу. Вы получите старое доброе приложение Hello World – мы его 'программировали' в начале серии уроков; удалите строчки {{oncolor||green|Console.WriteLine()}} и оставьте метод {{oncolor||green|Main()}} пустым.&lt;br /&gt;
&lt;br /&gt;
=== GTK и командная строка ===&lt;br /&gt;
&lt;br /&gt;
Для этого проекта нам нужно использовать ''Beagle'' и – не удивляйтесь – ''GTK'', поэтому нажмите правой кнопкой мыши на References на панели слева (сразу над ''Resources'', ''AssemblyInfo.cs'' и ''Main.cs'') и выберите Edit References. В появившемся окне переключитесь на вкладку Packages, где выберите ''Beagle'' (версия 0.0.0.0 – я предупреждал, что он далеко не стабилен, не так ли?) и ''GTK-sharp'' (версия 2.10.0.0). Эти номера просто сообщают, какие версии установлены в данный момент – если у кого-то другая версия ''Beagle'', Mono преспокойно обойдется той, что есть.&lt;br /&gt;
&lt;br /&gt;
Тем самым мы запросили для использования библиотеки ''Beagle'' и ''GTK#'', но чтобы действительно их использовать, необходимо прописать операторы {{oncolor||green|using}} в начале исходного кода. По умолчанию, единственная строка {{oncolor||green|using}} –&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;using System;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Библиотека System включает основные функции для написания консольного приложения, включая доступ к самой консоли для обеспечения ввода-вывода. Мы хотим включить в этот список ''Beagle'' и ''GTK'', так что добавим следующие две строки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
using Beagle;&lt;br /&gt;
using Gtk;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В методе {{oncolor||green|Main()}} необходимо вызвать ''Beagle'' и сказать ему, что искать. Это можно сделать через {{oncolor||green|Query}}, специальный объект ''Beagle''. Этот объект также умеет запускать наши собственные методы при наступленииопределенных событий – например, найдя что-нибудь, отвечающее поисковому запросу. Вот как все это выглядит в C# – поместите этот код туда, где находился {{oncolor||green|Console.WriteLine()}}:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
// Создаем новый запрос и добавляем два метода обработчика событий&lt;br /&gt;
 Query q = new Query();&lt;br /&gt;
 q.HitsAddedEvent += OnHitsAdded;&lt;br /&gt;
 q.FinishedEvent += OnFinished;&lt;br /&gt;
// Сообщаем Beagle, что запрос содержится в первом параметре командной строки&lt;br /&gt;
 q.AddText(args[0]);                                                       &lt;br /&gt;
// Начинаем поиск&lt;br /&gt;
 q.SendAsync();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
В общем, несложно, но это еще не вся сказка: найдя файл, RSS-ленту или что там еще совпадет с нашим запросом, ''Beagle'' всегда в вызывает метод {{oncolor||green|OnHitsAdded()}}, а закончив поиск, вызовет метод {{oncolor||green|OnFinished()}} – чтобы код скомпилировался, необходимо реализовать оба этих метода. Для успешной компиляции достаточно вставить два пустых метода:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
 static void OnHitsAdded (HitsAddedResponse response) { }&lt;br /&gt;
 static void OnFinished(FinishedResponse response) { }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Объекты {{oncolor||green|HitsAddedResponse}} и {{oncolor||green|FinishedResponse}} вообще-то дают массу полезной информации, но пока мы их проигнорируем. Продолжим: нажмем F8, чтоб скомпилировать первый релиз ''Poochy'' (храбро назовем его 0.1), затем откроем окно терминала и перейдем в '''/каталог/где/находится/poochy/bin/Debug'''. Пора протестировать нашу ищейку.&lt;br /&gt;
&lt;br /&gt;
''Poochy'' необходимо запускать из командной строки, потому что он читает {{oncolor||green|arg[0]}}, который мы должны передать из командной строки. Запустите следующую команду:&lt;br /&gt;
&lt;br /&gt;
 mono poochy.exe foo&lt;br /&gt;
&lt;br /&gt;
Эта команда заставит ''Beagle'' искать в своем кэше аргумент {{oncolor||green|'foo'}}, и для выполнения запроса понадобится около секунды (замените {{oncolor||green|foo}} на что-нибудь заведомо присутствующее в вашем кэше ''Beagle''). Но тут вы обнаружите, что ничего не выводится – ни файлов, ни чего-либо еще,&lt;br /&gt;
содержащего {{oncolor||green|'foo'}}. Чья это проблема – ''Beagle'' или наша? ''Beagle'' вне подозрений, значит, проблема в нашем коде. Расследуем...&lt;br /&gt;
&lt;br /&gt;
=== Гонка на время ===&lt;br /&gt;
&lt;br /&gt;
Наша программа не работает по двум причинам. Более заметная из них – пуст метод {{oncolor||green|OnHitsAdded()}}, вызываемый ''Beagle'' при нахождении совпадения, в который ''Poochy'' должен вывести результат. Поэтому Mono безмолвствует, даже и получив что-то от ''Beagle''. Проще всего заставить ''Poochy'' выводить URL каждого найденного ''Beagle'' объекта, например, так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
foreach(Hit hit in response.Hits)&lt;br /&gt;
 {&lt;br /&gt;
  Console.WriteLine(&amp;quot;Hit: &amp;quot; + hit.Uri);&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если вы запустите программу, то увидите, что она опять ничего не выдает, хотя ''Beagle'' должен бы найти то, что вы просили. Проблема том, что наш поиск использует метод '''SendAsync()''', то есть ''Beagle'' выполняет поиск асинхронно. Мысленно прокрутите программу: компьютер выполняет первую строчку, переходит ко второй, затем к третьей, и так далее до конца. Конечно, иногда программа перескакивает с места на место, но смысл в том, что в один момент времени исполняется одна строка кода.&lt;br /&gt;
&lt;br /&gt;
У ''Beagle'' есть два способа поиска: синхронный и асинхронный. Первый означает «выполняй поиск, а я буду ждать его окончания», а второй – «начинай поиск, а я продолжу выполнение программы; когда закончишь, прерви меня». Они также известны как блокирующий и неблокирующий, потому что синхронный метод блокирует выполнение следующей строки, пока сам не завершит работу, в то время как асинхронный метод позволит вам выполнять код, а сам будет работать параллельно.&lt;br /&gt;
&lt;br /&gt;
Вам необходимо это знать, чтобы учесть такую возможность: вдруг ваша программа завершится раньше, чем асинхронный метод успеет что-либо сделать? То есть завершится до того, как ''Beagle'' найдет какое-либо совпадение? Ответ состоит в том, что программа успешно отключится, и вызванный метод сгинет, не успев ничего напечатать. Вот почему мы не получили никакого результата, и, значит, нам надо ждать, пока ''Beagle'' завершит поиск.&lt;br /&gt;
&lt;br /&gt;
Вот здесь на сцену и выходит GTK. Когда вы используете программы с графическим интерфейсом, приложение ждет, пока вы чтонибудь сделаете: выберете пункт меню или хотя бы наведете курсор мыши на кнопку. Фактически, любое действие посылает сигнал приложению, чтобы оно смогло отреагировать, то есть приложение просто ждет сигнала. Очевидно, такие приложения не отключаются, выполнив то или иное действие, иначе, например, в Abiword вам пришлось бы непрерывно что-то печатать, чтобы редактор не закрылся. Вместо этого они используют так называемый главный цикл [сообщений], который выглядит примерно так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
while (1) {&lt;br /&gt;
  LookForSignals();&lt;br /&gt;
  ActOnSignals();&lt;br /&gt;
}&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вы, конечно, сообразили, что это бесконечный цикл, но он практически не потребляет процессорное время и позволяет другим частям приложения (графическому интерфейсу или, в нашем случае, ''Beagle'') работать на полную катушку. Нам того и надо, вот почему мы собираемся сесть на главный цикл GTK: пусть наша программа простаивает, пока ''Beagle'' производит поиск и вывод результата. Чтобы это сделать, добавим в конец метода {{oncolor||green|Main()}} две строчки:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;Gtk.Application.Init();&lt;br /&gt;
Gtk.Application.Run();&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Этот код велит GTK запуститься и работать. Скомпилируйте программу, нажав {{oncolor||green|F8}}, и запустите ее из командной строки. На этот раз вы должны получить список результатов, похожих на следующие:&lt;br /&gt;
&lt;br /&gt;
 Hit: file:///home/paul/foo.xml&lt;br /&gt;
 Hit: file:///usr/share/doc/tzdata-2006m/tz-link.html&lt;br /&gt;
 Hit: file:///usr/share/gtk-doc/html/libuser/libuser-config.html&lt;br /&gt;
 Hit: file:///usr/share/doc/nant-0.85/releasenotes.html&lt;br /&gt;
 Hit: file:///usr/share/gtk-doc/html/libgnome/libgnome-gnomeconfig.html&lt;br /&gt;
 Hit: file:///usr/share/gtk-doc/html/gtk/gtk-question-index.html&lt;br /&gt;
 Hit: file:///usr/share/gtk-doc/html/gtk/gtk-Resource-Files.html&lt;br /&gt;
&lt;br /&gt;
=== Два шага вперед, один назад ===&lt;br /&gt;
&lt;br /&gt;
Кроме основного результата, мы также получили побочный: выхода из приложения не происходит. Когда ''Beagle'' вернет все возможные результаты, Poochy будет по-прежнему чего-то ждать. Вы видели, что основной цикл приложения – бесконечный, и коль скоро мы вызвали метод {{oncolor||green|Application.Run()}}, то вошли в состояние вечного исполнения. Пока программа не даст сбой, машина не перезагрузится или мы не нажмем {{oncolor||green|Ctrl+C}}, ''Poochy'' так и будет находиться в этом состоянии.&lt;br /&gt;
&lt;br /&gt;
Может, вам того и надо – к примеру, вы хотите периодически проверять ресурс или дожидаться, пока данные поиска доберутся до вас через сокет. Но ''Poochy'' задуман как программа, выполняющая поиск по требованию, а затем завершающаяся. Мы уже написали заглушку метода {{oncolor||green|OnHitsAdded}}, а теперь займемся методом {{oncolor||green|OnFinished()}}, который покамест пуст.&lt;br /&gt;
&lt;br /&gt;
Когда ''Beagle'' вернет все результаты, он посмотрит, зарегистрирован ли метод для свойства {{oncolor||green|FinishedEvent}}. Мы уже делали это с нашим методом {{oncolor||green|OnFinished()}}, который вызывается по окончании работы ''Beagle''. А сейчас нам нужно сообщить GTK, чтобы программа покинула основной цикл, тогда наше приложение сможет корректно завершиться. Это довольно просто – вот как выглядит новый метод {{oncolor||green|OnFinished()}}:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
static void OnFinished(FinishedResponse response)&lt;br /&gt;
 {&lt;br /&gt;
   Application.Quit();&lt;br /&gt;
 }&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{oncolor||green|Application.Quit()}} – это GTK-метод, который прерывает главный цикл, очищает все использованные GTK-ресурсы (в нашем случае их немного, так как мы не работаем с графикой), затем передает управление нашему приложению сразу же после строки {{oncolor||green|Application.Run()}} в методе {{oncolor||green|Main()}}. Поэтому путь работы программы будет следующим: {{oncolor||green|Main() &amp;gt; SendAsync() &amp;gt; Application.Run()}} &amp;gt; основной цикл GTK &amp;gt; {{oncolor||green|OnFinished() &amp;gt; Application.Quit() &amp;gt; Main()}}.&lt;br /&gt;
&lt;br /&gt;
Скомпилируйте, запустите и восхититесь собственным умом: ваша программа делает все, что задумано, и потребовала всего десять строк значащего кода!&lt;br /&gt;
&lt;br /&gt;
''Poochy'' выводит на экран все URL, RSS-ленты, документы OpenOffice.org, MP3, презентации PowerPoint, заметки Tomboy, исходный код, JPEG файлы, приложения... (глубокий вдох)... email, видео, встречи, zip-файлы и установленные пакеты на вашей системе, которые соответствуют запросу, передаваемому в {{oncolor||green|AddText()}}. А если вас интересуют только файлы, находящиеся на вашем диске, а не все что ни попадя?&lt;br /&gt;
&lt;br /&gt;
=== Погодите... еще не все! ===&lt;br /&gt;
&lt;br /&gt;
Два урока назад мы рассматривали метод {{oncolor||green|EndsWith()}}, применимый к строкам, который принимает строку в качестве аргумента и возвращает true, если строка А оканчивается строкой B. Например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;string foo = &amp;quot;bar&amp;quot;;&lt;br /&gt;
bool baz = foo.EndsWith(&amp;quot;r&amp;quot;);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Когда этот код выполнится, переменная {{oncolor||green|baz}} установится в '''{{oncolor||green|true}}''', так как {{oncolor||green|foo}} оканчивается на 'R'. В .NET также есть метод {{oncolor||green|StartsWith()}}, который действует наоборот – возвращает '''{{oncolor||green|true}}''', если одна строка начинается с другой. Выходит, мы можем заставить наш код выводить только файлы, поменяв метод {{oncolor||green|OnHitsAdded()}} на следующий:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
 static void OnHitsAdded (Beagle.HitsAddedResponse response)&lt;br /&gt;
  {&lt;br /&gt;
    foreach(Hit hit in response.Hits)&lt;br /&gt;
     {&lt;br /&gt;
       if (hit.Uri.StartsWith(&amp;quot;file&amp;quot;))&lt;br /&gt;
        {&lt;br /&gt;
         Console.WriteLine(&amp;quot;Hit: &amp;quot; + hit.Uri);&lt;br /&gt;
        }&lt;br /&gt;
     }&lt;br /&gt;
  }&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это метод грубой силы: ''Beagle'' ищет все подряд, а мы фильтруем результаты перед выводом. Но ''Beagle'' можно научить искать и конкретный тип совпадений, с помощью метода {{oncolor||green|AddHitType()}}: он позволит описать то, что вы ищете, обычным текстом. Корректные параметры включают {{oncolor||green|Application}}, {{oncolor||green|Calendar}}, {{oncolor||green|Contact}}, {{oncolor||green|Feeditem}} (для RSS), {{oncolor||green|Image}}, {{oncolor||green|IMLog}}, {{oncolor||green|MailMessage}} и – вот оно! – {{oncolor||green|File}}.&lt;br /&gt;
&lt;br /&gt;
Вернувшись к методу {{oncolor||green|Main()}}, найдите строку {{oncolor||green|q.AddText(args[0])}} и добавьте перед ней строку:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;q.AddHitType(&amp;quot;File&amp;quot;);&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Запустите программу, и увидите, что выводятся только файлы – никакой переписки из чатов, засоряющей результаты! [http://www.linuxformat.ru LXF]&lt;br /&gt;
&lt;br /&gt;
=== Часто задаваемые вопросы ===&lt;br /&gt;
&lt;br /&gt;
'''Mono FAQ – часть I'''&lt;br /&gt;
&lt;br /&gt;
''Если тонкие моменты Mono вызывают у вас вопросы, то вот ответы на них...''&lt;br /&gt;
&lt;br /&gt;
* '''Не понял. Зачем мы пометили Reference, а потом еще и прописали строку {{oncolor||red|using}}?'''&lt;br /&gt;
&lt;br /&gt;
Добавление чего-то через Reference позволяет воспользоваться соответствущим кодом; добавление чего-то с помощью строки {{oncolor||red|using}} позволяет сэкономить набор кода при вызове методов. Для подключения ''Beagle'' необходимо добавить его как Reference – тогда станут доступны его объекты и методы, и мы можем немедля их использовать, но только под полным именем, включающим ссылку на пространство имен. Строка {{oncolor||red|using Beagle}}; сообщает .NET, что когда мы пишем {{oncolor||red|Query}}, подразумевается {{oncolor||red|Beagle.Query}}. В нашем случае экономия невелика; а вот, например, алгоритм SHA1 в .NET находится в пространстве {{oncolor||red|System.Encryption.Cryptography}}, и пришлось бы писать {{oncolor||red|System.Encryption.Cryptography.SHA1CryptoServiceProvider foo &amp;amp;#61; new System.Encryption.Cryptography.SHA1CryptoServiceProvider()}} – согласитесь, довольно утомительно! Вместо этого можно поместить в начале {{oncolor||red|using System.Encryption.Cryptography;}}, затем {{oncolor||red|SHA1CryptoServiceProvider foo &amp;amp;#61; new SHA1CryptoServiceProvider()}}. Помните, что MonoDevelop по умолчанию добавляет System в Reference.&lt;br /&gt;
* '''Почему мы используем +=, чтобы добавить метод к событию Beagle? Я думал, что += для добавления значения к переменной.'''&lt;br /&gt;
&lt;br /&gt;
Да, += используется для сложения переменных, но почему бы не расширить эту метафору на события, происходящие во время работы Beagle, и не использовать += для добавления методов. Это также известно как подписка. Используя +=, вы можете 'подписать' несколько методов на одно событие – Mono просто запустит их по одному последовательно в порядке их добавления.&lt;br /&gt;
* '''Зачем нужен файл AssemblyInfo.cs?'''&lt;br /&gt;
&lt;br /&gt;
Вы будете смеяться, но там и правда информация о вашей сборке! В терминах .NET сборка может быть как разделяемым объектом (SO файл в Linux или DLL в Windows), так и исполняемым файлом. Номер версии вашего исполняемого файла, имя программиста и другая информация находится в конечном двоичном файле poochy, и все это вы устанавливаете в AssemblyInfo.cs.&lt;br /&gt;
* '''Надо ли располагать открывающую и закрывающую фигурные скобки на отдельных строках?'''&lt;br /&gt;
&lt;br /&gt;
Нет – вовсе нет! Лично я люблю ставить { на той же строке, что и оператор, ей предшествующий. Этот стиль известен как Единственно Верный Скобочный Стиль, потому что его приняли Брайан Керниган и Деннис Ритчи, когда они изобрели язык программирования С. Однако MonoDevelop по умолчанию использует стиль BSD, когда каждая скобка располагается на своей строке. Выбирайте, что вам больше нравится, главное – соблюдать единый стиль во всей программе!&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Lockal</id>
		<title>Участник:Lockal</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:Lockal"/>
				<updated>2008-04-27T16:52:48Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: +2 цикла&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Учебники ===&lt;br /&gt;
* [[LXF70:Gnome 2.10]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF70:Perl. Переменные и операторы]]&lt;br /&gt;
* [[LXF70:Perl. Сортируем наш код]]&lt;br /&gt;
* [[LXF72:Perl]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF70:Subversion1]]&lt;br /&gt;
* [[LXF70:Subversion2]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF70:PHP. Загадка Монти Холла]]&lt;br /&gt;
* [[LXF73:PHP I]]&lt;br /&gt;
* [[LXF73:PHP II]]&lt;br /&gt;
* [[LXF76:Учебник PHP]]&lt;br /&gt;
* [[PHP]]&lt;br /&gt;
* [[LXF78:Учебник PHP: MySQL 5.0 Special]]&lt;br /&gt;
* [[LXF79:PHP]]&lt;br /&gt;
* [[LXF80:PHP]]&lt;br /&gt;
* [[LXF81:PHP]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF72:Gambas]]&lt;br /&gt;
* [[LXF73:Gambas]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF70:GIMP. Коррекция улыбки]]&lt;br /&gt;
* [[LXF72:GIMP]]&lt;br /&gt;
* [[LXF73:GIMP]]&lt;br /&gt;
* [[LXF76:Учебник Gimp, часть 1]]&lt;br /&gt;
* [[LXF76:Учебник Gimp, часть 2]]&lt;br /&gt;
* [[LXF78:Gimp: Блики на стекле]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF73:Автомонтирование USB]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF73:Русификация Debian 3.1]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF73:Локализация ПО]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF72:Первые шаги]]&lt;br /&gt;
* [[LXF73:Первые шаги]]&lt;br /&gt;
* [[LXF76:Первые шаги: Writer]]&lt;br /&gt;
* [[LXF76:Первые шаги: Impress]]&lt;br /&gt;
* [[LXF80:первые шаги]]&lt;br /&gt;
* [[LXF81:Firefox]]&lt;br /&gt;
* [[LXF82:Первые шаги]]&lt;br /&gt;
* [[LXF83:Ubuntu_for_children]]&lt;br /&gt;
* [[LXF84:Первые шаги]]&lt;br /&gt;
* [[LXF89:Первые шаги]]&lt;br /&gt;
* [[LXF92:Первые шаги]]&lt;br /&gt;
* [[LXF96:Первые шаги]]&lt;br /&gt;
* [[LXF97:Первые шаги]]&lt;br /&gt;
* [[LXF98:Первые_шаги]]&lt;br /&gt;
* [[LXF99:Первые шаги]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF76:Азбука записи]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF76:Учебник Fuse]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF76:Ubuntu по-русски]]&lt;br /&gt;
* [[LXF76:Учебник Ubuntu, часть 2]]&lt;br /&gt;
&lt;br /&gt;
{{Цикл/Inkscape}}&lt;br /&gt;
* [[LXF76:Учебник Inkscape, часть 1]]&lt;br /&gt;
* [[LXF76:Учебник Inkscape, часть 2]]&lt;br /&gt;
* [[LXF78:Inkscape. Работа с текстом]]&lt;br /&gt;
* [[LXF79:Inkscape]]&lt;br /&gt;
* [[LXF81:Inkscape]]&lt;br /&gt;
* [[LXF82:Inkscape]]&lt;br /&gt;
* [[LXF83:InkScape]]&lt;br /&gt;
* [[LXF84:Inkscape]]&lt;br /&gt;
* [[LXF85:Inkscape]]&lt;br /&gt;
* [[LXF86:Inkscape]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF76:Введение в MetaPost]]&lt;br /&gt;
* [[LXF78:MetaPost Начала автоматизации]]&lt;br /&gt;
* [[LXF79:Metapost]]&lt;br /&gt;
* [[LXF80:MetaPost]]&lt;br /&gt;
&lt;br /&gt;
{{Цикл/Python}}&lt;br /&gt;
* [[LXF76:Уроки Python, часть 2]]&lt;br /&gt;
* [[LXF76:Разработка расширений Pyhton]]&lt;br /&gt;
* [[LXF78:Уроки Python]]&lt;br /&gt;
* [[LXF79:Python]]&lt;br /&gt;
* [[LXF80:Python]]&lt;br /&gt;
* [[LXF81:Python]]&lt;br /&gt;
* [[LXF82:Python]]&lt;br /&gt;
* [[LXF83:Python]]&lt;br /&gt;
* [[LXF84:Python]]&lt;br /&gt;
* [[LXF97:Python]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF76:Hardcore Linux, часть 1]]&lt;br /&gt;
* [[LXF76:Hardcore Linux, часть 2]]&lt;br /&gt;
* [[LXF78:Мощные инструменты командной строки]] ?&lt;br /&gt;
* [[LXF79:Hardcore Linux]]&lt;br /&gt;
* [[LXF80:Hardcore Linux]]&lt;br /&gt;
* [[LXF82:Hardcore Linux]]&lt;br /&gt;
* [[LXF83:Hardcore_Linux]]&lt;br /&gt;
* [[LXF84:Hardcore Linux]]&lt;br /&gt;
* [[LXF89:Hardcore Linux]]&lt;br /&gt;
* [[LXF92:Hardcore Linux]]&lt;br /&gt;
* [[LXF94:Графическое web-приложение]]&lt;br /&gt;
* [[LXF96:Hardcore linux:APT]]&lt;br /&gt;
* [[LXF97:Hardcore Linux]]&lt;br /&gt;
* [[LXF98:Hardcore Linux]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF78:Evolution: Управляйте своей почтой]]&lt;br /&gt;
&lt;br /&gt;
{{Цикл/Qt/KDE}}&lt;br /&gt;
* [[LXF78:Знакомство с Qt: первые шаги]]&lt;br /&gt;
* [[LXF79:Qt/KDE]]&lt;br /&gt;
* [[LXF80:Qt/KDE]]&lt;br /&gt;
* [[LXF81:KDE]]&lt;br /&gt;
* [[LXF82:Qt/KDE]]&lt;br /&gt;
* [[LXF83:Qt_KDE]]&lt;br /&gt;
* [[LXF84:Qt/KDE]]&lt;br /&gt;
* [[LXF85:Qt/KDE]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF78:Почему – Vim?]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF79:Audacity]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF79:Чистим записи]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF79:DCOP]]&lt;br /&gt;
&lt;br /&gt;
{{Цикл/OOo Basic}}&lt;br /&gt;
* [[LXF80:OOo Basic]]&lt;br /&gt;
* [[LXF81:OOo]]&lt;br /&gt;
* [[LXF82:OpenOffice.org]]&lt;br /&gt;
* [[LXF83:OOo_Basic]]&lt;br /&gt;
* [[LXF84:OpenOffice.org]]&lt;br /&gt;
* [[LXF85:OpenOffice.org Base]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF82:Безопасность]]&lt;br /&gt;
* [[LXF84:Безопасность]]&lt;br /&gt;
* [[LXF85:Безопасность]]&lt;br /&gt;
* [[LXF86:Безопасность]]&lt;br /&gt;
* [[LXF89:Безопасность]] 5&lt;br /&gt;
&lt;br /&gt;
* [[LXF80:загрузка]]&lt;br /&gt;
&lt;br /&gt;
{{Цикл/Unix API}}&lt;br /&gt;
* [[LXF80:Программирование для Linux]]&lt;br /&gt;
* [[LXF81:IPC]]&lt;br /&gt;
* [[LXF82:Unix API]]&lt;br /&gt;
* [[LXF83:Unix_API]]&lt;br /&gt;
* [[LXF84:Unix API]]&lt;br /&gt;
* [[LXF85:Unix API]]&lt;br /&gt;
* [[LXF86:Unix]]&lt;br /&gt;
* [[LXF89:Unix API]] 8&lt;br /&gt;
* [[LXF90:Unix API]]&lt;br /&gt;
* [[LXF91:Unix API]]&lt;br /&gt;
* [[LXF92:Unix API]] 12&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF80:шифрование]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF81:WordPress]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF81:DansGuardian]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF81:Open-Xchange]]&lt;br /&gt;
&lt;br /&gt;
{{Цикл/Maxima}}&lt;br /&gt;
* [[LXF81:Maxima]]&lt;br /&gt;
* [[LXF82:Maxima]]&lt;br /&gt;
* [[LXF83:MAXIMA]]&lt;br /&gt;
* [[LXF84:Maxima]]&lt;br /&gt;
* [[LXF85:Maxima]]&lt;br /&gt;
* [[LXF86:Maxima]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF81:PAW]]&lt;br /&gt;
* [[LXF83:ROOT]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF82:Разработка 3D-игры]]&lt;br /&gt;
* [[LXF83:3D_Game]]&lt;br /&gt;
* [[LXF84:Разработка 3D-игры]]&lt;br /&gt;
* [[LXF85:Ogre]]&lt;br /&gt;
* [[LXF86:Ogre]]&lt;br /&gt;
&lt;br /&gt;
{{Цикл/LaTeX}}&lt;br /&gt;
* [[LXF82:LaTeX]]&lt;br /&gt;
* [[LXF83:LaTex]]&lt;br /&gt;
* [[LXF84:LaTeX]]&lt;br /&gt;
* [[LXF85:LaTeX]]&lt;br /&gt;
* [[LXF86:LaTeX]]&lt;br /&gt;
* [[LXF89:LaTeX]] 6&lt;br /&gt;
* [[LXF90:LaTeX]]&lt;br /&gt;
* [[LXF91:LaTeX]]&lt;br /&gt;
* [[LXF92:TeX]] 9&lt;br /&gt;
* [[LXF94:LaTeX Программирование]]&lt;br /&gt;
* [[LXF97:TeX]]&lt;br /&gt;
&lt;br /&gt;
{{Цикл/Java}}&lt;br /&gt;
* [[LXF82:Java]]&lt;br /&gt;
* [[LXF84:Java]]&lt;br /&gt;
* [[LXF85:Java]]&lt;br /&gt;
* [[LXF86:Java]]&lt;br /&gt;
* [[LXF87/88:Java]]&lt;br /&gt;
&lt;br /&gt;
{{Цикл/Java EE}}&lt;br /&gt;
* [[LXF89:Java EE]] 1&lt;br /&gt;
* [[LXF90:JavaEE]]&lt;br /&gt;
* [[LXF91:Java EE]]&lt;br /&gt;
* [[LXF92:Java EE]] 4&lt;br /&gt;
* [[LXF94:Команды и фабрики]] (серия «Java Enterprise Edition»)&lt;br /&gt;
* [[LXF95:Java EE]]&lt;br /&gt;
* [[LXF96:Java EE]] 8&lt;br /&gt;
* [[LXF97:Java]]&lt;br /&gt;
* [[LXF98:Java EE10]] 10&lt;br /&gt;
* [[LXF99:Java EE EJB3]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF83:HDD]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF83:XDMCP]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF83:WINK]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF85:Compiz]]&lt;br /&gt;
&lt;br /&gt;
{{Цикл/PostgreSQL}}&lt;br /&gt;
* [[LXF85:PostgreSQL]]&lt;br /&gt;
* [[LXF86:Учебники:PostgreSQL]]&lt;br /&gt;
* [[LXF89:PostgreSQL]] 4&lt;br /&gt;
* [[LXF90:PostgreSQL]]&lt;br /&gt;
* [[LXF91:PostgreSQL]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF86:Wine]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF86:Kamaelia]]&lt;br /&gt;
&lt;br /&gt;
{{Цикл/GTK+}}&lt;br /&gt;
* [[LXF86:GTK]]&lt;br /&gt;
* [[LXF89:GTK+]] 3&lt;br /&gt;
* [[LXF90:GTK+]]&lt;br /&gt;
* [[LXF91:GTK]]&lt;br /&gt;
* [[LXF92:GTK+]] 6&lt;br /&gt;
* [[LXF94:GTK+: Буфер обмена и VFS]]&lt;br /&gt;
* [[LXF95:GTK+]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF89:Blender]] 2&lt;br /&gt;
* [[LXF90:Blender]]&lt;br /&gt;
* [[LXF91:Blender]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF90:RPM]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF90:SugarCRM]]&lt;br /&gt;
* [[LXF91:SugarCRM]]&lt;br /&gt;
* [[LXF92:SugarCRM]] 3&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF90:Grub]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF91:Система]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF91:XSLT]]&lt;br /&gt;
&lt;br /&gt;
{{Цикл/Mono}}&lt;br /&gt;
* [[LXF89:Mono]]&lt;br /&gt;
* [[LXF90:Mono]]&lt;br /&gt;
* [[LXF91:Mono]]&lt;br /&gt;
* [[LXF92:Mono-Мания]]&lt;br /&gt;
* [[LXF94:Программирование для Mono]]&lt;br /&gt;
* [[LXF95:Mono]]&lt;br /&gt;
* [[LXF96:Mono-мания]]&lt;br /&gt;
* [[LXF97:Mono]]&lt;br /&gt;
* [[LXF98:Mono]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF91:Deb]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF92:Lm-sensors HOWTO]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF92:Cinelerra]] 1&lt;br /&gt;
* [[LXF95:Cinelerra]]&lt;br /&gt;
&lt;br /&gt;
* [[LXF94:Обмен файлами]] (серия «Linux для новичков»)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF94:Макрос, загружающий данные]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF94:Следим за сетью]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF95:F-Spot]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF95:Akelos]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF95:Cron]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF95:DCOP]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF95:Препринт]]&lt;br /&gt;
&lt;br /&gt;
* [[LXF97:Препресс в Linux]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF96:Bash]] 1&lt;br /&gt;
* [[LXF97:Bash]]&lt;br /&gt;
* [[LXF98:Bash3]] 3&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF96:Evolution]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF96:Vim]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF97:Командная строка]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF97:GtkSourceView]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF97:Новая серия!]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF97:Hibernate]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF98:KDE]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF98:Диагностика]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF98:Ананас3]] 2&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF98:wxWidgets1]] 1&lt;br /&gt;
* [[LXF99:wxWidgets]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF98:Perl и C++]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF98:Чистка DVD видео]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF99:D-Bus]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[LXF99:WavPack]]&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/%D0%A8%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD:%D0%A6%D0%B8%D0%BA%D0%BB/GTK%2B</id>
		<title>Шаблон:Цикл/GTK+</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/%D0%A8%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD:%D0%A6%D0%B8%D0%BA%D0%BB/GTK%2B"/>
				<updated>2008-04-27T16:49:39Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: оформление&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{цикл|GTK+|&lt;br /&gt;
* [[LXF86:GTK+|Часть 1: ]]&lt;br /&gt;
* [[LXF87-88:GTK+|Часть 2: Интернационализация]]&lt;br /&gt;
* [[LXF89:GTK+|Часть 3: Изучаем сигналы и события]]&lt;br /&gt;
* [[LXF90:GTK+|Часть 4: Glade 2.x — визуальная классика]]&lt;br /&gt;
* [[LXF91:GTK+|Часть 5: Новый Glade]]&lt;br /&gt;
* [[LXF92:GTK+|Часть 6: Программирование GNOME]]&lt;br /&gt;
* [[LXF93:GTK+|Часть 7: ]]&lt;br /&gt;
* [[LXF94:GTK+|Часть 8: Буфер обмена и VFS]]&lt;br /&gt;
* [[LXF95:GTK+|Часть 9: Переход на C++]]&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/%D0%A8%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD:%D0%A6%D0%B8%D0%BA%D0%BB/GTK%2B</id>
		<title>Шаблон:Цикл/GTK+</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/%D0%A8%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD:%D0%A6%D0%B8%D0%BA%D0%BB/GTK%2B"/>
				<updated>2008-04-27T16:49:17Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: +&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{цикл|GTK+|&lt;br /&gt;
* [[LXF86:GTK+|Часть 1: ]]&lt;br /&gt;
* [[LXF87-88:GTK+|Часть 2: Интернационализация]]&lt;br /&gt;
* [[LXF89:GTK+|Часть 3: Изучаем сигналы и события]]&lt;br /&gt;
* [[LXF90:GTK+|Часть 4: Glade 2.x — визуальная классика]]&lt;br /&gt;
* [[LXF91:GTK+|Часть 5: Новый Glade]]&lt;br /&gt;
* [[LXF92:GTK+|Часть 6: Программирование GNOME – первые шаги]]&lt;br /&gt;
* [[LXF93:GTK+|Часть 7: ]]&lt;br /&gt;
* [[LXF94:GTK+|Часть 8: Буфер обмена и VFS]]&lt;br /&gt;
* [[LXF95:GTK+|Часть 9: Переход на C++]]&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/%D0%A8%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD:%D0%A6%D0%B8%D0%BA%D0%BB/GTK%2B</id>
		<title>Шаблон:Цикл/GTK+</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/%D0%A8%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD:%D0%A6%D0%B8%D0%BA%D0%BB/GTK%2B"/>
				<updated>2008-04-27T16:48:56Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: Новая: {{цикл|GTK| * Часть 1:  * Часть 2: Интернационализация * [[LXF89:GTK+|Часть 3: Изучаем сигналы и с...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{цикл|GTK|&lt;br /&gt;
* [[LXF86:GTK+|Часть 1: ]]&lt;br /&gt;
* [[LXF87-88:GTK+|Часть 2: Интернационализация]]&lt;br /&gt;
* [[LXF89:GTK+|Часть 3: Изучаем сигналы и события]]&lt;br /&gt;
* [[LXF90:GTK+|Часть 4: Glade 2.x — визуальная классика]]&lt;br /&gt;
* [[LXF91:GTK+|Часть 5: Новый Glade]]&lt;br /&gt;
* [[LXF92:GTK+|Часть 6: Программирование GNOME – первые шаги]]&lt;br /&gt;
* [[LXF93:GTK+|Часть 7: ]]&lt;br /&gt;
* [[LXF94:GTK+|Часть 8: Буфер обмена и VFS]]&lt;br /&gt;
* [[LXF95:GTK+|Часть 9: Переход на C++]]&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF94:GTK%2B:_%D0%91%D1%83%D1%84%D0%B5%D1%80_%D0%BE%D0%B1%D0%BC%D0%B5%D0%BD%D0%B0_%D0%B8_VFS</id>
		<title>LXF94:GTK+: Буфер обмена и VFS</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF94:GTK%2B:_%D0%91%D1%83%D1%84%D0%B5%D1%80_%D0%BE%D0%B1%D0%BC%D0%B5%D0%BD%D0%B0_%D0%B8_VFS"/>
				<updated>2008-04-27T16:43:03Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: «LXF94:GTK+: Буфер обмена и VFS» переименована в «LXF94:GTK+»: унификация&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[LXF94:GTK+]]&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF94:GTK%2B</id>
		<title>LXF94:GTK+</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF94:GTK%2B"/>
				<updated>2008-04-27T16:43:03Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: «LXF94:GTK+: Буфер обмена и VFS» переименована в «LXF94:GTK+»: унификация&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Погружение в GNOME ==&lt;br /&gt;
''ЧАСТЬ 8 Мы уже успели замочить ножки в океане возможностей, которые предоставляет GNOME – и сейчас самое время зайти поглубже. '''Андрей Боровский''' проверяет, теплая ли водичка.''&lt;br /&gt;
&lt;br /&gt;
В прошлый раз мы начали работу над демо-приложением GNOME – текстовым редактором. До сих пор в этой программе собственно «гномовского» было не так уж много: только код инициализации. На этот раз мы рассмотрим некоторые функции, относящиеся исключительно к GNOME; но сначала – немного визуального программирования.&lt;br /&gt;
&lt;br /&gt;
=== Редактирование меню ===&lt;br /&gt;
&lt;br /&gt;
Заготовка главного меню нашей программы содержит пункт Вид (View), однако само это меню пустое. Добавим в меню Вид новую команду Шрифт..., позволяющую выбрать шрифт для отображения текста. Щелкните правой кнопкой мыши по строке главного меню в окне формы приложения и в открывшемся контекстном меню выберите команду Правка меню...&lt;br /&gt;
&lt;br /&gt;
[[Image:Gtk 1.JPG|left|thumb|300px|Редактор меню Glade.]]&lt;br /&gt;
&lt;br /&gt;
Список названий пунктов меню отражает существующие между ними иерархические отношения. Сдвиг строки вправо означает переход к следующему уровню вложенности меню. С помощью кнопок Добавить и Добавить подчиненный в меню можно добавить новый пункт. При добавлении нового подчиненного пункта необходимо указать для него родительский пункт меню. Если мы потом передумаем, то с помощью клавиш навигации сможем переместить уже созданный пункт в другую группу или на другой уровень вложенности.&lt;br /&gt;
&lt;br /&gt;
Раскрывающийся список Встроенный элемент позволяет присвоить новому пункту меню свойства одного из стандартных элементов меню (эти встроенные элементы используют пункты меню, созданные автоматически). Строка ввода Метка позволяет указать название пункта меню. Нижний дефис в названии пункта меню отмечает подчеркнутый символ, который нужно вводить в сочетании с Alt для быстрого доступа к этому пункту. Строка ввода имя позволяет указать имя объекта GtkImageMenuItem, соответствующего пункту меню. В строке ввода Обработчик указывается имя функции-обработчика сигнала activate, посылаемого командой меню. Комбинированный раскрывающийся список Иконка позволяет указать пиктограмму, которая будет отображаться рядом с командой меню. Можно загрузить собственную пиктограмму из файла либо использовать одну из стандартных пиктограмм, установленных в системе.&lt;br /&gt;
&lt;br /&gt;
Для создаваемого нами пункта меню Шрифт... выберем стандартную пиктограмму gtk-select-font. Остальные элементы редактора меню нам сейчас не интересны, так что мы их опустим (читателю, как всегда, рекомендуется обратиться к документации). Щелкните кнопку OK. Теперь у нас есть новая команда меню, для которой нужно написать обработчик (функция on_fontselect_activate()). Для выбора шрифта используйте уже знакомое нам диалоговое окно GtkFontSelectionDialog. Полный код обработчика вы найдете на диске, мы на нем останавливаться не будем.&lt;br /&gt;
&lt;br /&gt;
=== Буфер обмена GTK+ и GNOME ===&lt;br /&gt;
&lt;br /&gt;
Интерфейс буфера обмена в GTK+ основан на структуре GtkClipboard. Мы получаем доступ к этой структуре с помощью функции gtk_clipboard_get(). Первый вызов gtk_clipboard_get() создает экземпляр структуры, которая переходит под управление GTK+ (так что мы не должны удалять ее явным образом). При последующих вызовах gtk_clipboard_get() возвращает указатель на существующую структуру GtkClipboard.&lt;br /&gt;
&lt;br /&gt;
При работе с X Window следует учесть, что система поддерживает как минимум два буфера обмена (теоретически их может быть и больше). Если вы используете команду меню Правка | Копировать, данные обычно попадают в буфер обмена, связанный с атомом CLIPBOARD. В то же время любые данные, выделенные мышью в окне X-программы, заносятся в буфер обмена, связанный с атомом PRIMARY (вставка данных из этого буфера обычно выполняется с помощью щелчка средней кнопкой мыши). Вообще говоря, X-программы вольны интерпретировать оба буфера так, как им заблагорассудится. На практике это иногда приводит к тому, что результаты вставки данных из буфера обмена оказываются несколько неожиданными.&lt;br /&gt;
&lt;br /&gt;
Интерфейс буфера обмена GTK+ позволяет работать со всеми буферами обмена X. GTK+ поддерживает размещение данных в буферах обмена в нескольких форматах и отложенную запись.&lt;br /&gt;
&lt;br /&gt;
Организовать передачу данных между буфером обмена и экземпляром GtkTextBuffer очень просто. Ниже приводится текст обработчика сигнала меню copy1_activate нашего текстового редактора (этот сигнал генерирует команда Правка | Копировать).&lt;br /&gt;
&lt;br /&gt;
 void on_copy1_activate (GtkMenuItem * menuitem, gpointer user_data)&lt;br /&gt;
 {&lt;br /&gt;
 char * atom = gdk_atom_name(&amp;quot;CLIPBOARD&amp;quot;);&lt;br /&gt;
 GtkClipboard * cb = gtk_clipboard_get(atom);&lt;br /&gt;
 g_free(atom);&lt;br /&gt;
 gtk_text_buffer_copy_clipboard(textbuffer, cb);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Вызывая gtk_clipboard_get(), мы передаем этой функции X-атом, идентифицирующий буфер обмена, который мы хотим открыть, и получаем строку с именем атома с помощью функции gdk_atom_name(). Функция gtk_text_buffer_copy_clipboard() копирует в буфер обмена строку текста, выделенную в текстовом буфере GtkTextBuffer (программно или с помощью интерфейса пользователя). Первым параметром функции, копирующей данные, должен быть указатель на объект GtkTextBuffer, вторым параметром – указатель на объект GtkClipboard. Для вставки данных из буфера обмена в текстовый буфер применяется функция gtk_text_buffer_paste_clipboard(), которой, помимо прочего, следует передать итератор, указывающий, где именно в тексте должна быть вставлена строка из буфера обмена (при использовании текстового буфера вместе с GtkTextView вместо итератора функции можно передать NULL).&lt;br /&gt;
&lt;br /&gt;
Разумеется, у буфера обмена есть и собственный API, который можно применять независимо от других компонентов GTK+/GNOME. Для передачи в буфер обмена строки текста в общем случае используется функция gtk_clipboard_set_text(). Первым параметром этой функции должен быть указатель на объект GtkClipboard. Второй и третий параметры, соответственно, строка текста с нулевым конечным символом и длина строки в байтах (напомню, что в GTK+ и GNOME по умолчанию используется кодировка UTF-8). Для передачи в буфер обмена растрового графического объекта служит функция gtk_clipboard_set_image(). У этой функции всего два параметра: указатель на объект GtkClipboard и указатель на объект GdkPixBuf, содержащий данные растрового изображения.&lt;br /&gt;
&lt;br /&gt;
[[Image:Gtk 2.JPG|right|thumb|180px]]&lt;br /&gt;
&lt;br /&gt;
Если вы хотите поместить в буфер обмена данные в нескольких форматах или реализовать отложенную запись, все становится более сложным. В этом случае ваша программа должна объявить системе, что она готова передать в буфер обмена данные в определенных форматах и зарегистрировать функции обратного вызова, которые будут выполнять их фактическую обработку. Когда данные понадобятся, эти функции будут вызваны системой. Рассмотрим пример – фрагмент программы, копирующей в буфер строку текста:&lt;br /&gt;
&lt;br /&gt;
 void cb_get_func(GtkClipboard * clipboard, GtkSelectionData * selection_data, guint info, gpointer user_data)&lt;br /&gt;
 {&lt;br /&gt;
 char * str = &amp;quot;Данные для буфера обмена&amp;quot;;&lt;br /&gt;
 gtk_selection_data_set_text(selection_data, str, strlen(str));&lt;br /&gt;
 }&lt;br /&gt;
 void cb_clear_func(GtkClipboard * clipboard, gpointer user_data)&lt;br /&gt;
 {&lt;br /&gt;
 // Nothing to do&lt;br /&gt;
 }&lt;br /&gt;
 void on_copy1_activate (GtkMenuItem * menuitem, gpointer user_data)&lt;br /&gt;
 {&lt;br /&gt;
 static const GtkTargetEntry targets[] =&lt;br /&gt;
 { { &amp;quot;UTF8_STRING&amp;quot;, 0, GDK_TARGET_STRING } };&lt;br /&gt;
 char * atom = gdk_atom_name(&amp;quot;CLIPBOARD&amp;quot;);&lt;br /&gt;
 GtkClipboard * cb = gtk_clipboard_get(atom);&lt;br /&gt;
 g_free(atom);&lt;br /&gt;
 gtk_clipboard_set_with_data(cb, targets, 1, cb_get_func, cb_clear_func,&lt;br /&gt;
 NULL);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Виртуальная файловая система GNOME ===&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF99:Mono</id>
		<title>LXF99:Mono</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF99:Mono"/>
				<updated>2008-04-27T15:25:21Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: Шаблон:Цикл/Mono  AWB&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/Mono}}&lt;br /&gt;
&lt;br /&gt;
==Mono: Рецепты==&lt;br /&gt;
&lt;br /&gt;
За прошедший год '''Пол Хадсон''' рассказал нам о файловых системах, доступе к базе данных, графическом интерфейсе, XML и сетях. Пришло время расправить крылья...&lt;br /&gt;
&lt;br /&gt;
Дошло, что от вас требуется? Чтобы стать хорошим программистом, необходимо нечто большее, чем пристрастие к сандалиям и очки, держащиеся только на клейкой ленте. На самом деле, это острый ум, хорошая память, жадность до новых технологий и – бесспорно, самое важное – способность хранить часто используемые участки кода в голове, чтобы решать стандартные проблемы быстро. Многое тут вытекает из склада ума, но ум приходит с опытом: вы сталкиваетесь с проблемой, решаете ее и создаете личную библиотеку кода, позволяющую быстро сколачивать решения. Данный урок – последний в нашей серии учебников по Mono, поэтому мы сосредоточимся на кусках кода, способных помочь вам решить стандартные проблемы и извлечь преимущества из полезных технических приемов – пожалуйста, берите их и свободно используйте в своих проектах, под какой бы лицензией они не издавались.&lt;br /&gt;
&lt;br /&gt;
'''Проблема'''&lt;br /&gt;
&lt;br /&gt;
===Удалить в цикле несколько элементов из массива===&lt;br /&gt;
&lt;br /&gt;
Этот пример достаточно прост для затравки, но он ставит в тупик некоторых начинающих. Допустим, у вас есть объект '''List&amp;lt;string&amp;gt;''' с именем '''MyNames''', то есть он хранит массив строк. Поскольку это обобщенный тип данных, вам следует добавить '''using System.Collections.Generic'''; в  начало вашего файла проекта. И если вы хотите удалить из этого списка все имена, начинающиеся с '''&amp;quot;Mike&amp;quot;''', то первый вариант вашего кода может выглядеть так:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 for (int i = 0; i &amp;lt; MyNames.Count; ++i) {&lt;br /&gt;
   if (MyNames[i].StartsWith(&amp;quot;Mike&amp;quot;)) {&lt;br /&gt;
       MyNames.RemoveAt(i);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Или, если вы аккуратист, то так:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 foreach (string name in MyNames) {&lt;br /&gt;
    if (name.StartsWith(&amp;quot;Mike&amp;quot;)) {&lt;br /&gt;
       MyNames.Remove(name);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Но здесь налицо серьезная проблема: '''.NET''' не разрешает изменять массив, пока вы перемещаетесь по нему, то есть первый '''Mike''' будет удален, но цикл продолжится, и появится ошибка, потому что на самом деле вы сдвинули все элементы на одну позицию, и какой же элемент должен быть следующим в цикле? Приведенное решение вполне очевидно, если немного подумать: при перемещении по массиву в обратную сторону сдвиг элементов не имеет значения, потому что вы его уже обработали. Вот оно:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  for (int i = MyNames.Count – 1; i &amp;gt;= 0; --i) {&lt;br /&gt;
    if (MyNames[i].StartsWith(&amp;quot;Mike&amp;quot;)) {&lt;br /&gt;
       MyNames.RemoveAt(i);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Проблема'''&lt;br /&gt;
&lt;br /&gt;
===Округление чисел портит ваш код===&lt;br /&gt;
&lt;br /&gt;
По мере увеличения объема кода нарастает необходимость его чистки. Одной из наиболее раздражающих ловушек в коде на '''C#''' является '''Math.Round()''', потому что если вы захотите написать код &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  int foo = Math.Round(10.1f);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
он не сработает. О нет – вы получите сообщение об ошибке преобразования: '''Mono''' не умеет преобразовывать из '''double''' в '''int'''. Вы-то думали, что этот код преобразует число с плавающей точкой '''10.1''' в целое '''10''', но '''Math.Round()''' возвращает не целое – потому что если указать второй параметр, можно получить число, округленное до указанного знака после запятой.&lt;br /&gt;
&lt;br /&gt;
Конечно, это лишнее, если вам всего лишь надо преобразовать число с плавающей точкой в целое, поэтому я предлагаю создать такой небольшой метод:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  public int Round(float num) {&lt;br /&gt;
    return (int)Math.Round(num);&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вы можете использовать его так:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  int foo = Round(10.1f);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
      &lt;br /&gt;
Вам, вероятно, кажется, что можно и без него обойтись, но пред ставьте такой код:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  DrawRectangle((int)Math.Round(obj.x), (int)Math.Round(obj.y), (int)Math. Round(obj.w), (int)Math.Round(obj.h))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ну не уродство? Странно: в '''Java''' есть прекрасный метод '''Math.round()''', получающий '''float''', а возвращающий '''int''', а вот в '''C#''' требуется собственный код. Не опасайтесь снижения производительности за счет добавочного вызова функции: такой простой метод, вероятно, будет встроенным '''(inline)'''.&lt;br /&gt;
&lt;br /&gt;
'''Проблема'''&lt;br /&gt;
&lt;br /&gt;
===Сортировка массива экзотических данных===&lt;br /&gt;
&lt;br /&gt;
Стандартный класс '''List''' имеет метод '''Sort()''', который выстраивает строки и числа в определенном порядке, но он бесполезен, если вы храните объекты и хотите отсортировать их по определенному свойству. Однако вы можете сообщить '''Sort()''' имя сравнивающей функции, способной выполнять более продвинутую сортировку, а затем использовать ее обычным способом. Например, пусть у вас есть класс&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 public class User {&lt;br /&gt;
   public int ID;&lt;br /&gt;
   public string Name;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
и '''List''' [Список] этих пользователей, вроде такого:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 List&amp;lt;User&amp;gt; MyUsers = new List&amp;lt;User&amp;gt;();&lt;br /&gt;
 User user = new User();&lt;br /&gt;
 user.ID = 1;&lt;br /&gt;
 user.Name = &amp;quot;Paul&amp;quot;;&lt;br /&gt;
 MyUsers.Add(user);&lt;br /&gt;
 user = new User();&lt;br /&gt;
 user.ID = 10;&lt;br /&gt;
 user.Name = &amp;quot;Scott&amp;quot;;&lt;br /&gt;
 MyUsers.Add(user);&lt;br /&gt;
 user = new User();&lt;br /&gt;
 user.ID = 5;&lt;br /&gt;
 user.Name = &amp;quot;Mike&amp;quot;;&lt;br /&gt;
 MyUsers.Add(user);&lt;br /&gt;
 user = new User();&lt;br /&gt;
 user.ID = 50;&lt;br /&gt;
 user.Name = &amp;quot;Graham&amp;quot;;&lt;br /&gt;
 MyUsers.Add(user);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Сортируя его при помощи обычного старого '''Sort()''', вы получите ошибку, ибо '''.NET''' не умеет обращаться с объектами '''User'''. Но не так уж трудно написать собственный метод сравнения сложных объектов. А если вы предоставите его имя функции '''Sort()''', он будет вызываться для каждого сравнения двух объектов, чтобы решить, в каком порядке их расположить. Метод должен возвращать '''1''' (объект '''1''' должен следовать после объекта '''2'''), '''-1''' (объект '''2''' должен следовать за объектом '''1''') или '''0''' (объекты '''1''' и '''2''' равноправны). Он может выглядеть примерно так:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 private int CompareUserByID(User a, User b) {&lt;br /&gt;
   if (a.ID &amp;gt; b.ID) {&lt;br /&gt;
      return 1;&lt;br /&gt;
   } else if (a.ID &amp;lt; b.ID) {&lt;br /&gt;
      return -1;&lt;br /&gt;
   } else {&lt;br /&gt;
      return 0;&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Затем сортируйте ваш массив, используя&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 MyUsers.Sort(CompareUserByID);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь все элементы будут переставлены. Приведенный способ показывает, как создать свою собственную систему сортировки для любого типа данных, но встроенные типы данных – '''int, string''' и т.п. – можно сравнивать еще проще. Все эти типы имеют специальный метод '''CompareTo()''', принимающий в качестве единственного параметра другой идентичный тип и возвращающий вам '''1''', '''-1''' или '''0'''. Поэтому, если хотите, можете написать метод '''CompareUserByName()''' вот так:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 private int CompareUserByName(User a, User b) {&lt;br /&gt;
   return a.Name.CompareTo(b.Name);&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Проблема'''&lt;br /&gt;
&lt;br /&gt;
===Перемешать элементы массива случайным образом===&lt;br /&gt;
&lt;br /&gt;
'''.NET''' имеет несколько способов манипуляции массивами, но ни один из них не столь сжат, как функция '''shuffle()''' в '''PHP:''' даете ей массив и получаете обратно перемешанный. Вы можете скопировать ее одним из двух способов – в зависимости от того, хотите ли вы потренироваться или выглядеть круче!&lt;br /&gt;
&lt;br /&gt;
Простой путь перемешать массив таков:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  public void ShuffleList(List&amp;lt;string&amp;gt; list) {&lt;br /&gt;
    Random rand = new Random();&lt;br /&gt;
    for (int i = 0; i &amp;lt; list.Count; i++) {&lt;br /&gt;
        string tmp = list[i];&lt;br /&gt;
        list.RemoveAt(i);&lt;br /&gt;
        list.Insert(rand.Next(0, list.Count), tmp);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
В цикле перемещаемся по массиву, удаляя каждый элемент и вставляя его в случайную позицию. Заметьте: код генерирует случайное число, используя новый объект '''Random''' при каждом вызове метода; это лучше, чем создание одного объекта '''Random''' для всей программы.&lt;br /&gt;
&lt;br /&gt;
Итак, вот схема перемешивания: взять '''List''', содержащий строки, и перемешать их случайным образом. А если вы захотите перемешать массив целых чисел? Или объектов '''User'''? Или чего угодно, но не строк? Можно, конечно, создать несколько методов '''ShuffleList()''', но это недальновидное решение: ваш код очень скоро раздуется. Намного лучше использовать стандарты, создав функцию, которая принимает список любого типа и перемешивает содержимое. Тут требуется некий специальный синтаксис '''C#''', потому что вам необходимо сообщить своему методу, что он будет принимать неизвестный тип и использовать этот тип для всех данных. Обычно на обобщенные типы ссылаются как на '''T''' или '''T1, T2''' и т.д., если их более одного. Итак, метод '''ShuffleList()''' можно переписать так:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  public void ShuffleList&amp;lt;T&amp;gt;(List&amp;lt;T&amp;gt; list) {&lt;br /&gt;
      Random rand = new Random();&lt;br /&gt;
      for (int i = 0; i &amp;lt; list.Count; i++) {&lt;br /&gt;
          T tmp = list[i];&lt;br /&gt;
          list.RemoveAt(i);&lt;br /&gt;
          list.Insert(rand.Next(0, list.Count), tmp);&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Когда вы используете '''ShuffleList(MyUsers)''', '''.NET''' по сути заменяет в этом методе «'''Т'''» на «'''User'''», т.е. '''ShuffleList()''' принимает '''List&amp;lt;User&amp;gt;''', а переменная '''tmp''' получает тип '''User'''. Итак, вы можете вызвать '''ShuffleList()''' со списком '''[List]''' строк, целых чисел, дробных, логических, людей, рыбок или данных любого другого типа, какой сможете придумать.&lt;br /&gt;
&lt;br /&gt;
'''Проблема'''&lt;br /&gt;
&lt;br /&gt;
===Узнать, когда один объект находится над другим===&lt;br /&gt;
&lt;br /&gt;
Это весьма общая формулировка, а вот конкретный пример: вы хотите знать, когда мышь находится над нарисованным вами объектом. Проблема решается очень просто: все, что надо сделать – это проверить, что координаты мыши больше, чем позиция '''X''' и '''Y''' вашего объекта, и меньше чем '''X''', '''Y + ширина и высота объекта'''. Вчерне можно записать подобный метод так:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 public bool PointOverRect(int x1, int y1, int x2, int y2, int width, int height) {&lt;br /&gt;
   if (x1 &amp;gt;= x2 &amp;amp;&amp;amp; x1 &amp;lt;= x2 + width) {&lt;br /&gt;
      if (y1 &amp;gt;= y2 &amp;amp;&amp;amp; y1 &amp;lt;= y2 + height) {&lt;br /&gt;
         return true;&lt;br /&gt;
      }&lt;br /&gt;
   }&lt;br /&gt;
   return false;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для использования этого метода передайте координаты '''X''' и '''Y''' мыши в качестве первых двух параметров, затем '''X''', '''Y''', ширину и высоту вашего объекта в качестве вторых параметров. Конечно, реально это работает только для прямоугольных объектов, но создавайте прямоугольные рамки вокруг объектов другой формы, и все будет хорошо.'''[для фигур произвольной формы часто в качестве второго входного параметра используется массив координат узлов контура, ограничивающего объект или, если контур является геометрической фигурой, то ее атрибуты, например, центр и радиус окружности, – прим. пер.]'''&lt;br /&gt;
&lt;br /&gt;
В принципе, можно взять этот простой метод и подстроить под свои личные цели. Например, вы могли бы захотеть добавить поддержку вращения ограничивающей рамки. Если все, что вам надо, это стандартная функция проверки нахождения точки в прямоугольнике, используйте метод '''Contains()''' вашего прямоугольника и передайте ему точку.&lt;br /&gt;
&lt;br /&gt;
'''Проблема'''&lt;br /&gt;
&lt;br /&gt;
===Нужно узнать, перекрываются ли два объекта===&lt;br /&gt;
&lt;br /&gt;
Еще одна общая проблема, так что снова поясню на примере: вы хотите реализовать проверку столкновений в игре. Это очень похоже на проверку, принадлежит ли точка прямоугольнику, особенно если использовать метод '''Contains()'''. Однако, хотя '''Contains()''' и может принимать объект '''Rectangle''' в качестве параметра, он возвращает '''true''', если один прямоугольник полностью лежит внутри другого, а не просто пересекает его, а для обнаружения столкновений вам необходимо последнее.&lt;br /&gt;
&lt;br /&gt;
К счастью, для прямоугольников есть другой небольшой полезный метод, под названием '''Intersect()''', который накладывает один прямоугольник на другой и возвращает новый прямоугольник-пересечение, и вы можете проверить его ширину и высоту, чтобы понять, имеет ли место пересечение. Простой и легкий способ проверки столкновений – вот такой метод:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  public bool RectOverRect(int x1, int y1, int width1, int height1, int x2, int y2, int width2, int height2) {&lt;br /&gt;
    Rectangle rectthis = new Rectangle(x1, y1, width1, height1);&lt;br /&gt;
    Rectangle rectthat = new Rectangle(x2, y2, width2, height2);&lt;br /&gt;
    rectthis.Intersect(rectthat);&lt;br /&gt;
    if (rectthis.Width == 0 &amp;amp;&amp;amp; rectthis.Height == 0) {&lt;br /&gt;
       return false;&lt;br /&gt;
    } else {&lt;br /&gt;
       return true;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Проблема'''&lt;br /&gt;
&lt;br /&gt;
===Обработка ошибок при их возникновении===&lt;br /&gt;
&lt;br /&gt;
Я не затрагивал старый добрый блок '''try/catch''' в нашей серии, но теперь настало время это сделать! Система '''try/catch''' позволяет выполнять команды и предпринимать заданные действия, если возникла ошибка. Например, вы можете написать:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  try {&lt;br /&gt;
           SomeDangerousMethodCall();&lt;br /&gt;
  } catch (Exception e) {&lt;br /&gt;
           Console.WriteLine(&amp;quot;Ой!&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обычно ошибка в '''SomeDangerousMethod()''' приводит к краху программы, но использование '''try/catch''' означает, что такая ошибка в '''SomeDangerousMethod()''' вернет управление в вызывающий код, с последующей передачей блоку '''catch''', а тот выведет «Ой!», элегантно обработав вашу ошибку. Это не повод становиться программистом-неряхой, потому что код обработки исключений вроде этого здорово тормозит – уж лучше заранее выполнять проверки в коде!&lt;br /&gt;
&lt;br /&gt;
Вы можете перехватывать несколько типов исключительных ситуаций, добавив новые блоки '''catch'''; выполнится лишь один, соответствующий конкретному исключению; а если возможны непредвиденные ситуации, следует, вероятно, добавить общий обработчик '''Exception''' – это базовый класс всех исключительных ситуаций, соответствующий всем исключениям вообще.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 try {&lt;br /&gt;
    DangerousMethod();&lt;br /&gt;
  } catch (DllNotFoundException e) {&lt;br /&gt;
    Console.WriteLine(&amp;quot;Ой - отсутствует необходимая DLL!&amp;quot;);&lt;br /&gt;
  } catch (FileNotFoundException e) {&lt;br /&gt;
    Console.WriteLine(&amp;quot;Ой - отсутствует необходимый файл!&amp;quot;);&lt;br /&gt;
  } catch (Exception e) {&lt;br /&gt;
    Console.WriteLine(&amp;quot;Ой - произошла ошибка!&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Преимущество соответствия конкретному исключению в том, что вы получаете дополнительные данные для обработки. Например, '''FileNotFoundException''' имеет свойство '''FileName''', которое подскажет, какой файл отсутствует.&lt;br /&gt;
&lt;br /&gt;
В истинно устойчивой как скала программе следует использовать блоки '''try/catch''' почаще – при желании их даже можно вкладывать друг в друга, чтобы предусмотреть самые причудливые ошибки. Предусмотрены исключения для всех сортов типичных проблем: '''OutOfMemoryExceptions, AccessViolationException''' и немаловажное '''NullReferenceException'''. Не скупитесь на проверки!&lt;br /&gt;
&lt;br /&gt;
===И, наконец, finally...===&lt;br /&gt;
&lt;br /&gt;
{{Врезка&lt;br /&gt;
    |Заголовок=Идем дальше&lt;br /&gt;
    |Содержание=Ну-с, '''Mono'''-маны, это конец: надеюсь, вы попытались завершить хотя бы один из наших проектов, потому что лучший способ обучения – это пытаться делать что-то самому, менять код под ваши нужды, создавать библиотеки идей и кода для выполнения ваших заказов. Берите код и технические приемы, описанные выше, и применяйте их в вашей работе – да сообщите мне, как ваши дела!&lt;br /&gt;
    |Ширина=200px}}&lt;br /&gt;
&lt;br /&gt;
Было бы неверно описать '''try/catch''', не сказав об его кузене '''try/finally'''. Он используется намного реже, чем '''try/catch''', вследствие общего заблуждения, что в '''.NET'''-коде незачем беспокоиться об управлении памятью. Что ж, вот вам изящный поворот: всякий раз, когда вы беретесь за собственный код, будьте с памятью поосторожнее. Объекты, классы и ресурсы '''.NET''' все под контролем, то есть автоматически освобождаются, когда больше не нужны, но собственные ресурсы – например, '''3D'''-текстуры, загруженные вами в '''OpenGL''' – не управляемы, и о них необходимо позаботиться вам. Блок '''try/finally''' разработан, чтобы обезопасить управление памятью, путем насильственного выполнения заданного блока кода, невзирая ни на что. Это полезно даже помимо управления памятью, потому что вы будете уверены, что определенный метод вызовется перед тем, как объект будет освобожден.&lt;br /&gt;
&lt;br /&gt;
Перейдем от теории к практике на примере: когда клиент подключается к вашему серверу, вы хотите отослать ему текст приветствия, прочитать какой-то текст, отправить текст-прощание, затем закрыть сокет. Посмотрите этот код:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  function ClientConnect(MySocket sock) {&lt;br /&gt;
         try {&lt;br /&gt;
                 sock.SendHello();&lt;br /&gt;
                 sock.ReadMessage();&lt;br /&gt;
                 sock.SendGoodbye();&lt;br /&gt;
         } catch (Exception e) {&lt;br /&gt;
                 Console.WriteLine(&amp;quot;При подключении клиента возникла ошибка.&amp;quot;);&lt;br /&gt;
         }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вам этот код может показаться вполне пригодным, но вдруг в процессе чтения возникнет ошибка – предположим, клиент отправит неправильно оформленное сообщение? Вот что произойдет:&lt;br /&gt;
*1 Вызов '''SendHello()'''&lt;br /&gt;
*2 Вызов '''ReadMessage()'''&lt;br /&gt;
*3 Возникло исключение&lt;br /&gt;
*4 Вызов '''Console.WriteLine()'''&lt;br /&gt;
*5 Метод завершился&lt;br /&gt;
&lt;br /&gt;
Как видите, в этой последовательности событий нет '''SendGoodbye()''', то есть сообщение-прощание никогда не будет отослано. Если клиент ожидает его, или сервер использует этот метод для выполнения некой очистки собственных ресурсов, тогда у вас проблема. Тут-то и выходит на сцену '''try/finally''', потому что он в общем гарантирует, что определенный блок кода вызовется при любом раскладе. Перепишем предыдущий пример:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  void ClientConnect(MySocket sock) {&lt;br /&gt;
         try {&lt;br /&gt;
                  try {&lt;br /&gt;
                          sock.SendHello();&lt;br /&gt;
                          sock.ReadMessage();&lt;br /&gt;
                    } catch (Exception e) {&lt;br /&gt;
                             Console.WriteLine (&amp;quot;При подключении клиента возникла ошибка.&amp;quot;);&lt;br /&gt;
                    }&lt;br /&gt;
         } finally {&lt;br /&gt;
                    sock.SendGoodbye();&lt;br /&gt;
         }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Даже если в '''SendHello()''' или в '''ReadMessage()''' возникнет исключение, '''SendGoodbye''' все равно будет вызван. На самом деле, работает даже нечто вроде этого:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  void ClientConnect(MySocket sock) {&lt;br /&gt;
         try {&lt;br /&gt;
                    sock.SendHello();&lt;br /&gt;
                    sock.ReadMessage();&lt;br /&gt;
                    return;&lt;br /&gt;
         } finally {&lt;br /&gt;
                    sock.SendGoodbye();&lt;br /&gt;
         }&lt;br /&gt;
  }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вызов '''return''' должен бы привести к немедленному выходу из метода, да и приводит – но '''.NET''' все-таки сначала выполняет все блоки '''finally'''. Даже старый метод '''Environment.Exit()''' находит время для вызова блоков '''finally''' перед завершением программы – а если вы не хотите, чтобы ваш блок '''finally''' выполнился (поэтому я и сказал, что блоки '''finally''' «в общем гарантируют», а не «абсолютно гарантируют» выполнение блока кода), используйте метод '''Environment.FailFast()'''. '''LXF'''&lt;br /&gt;
&lt;br /&gt;
===Перехватываемые исключения===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! &lt;br /&gt;
! &lt;br /&gt;
|-&lt;br /&gt;
| AccessViolationException&lt;br /&gt;
| Возникает, когда вы пытаетесь записать в область памяти только для чтения.&lt;br /&gt;
|-&lt;br /&gt;
| ArgumentNullException&lt;br /&gt;
| Возникает, когда метод требует аргументы, а вы случайно передаете ему null.&lt;br /&gt;
|-&lt;br /&gt;
| DivideByZeroException&lt;br /&gt;
| Деление любых чисел на ноль – табу в любом языке программирования; перехватывается здесь!&lt;br /&gt;
|-&lt;br /&gt;
| DllNotFoundException&lt;br /&gt;
| Когда .NET создает ссылки на несуществующие родные библиотеки, возникает это исключение.&lt;br /&gt;
|-&lt;br /&gt;
| Exception&lt;br /&gt;
| Дедушка всех исключений; хорош для перехвата, когда вы не представляете, что может произойти.&lt;br /&gt;
|-&lt;br /&gt;
| IndexOutOfRangeException&lt;br /&gt;
| Возникает при выходе за границы и попытке чтения несуществующего элемента массива.&lt;br /&gt;
|-&lt;br /&gt;
| NullReferenceException&lt;br /&gt;
| Вы получаете это при попытке читать из несозданного объекта.&lt;br /&gt;
|-&lt;br /&gt;
| OutOfMemoryException&lt;br /&gt;
| Системе не хватает памяти, и, вероятно, ваша программа будет закрыта.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF98:Mono</id>
		<title>LXF98:Mono</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF98:Mono"/>
				<updated>2008-04-27T15:25:08Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: Шаблон:Цикл/Mono  AWB&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/Mono}}&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;font color=darkred&amp;gt;Mono:&amp;lt;/font&amp;gt; Назад в Unix==&lt;br /&gt;
&lt;br /&gt;
''Хотя C# и новый, и передовой, Mono стоит на плечах уродливого монстра Posix.&lt;br /&gt;
'''Пол Хадсон''' пробует заставить Unix-натуру Linux сработаться с .NET...''&lt;br /&gt;
&lt;br /&gt;
Имеет ли место садомазохизм в мире компьютеров? Если да, то вот он: я покажу вам, как заставить C# идти бок о бок с Posix и выиграть. Да, Posix – этот дурно задуманный процесс стандартизации, сбивающий с толку программистов, игнорируемый конечными пользователями, и все же подпирающий Linux и другие&lt;br /&gt;
Unix-подобные ОС. Posix – это набор системных вызовов, интерфейсов и сигналов, определяющий, как мы, разработчики, взаимодействуем с операционной системой. Действующий стандарт Posix весьма обширен, но по сути мы должны заботиться только вот о чем: если вы пишете Posix-совместимый код, он должен работать в любой Posix-совместимой ОС.&lt;br /&gt;
&lt;br /&gt;
Как ни странно, список совместимости включает Windows Vista, точнее, большинство основанных на NT версий Windows, коль скоро они имеют установленными службы Services for Unix. Но с нашей точки зрения важно то, что Linux, FreeBSD, OpenBSD и Syllable практически, а AIX, HP-UX, Minix, OS X и Solaris – полностью поддерживают Posix. Короче, использование функциональности Posix может заставить вас рвать на себе волосы, но, по крайней мере, вы в хорошей компании!&lt;br /&gt;
&lt;br /&gt;
===Posix и вы===&lt;br /&gt;
&lt;br /&gt;
Имеется два типа людей, в основном использующих Posix: конечные пользователи и разработчики. Значит, практически все! Рассмотрим каждый тип отдельно, начав с пользователя. Да, я помню свои слова, что конечный пользователь игнорирует Posix, но это не совсем верно – фактически, вы используете преимущества инструментов и интерфейсов Posix при каждом обращении к командной строке. Видите ли, Posix заправляет едва ли не всем, что даруют Unix-подобные операционные системы – как работает ваша командная строка, есть ли инструменты типа awk и компиляторов, как происходит взаимодействие программ через каналы. Пусть даже конечные пользователи ничего не знают и знать не хотят о Posix, они обязательно опираются на его набор функций! Что касается разработчиков, то любой из пишущих код на С должен работать с одним из многих интерфейсов ядра и вызовами стандартной библиотеки С, входящими в Posix, и эти функции – например, &amp;lt;font color=darkred&amp;gt;malloc&amp;lt;/font&amp;gt;, &amp;lt;font color=darkred&amp;gt;system&amp;lt;/font&amp;gt;, &amp;lt;font color=darkred&amp;gt;printf&amp;lt;/font&amp;gt;, &amp;lt;font color=darkred&amp;gt;fopen&amp;lt;/font&amp;gt; и другие – доступны везде, куда ни сунься.&lt;br /&gt;
&lt;br /&gt;
Это ставит нас перед вопросом: «Какой прок в использовании Posix?» Общеизвестно, что все системные вызовы Posix скопированы в стандарте среды .NET, с использованием управляемых эквивалентов: вы можете читать и записывать файлы, работать со строками, открывать сокеты, читать данные файловой системы и так далее, не беспокоясь о распределении памяти, потому что .NET освободит все, когда сработает сборщик мусора. Но использование версий Posix дает некоторые преимущества:&lt;br /&gt;
&lt;br /&gt;
# Унаследованный код очень легко портировать. Вы можете взять код на C и запросто перенести его на C#, затем, при добавлении новых функций, добавить расширенную функциональность, присущую C#.&lt;br /&gt;
# В том же русле: для C-программистов вполне очевидно, что делает код C# Posix, а это облегчает изучение и сопровождение.&lt;br /&gt;
# Вы можете использовать преимущества специфичной для Posix функциональности. Например, чтение данных из файла '''/etc/passwd''' в обычном .NET коде необходимо делать вручную, а с использованием инструментов Posix это раз плюнуть.&lt;br /&gt;
&lt;br /&gt;
Итак, использование Posix не лишено преимуществ, но вдобавок имеется одно большое неудобство: львиная доля Posix работает с указателями.&lt;br /&gt;
&lt;br /&gt;
«Указатели?» Так и слышу, как вы охнули. «Привет! Говорят 1980-е! Они требуют обратно свой безумный, анахроничный, осложненный переполнениями буфера доступ к памяти!» Именно так. Указатели – это программные имена, описывающие конкретный участок памяти. Например, переменная – указатель на строку содержит точный адрес в памяти, где располагается строка текста. Понятно, что это прекрасно для быстродействия, так как между программой и оборудованием нет посредников, но ужасно с точки зрения безопасности, потому что программа имеет полную власть над вашим компьютером: даже крошечная щелочка в безопасности может вылиться в захват системы. Теперь, когда вы знаете все о плюсах и минусах Posix, давайте нырнем в него и посмотрим, что тут можно сделать...&lt;br /&gt;
&lt;br /&gt;
===Базируемся на Stdlib===&lt;br /&gt;
&lt;br /&gt;
Имеется три компонента для поддержки Unix в Mono: &amp;lt;font color=darkred&amp;gt;Mono.Posix&amp;lt;/font&amp;gt;, &amp;lt;font color=darkred&amp;gt;Mono.Unix&amp;lt;/font&amp;gt; и &amp;lt;font color=darkred&amp;gt;Mono.Unix.Native&amp;lt;/font&amp;gt;. Два последних отличаются лишь тем, что &amp;lt;font color=darkred&amp;gt;Mono.Unix&amp;lt;/font&amp;gt; – это небольшая обертка для &amp;lt;font color=darkred&amp;gt;Mono.Unix.Native&amp;lt;/font&amp;gt;, но вы можете использовать ту, где вам комфортнее.&lt;br /&gt;
&lt;br /&gt;
Начнем с простого: создадим новое решение под названием &amp;lt;font color=darkred&amp;gt;Monix&amp;lt;/font&amp;gt;, затем изменим его код '''Main.cs''' так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
 using Mono.Posix;&lt;br /&gt;
 using Mono.Unix;&lt;br /&gt;
 using Mono.Unix.Native;&lt;br /&gt;
 using System;&lt;br /&gt;
 using System.Text;&lt;br /&gt;
 namespace monix {&lt;br /&gt;
    class Monix {&lt;br /&gt;
     public static void Main(string[] args) {&lt;br /&gt;
       Stdlib.system(&amp;quot;ls&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
   }&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Этот простой код – основа для всех дальнейших: будем изменять только строку &amp;lt;font color=darkred&amp;gt;Stdlib.system()&amp;lt;/font&amp;gt; да добавлять кое-какие кусочки.&lt;br /&gt;
Проверьте наличие Mono.Posix и добавьте ссылку на него в проект. В нашем первом методе мы воспользуемся классом &amp;lt;font color=darkred&amp;gt;Stdlib&amp;lt;/font&amp;gt; для вызова &amp;lt;font color=darkred&amp;gt;system()&amp;lt;/font&amp;gt;. Класс &amp;lt;font color=darkred&amp;gt;Stdlib&amp;lt;/font&amp;gt; содержит, в основном, статические методы, то есть вам не нужно создавать объект &amp;lt;font color=darkred&amp;gt;Stdlib&amp;lt;/font&amp;gt; для вызова этих методов. Метод &amp;lt;font color=darkred&amp;gt;system()&amp;lt;/font&amp;gt; (следите за регистром &amp;lt;font color=darkred&amp;gt;s&amp;lt;/font&amp;gt; – он нижний: сейчас мы в стране С!) исполняет любую команду на локальной машине, словно он был введен в командной строке. Для нашего примера это означает запуск ls, поэтому программа выведет список каталогов, как если бы вы сами запустили «ls».&lt;br /&gt;
&lt;br /&gt;
После ввода &amp;lt;font color=darkred&amp;gt;Stdlib.system()&amp;lt;/font&amp;gt;, MonoDevelop должна вывести информацию о параметрах метода &amp;lt;font color=darkred&amp;gt;system()&amp;lt;/font&amp;gt;, и вы увидите, что он принимает строки C#. В этом месте разработчики Mono адаптировали библиотеку вызовов C для лучшей совместимости с программированием .NET – обычно, в терминах С, &amp;lt;font color=darkred&amp;gt;system()&amp;lt;/font&amp;gt; получает &amp;lt;font color=darkred&amp;gt;const char*&amp;lt;/font&amp;gt;, так что использование строк более изящно!&lt;br /&gt;
&lt;br /&gt;
Этот переход существует лишь в некоторых методах. Например, &amp;lt;font color=darkred&amp;gt;printf()&amp;lt;/font&amp;gt; также дружественен к .NET, поэтому вы можете писать код вроде этого:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
 Stdlib.printf(&amp;quot;Hello, %s!\n&amp;quot;, &amp;quot;world&amp;quot;);&lt;br /&gt;
 Stdlib.printf(string.Format(&amp;quot;Hello, {0}!\n&amp;quot;, &amp;quot;world&amp;quot;));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
С другой стороны, методы &amp;lt;font color=darkred&amp;gt;fopen()&amp;lt;/font&amp;gt;, &amp;lt;font color=darkred&amp;gt;fwrite()&amp;lt;/font&amp;gt; и &amp;lt;font color=darkred&amp;gt;fclose()&amp;lt;/font&amp;gt; для работы с файлами требуют указателей. В C# указатели известны как &amp;lt;font color=darkred&amp;gt;IntPtr&amp;lt;/font&amp;gt;, потому что это представление указателя в целочисленном типе данных. Эти &amp;lt;font color=darkred&amp;gt;IntPtr&amp;lt;/font&amp;gt;'ы могут восприниматься как данные с неизвестной структурой: их нельзя прочесть без использования специфичных для этих данных методов. Например, файлы открываются так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
 IntPtr foo = Stdlib.fopen(&amp;quot;file.txt&amp;quot;, &amp;quot;w&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Но вы не можете читать или записывать с этого файлового дескриптора без других методов &amp;lt;font color=darkred&amp;gt;Stdlib. foo IntPtr&amp;lt;/font&amp;gt; – всего лишь дескриптор данных, и сам по себе бесполезен. На самом деле, это даже небезопасно: любая память, присвоенная указателю, недоступна сборщику мусора Mono, и необходимо освобождать ее вручную, не то образуется утечка [memory leak]. Вы можете выполнить запись в этот файл, затем закрыть его так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
 Stdlib.fwrite(Encoding.ASCII.GetBytes(&amp;quot;Hello, world!&amp;quot;), foo);&lt;br /&gt;
 Stdlib.fclose(foo);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
===Развернем обертки===&lt;br /&gt;
&lt;br /&gt;
Как указывалось ранее, Mono предоставляет набор упрощенных оберток для базовых структур данных и системных вызовов Unix. Например,&lt;br /&gt;
любую информацию о пользователе можно прочесть, создав объект UnixUserInfo таким образом:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
 UnixUserInfo user = new UnixUserInfo(&amp;quot;paul&amp;quot;);&lt;br /&gt;
 Console.WriteLine(user.HomeDirectory);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Класс &amp;lt;font color=darkred&amp;gt;UnixUserInfo&amp;lt;/font&amp;gt; читает информацию из '''/etc/passwd''', и вы можете увидеть имя пользователя, информацию о группах, их командных оболочках и так далее. Подобные структуры существуют и для файловых систем – следующая строка кода выудит информацию о вашем корневом каталоге:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
 UnixDriveInfo drive = new UnixDriveInfo(&amp;quot;/&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Затем вы можете узнать объем свободного пространства на диске, прочитав &amp;lt;font color=darkred&amp;gt;drive.AvailableFreeSpace&amp;lt;/font&amp;gt;. Это число возвращается в байтах, поэтому вы можете пожелать удобства ради преобразовать его в гигабайты:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
 Console.WriteLine(drive.AvailableFreeSpace / 1024 / 1024 / 1024.0);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Последнее &amp;lt;font color=darkred&amp;gt;1024&amp;lt;/font&amp;gt; записано как &amp;lt;font color=darkred&amp;gt;1024.0&amp;lt;/font&amp;gt;, потому что это заставит Mono преобразовать конечный результат в число с плавающей точкой, а не в целое – в противном случае результат не будет точным!&lt;br /&gt;
&lt;br /&gt;
Иногда эти обертки имеют собственные методы, как в случае с &amp;lt;font color=darkred&amp;gt;UnixFileInfo&amp;lt;/font&amp;gt; – она читает информацию о конкретных файлах, предоставляя вам такие методы, как &amp;lt;font color=darkred&amp;gt;CanAccess()&amp;lt;/font&amp;gt;, но, что более важно, позволяет создавать символьные ссылки на файл путем вызова функции &amp;lt;font color=darkred&amp;gt;CreateSymbolicLink()&amp;lt;/font&amp;gt;, примерно так:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
 UnixFileInfo file = new UnixFileInfo(&amp;quot;file.txt&amp;quot;);&lt;br /&gt;
 file.CreateSymbolicLink(&amp;quot;filesym.txt&amp;quot;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
создаст ссылку '''filesym.txt''' на '''file.txt''', как если бы вы выполнили ''ln -s file.txt filesym.txt'' в командной строке.&lt;br /&gt;
&lt;br /&gt;
===Звенит сигнал тревоги===&lt;br /&gt;
&lt;br /&gt;
Последний метод, который я хочу показать – &amp;lt;font color=darkred&amp;gt;signal()&amp;lt;/font&amp;gt;, он просто показывает, насколько хорошо интегрированы Mono и библиотека C: вы можете попросить Linux вызвать метод C# при поступлении любого сигнала. «Сигнал» в стране C – это то, что происходит, когда ОС пытается по каким-то причинам прервать программу. Например, нажатие Ctrl+C посылает программе &amp;lt;font color=darkred&amp;gt;SIGINT&amp;lt;/font&amp;gt;, что обычно приводит к выходу. А если вы не хотите, чтобы программа завершалась? Что ж, тогда потрудитесь сообщить C#, как поступать при получении &amp;lt;font color=darkred&amp;gt;SIGINT&amp;lt;/font&amp;gt;, и это делается при помощи метода &amp;lt;font color=darkred&amp;gt;signal()&amp;lt;/font&amp;gt;. Он принимает два параметра: сигнал, который вы хотите перехватить, и имя функции, вызываемой при получении сигнала.&lt;br /&gt;
&lt;br /&gt;
Говоря о &amp;lt;font color=darkred&amp;gt;SIGINT&amp;lt;/font&amp;gt; – вот код, который необходимо ввести в программе, чтобы она не отвечала на &amp;lt;font color=darkblue&amp;gt;Ctrl+C&amp;lt;/font&amp;gt;:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
 Stdlib.signal(Mono.Unix.Native.Signum.SIGINT, HandleSigInt);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&amp;lt;font color=darkred&amp;gt;HandleSigInt&amp;lt;/font&amp;gt; – новый метод, который необходимо создать за пределами &amp;lt;font color=darkred&amp;gt;Main()&amp;lt;/font&amp;gt;. Вот пример:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
 public static void HandleSigInt(int sig) {&lt;br /&gt;
    Console.WriteLine(&amp;quot;А я против!\n&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Теперь при нажатии &amp;lt;font color=darkblue&amp;gt;Ctrl+C&amp;lt;/font&amp;gt; пользователь получит сообщение-отказ; но это не остановит сигнал &amp;lt;font color=darkred&amp;gt;SIGKILL&amp;lt;/font&amp;gt; (посылаемый, когда кто-то выполняет &amp;lt;font color=darkred&amp;gt;kill -9 &amp;lt;ваш pid&amp;gt;&amp;lt;/font&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Конечно, вы не сможете протестировать обработку вашей программой сигналов прерывания, пока не заставите ее работать бесконечно:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
 System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
На этом наш блиц-тур по интеграции Mono и Unix закончен. Пожалуйста, не забывайте о потенциальных проблемах: утечки памяти – особенно в длительно работающих программах – могут вызвать серьезные осложнения, а привычка работы с Mono способствует небрежному обращению с памятью. Применение родных функций Unix делает миграцию с C на C# быстрой и простой, но в долгосрочной перспективе лучше начать вытеснять функции C-эквивалентами, родными для .NET...&lt;br /&gt;
&lt;br /&gt;
==Врезки==&lt;br /&gt;
&lt;br /&gt;
===Скорая помощь===&lt;br /&gt;
&lt;br /&gt;
*Не пытайтесь проигнорировать сигнал &amp;lt;font color=darkred&amp;gt;SIGKILL&amp;lt;/font&amp;gt; – все равно не удастся: в противном случае некоторые программы никогда не завершались бы!&lt;br /&gt;
&lt;br /&gt;
*Используя &amp;lt;font color=darkred&amp;gt;system()&amp;lt;/font&amp;gt; и аргументы, переданные вашей функции, вы можете за минуты сколотить быструю оболочку. Начните с пересылки всего переданного в &amp;lt;font color=darkred&amp;gt;system()&amp;lt;/font&amp;gt; и продвигайтесь далее, обрабатывая аргументы и по желанию добавляя собственную функциональность.&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF95:Mono</id>
		<title>LXF95:Mono</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF95:Mono"/>
				<updated>2008-04-27T15:24:54Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: Шаблон:Цикл/Mono  AWB&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/Mono}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: justify;&amp;quot;&amp;gt;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;''Едва вы начинаете делать что-нибудь интересное, XML сразу же становится медленным и громоздким, и '''Пол Хадсон''' думает, что пора взяться за работу с базами данных...'' &lt;br /&gt;
=== Mono-Мания ===&lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Программирование на современной платформе для новичков Mono-Мания Программирование на современной платформе для новичков Поскольку это — последний номер, который попадет к редакто- ру Ребекке, скажу не таясь: пишет она уж больно мелко. Когда мы возвращаемся из отпуска, на наших столах нас ждут ков- ры из желтых листков-наклеек для заметок, покрытых неразборчивыми каракулями. На вид сущая грязь, пока вы не вооружитесь лупой и не раз- глядите ее аккуратный почерк. Конечно, потом начинается надсадная для глаз работа – читать все эти записки, а ведь можно было обойтись всего лишь SQL-запросом, в стиле SELECT Значимое FROM ЗапискиРебекки Наш эксперт WHERE Приоритетность!=Не относится к делу. Увы, все попытки заставить Ребекку взаимодействовать через базу данных потерпели крах, и теперь она ищет другую работу. Но вы-то все еще здесь, верно? Значит, у меня есть время, чтобы подсадить вас на SQL, прежде чем вы заскучаете от Mono и перейдете к разделу Hardcore Linux!&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;На этом уроке мы напишем небольшой инструмент, способный следить за всеми Mono-программами, которые вы создали на протяжении всей нашей серии. Каждые десять секунд программа будет опрашивать Mono о списке всех активных приложений, а затем сохранять этот список в базе данных. Мы получим шанс изучить два новых аспекта Mono: чтение информации о процессах и доступ к базе данных. Этот проект – еще одна звездочка вам на погоны! Как и для всех наших Monoпроектов, потребуется среда исполнения .NET 2.0; убедитесь, что вы ее включили, через диалог Project &amp;gt; Options &amp;gt; Runtime Options.&lt;br /&gt;
=== Чтение процессов ===&lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Начните новый консольный проект в MonoDevelop и дайте ему имя Monocular. Первым делом надо прочесть список всех процессов, работающих в Mono, и вывести информацию на экран. Решить эту задачу довольно просто, благодаря пространству имен System.Diagnostics, которое дает доступ к россыпям внутренней системной информации. &lt;br /&gt;
Нас интересует класс Process, позволяющий читать информацию о запущенной программе. Помните, что «программа» – это исполняемый код на диске (например, Vim), а «процесс» – экземпляр программы, который в данный момент работает. То есть если вы запустите Vim шесть раз, в оперативной памяти будет шесть процессов Vim, но программ от этого не прибавится.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Добавьте using System.Diagnostics в начале файла Main.cs, затем замените стандартную строку Hello World на следующее:&lt;br /&gt;
&lt;br /&gt;
{{Врезка|right|&lt;br /&gt;
Заголовок=Наш эксперт ...|&lt;br /&gt;
Содержание=&amp;amp;nbsp;&amp;amp;nbsp;Пол Хадсон полагает, что Mono – лучшая вещь со времен мультфильма Pinky and the Brain, и сейчас поддерживает два проекта на основе Mono на SourceForge.|&lt;br /&gt;
Ширина=230px&lt;br /&gt;
}}&lt;br /&gt;
 &lt;br /&gt;
 Process[] proclist = Process.GetProcesses();&lt;br /&gt;
 foreach(Process proc in proclist) {&lt;br /&gt;
 Console.WriteLine(proc.ProcessName);&lt;br /&gt;
 } &lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Для работы этого достаточно, поэтому нажимайте F5 и смотрите на вывод панели Application Output. Вы увидите что-то вроде 'Monocular, MonoDevelop, mdhost, mdhost, MonoDevelop…', а также все прочие запущенные Mono-программы – Beagle, Tomboy, F-Spot и так далее. Если у вас сравнительно новая версия MonoDevelop (Fedora Core 6 или выше), будет доступно автоматическое завершение кода – вы это заметите, если нажмете . (точку) после proc: появится обширный набор свойств, которые можно узнать о процессе. Как именно поддерживаются эти свойства, зависит от версии Mono – полюбопытствуйте, что предоставляет ваша!&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Внимание: поддержка процессов улучшается с каждым релизом Mono – последние дистрибутивы по умолчанию включают Mono 1.2.3, а моя версия, из Fedora Core 6, уже приотстала. &lt;br /&gt;
=== Знамение времени ===&lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Следующая часть нашего проекта – задействовать таймеры, так как нам нужно выполнять периодическую проверку запущенных процессов. Можете написать следующий код: &lt;br /&gt;
 while(1){&lt;br /&gt;
 if (прошло достаточно времени){&lt;br /&gt;
 делай_работу();&lt;br /&gt;
 }&lt;br /&gt;
 } &lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;...но это капитальная глупость: ваше приложение будет тупо съедать процессорное время без особой пользы. Гораздо лучшее решение – применить таймер: он позволит вашему приложению уснуть на заданное время, а затем вызовет определенный вами метод.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Метод, который мы будем использовать, называется TimesUp(). Чтобы мы смогли подключить его к таймеру, он должен принимать определенный список параметров. Создайте следующий метод:&amp;lt;br&amp;gt;&lt;br /&gt;
 static void TimesUp(object sender, ElapsedEventArgs e){&lt;br /&gt;
 &lt;br /&gt;
 } &lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Теперь перенесите код из Main() в TimesUp(), потому что мы хотим вызывать его, когда наш таймер сработает. В начале файла напишите следующие строки using: &lt;br /&gt;
 using System.Threading;&lt;br /&gt;
 using System.Timers; &lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Чтобы ваша программа вызывала код каждые 10 секунд, создайте новый таймер и укажите ему метод TimesUp(): &lt;br /&gt;
 System.Timers.Timer timer = new System.Timers.Timer();&lt;br /&gt;
 timer.Interval = 10000;&lt;br /&gt;
 timer.Enabled = true;&lt;br /&gt;
 timer.Elapsed += new ElapsedEventHandler(TimesUp); &lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Не пытайтесь запустить код в MonoDevelop! Когда вы работаете с потоками, а с таймером так дело и обстоит, MonoDevelop обычно некорректно останавливает программу в режиме отладки; поэтому лучше запустить ее из консоли.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;При запуске не произойдет никакого вывода на экран. С чего бы это? Мы возвращаемся к проблеме с потоками, рассмотренной в прошлый раз: программа достигает конца Main() и завершает работу до того, как таймер сработает. Решение состоит в приказании главному потоку (он-то и исполняет Main()) уснуть, посредством метода Thread. Sleep(). Метод позволяет задать число миллисекунд, на которые поток впадет в спячку, или же указать Timeout.Infinite, если вы хотите, чтобы поток уснул навеки. Последняя опция нам и нужна – пусть главный поток спит, а таймер будет вкалывать. В конце Main() добавьте строку: &lt;br /&gt;
 Thread.Sleep(Timeout.Infinite); &lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Теперь при запуске программы она будет честно раз в 10 секунд выводить список процессов. Прежде чем продолжать, сделаем еще коечто: добавьте такую строку перед вызовом Thread.Sleep(): &lt;br /&gt;
 TimesUp(null, null); &lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Предоставляю вашему воображению – и тестированию! – догадаться, что она делает.&lt;br /&gt;
&lt;br /&gt;
=== Создание базы данных в Mono ===&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Информацию о процессах мы получили; надо ее куда-то положить. Базы данных бывают двух типов: клиент-серверные, когда данные хранятся где-то на сервере; и встроенные, когда есть локальный файл, напрямую управляемый из программы. Клиент-серверных баз данных полным-полно – MySQL, PostgreSQL, Oracle и другие соревнуются за место под солнцем. Но среди встроенных, одна из баз заслуживает большего внимания – это SQLite. SQLite хороша по нескольким причинам: ее код является достоянием общественности и вы можете делать с ним все, что хотите; у нее есть продвинутые возможности – поддержка Unicode, транзакций и, конечно, SQL-запросов; она также очень быстрая. Используя SQLite в Mono, можно считывать и записывать файл базы данных прямо из C#.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Слишком хорошо для этого мира? Да нет, загвоздка имеется: с базами данных не так легко работать через Mono. Если вы следовали инструкциям по установке в нашем первом выпуске ([[LXF87]]/[[LXF88]]), то уже разрешили зависимости Mono для SQLite; если нет, то я включил DLL-файл на диск, и вы можете его скопировать в папку с программой. В любом случае надо сделать ссылку на Mono.Data.SqliteClient. Есть небольшая разница между версией, входящей в Mono, и DLL – я постарался ее минимизировать, но если вы используете DLL, то вам понадобятся большие буквы в некоторых именах классов (т.е. SQLiteConnection вместо SqliteConnection).&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;В любом случае, SQLite использует для хранения данных обычный файл, так что первым шагом будет его создание. Добавьте следующие строки в начало вашего файла: &lt;br /&gt;
 using Mono.Data.SqliteClient;&lt;br /&gt;
 using System.IO; &lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Если вы используете DLL и обнаружили, что Mono.Data.SqliteClient не существует, попытаетесь набрать Mono.Data. и выбрать верное название сборки из предложенного списка опций.&amp;lt;br&amp;gt; &lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Создание базы данных осуществляется с помощью метода File. Create(), но фактически базу надо создать только один раз – если файл уже существует, незачем пересоздавать его. Поэтому предусмотрим проверку: первый раз запускается программа или нет, а также заведем место для хранения информации о соединении с нашей базой данных SQLite. Добавьте следующие две строки под class Monocular {: &lt;br /&gt;
 static bool FirstTime = false;&lt;br /&gt;
 static SqliteConnection Conn; &lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Теперь подправим Main(), чтобы он автоматически создавал базу при первом запуске приложения, а затем спокойно к ней подсоединялся: &lt;br /&gt;
 if (!File.Exists(&amp;quot;monocular.db&amp;quot;))}&lt;br /&gt;
 Firsttime=true;&lt;br /&gt;
 File.Create(&amp;quot;monocular.db&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 Conn =new SqliteConnection(&amp;quot;URL=file:monocular.db&amp;quot;);&lt;br /&gt;
 Conn.Open(); &lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Итак, файл для хранения ваших данных создан. Чтобы SQLite могла писать в него данные, надо еще создать таблицы, определяющие сохраняемые поля. Все команды SQLite выполняются через объекты SqliteCommand. Новая непонятка? А вы продолжайте читать. Эти SqliteCommand-объекты уникальны в Mono: несмотря на потуги программистов – разработчиков .NET-коннектора, они не убирают за собой. Если в Mono вы выделяете память под объект, то вам не надо заботиться о ее освобождении – сборщик мусора Mono автоматически сделает это за вас. SQLite иногда выделяет память, которая впоследствии автоматически не освобождается, и вам придется помнить об этом самим. &lt;br /&gt;
В данный момент вам надо создать объект типа команда, настроив его таким образом, чтоб он создавал таблицу для хранения информации о процессах; затем выполнить команду. Вот как это выглядит на С#: &lt;br /&gt;
 SqliteCommand dbcmd = Conn.CreateCommand();&lt;br /&gt;
 if (FirstTime) { &lt;br /&gt;
 dbcmd.CommandText = &amp;quot;CREATE TABLE processes&lt;br /&gt;
 (DateStamp TEXT, Name TEXT, Id INTEGER);&amp;quot;;&lt;br /&gt;
 dbcmd.ExecuteNonQuery();&lt;br /&gt;
 } &lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Если вы изучали SQL раньше, то удивитесь, почему поля отмечены как TEXT и INTEGER, а не более научно, как VARCHAR(255). Дело в том, что SQLite не содержит таких четких определений. Поля хранятся либо как числа, либо как текст. Если же вы не изучали SQL, то кусок кода выше создает таблицу для хранения полей DateStamp, Name и Id – мы будем использовать их для хранения даты каждого чтения, имени запущенного процесса и его идентификатора.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Вообще-то ExecuteNonQuery() – не самое умное имя: Q в аббревиатуре SQL означает Query – Запрос, то есть каждое предложение SQL является запросом. Ну, а ExecuteNonQuery() означает, что вы хотите заставить SQLite сделать что-то, но результаты запроса вас не интересуют.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;После создания таблицы необходимо очистить память, выделенную командой, следующим образом: &lt;br /&gt;
 dbcmd.Dispose(); dbcmd=null; &lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Вы, возможно, удивитесь, почему эти две строки кода не входят в блок if – а потому, что мы попозже добавим еще код! В любом случае, хотя код компилируется и запускается, проку от него мало – ничего интересного он не делает.&lt;br /&gt;
&lt;br /&gt;
=== Время писать! ===&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;ОК, у вас есть таймер, у вас есть список процессов, а теперь еще и доступ к базе данных – налицо весь инструментарий для создания всего проекта. Единственное, чего мы не умеем –писать в базу данных, но тут имеются осложнения. Противно то, что дело это нехитрое, но в наш отдел писем недавно поступила жалоба на мой «непонятный» стиль изложения. А я решил привести оптимальный способ создания записей в базе данных – оптимальный с точки зрения производительности, а не с точки зрения обучения. Кто не согласен, пишите мне, и мы сменим акценты. Так, отвел душу – и хватит; вернемся к базе данных! Есть две вещи, которые необходимо знать, прежде чем приступать к записи в базу SQLite: 1 SQLite использует транзакции для обеспечения целостности данных. То есть, когда вы пишете строку данных, то запускается транзакция, записываются данные, и транзакция завершается. Если вдруг ваша машина откажет во время записи транзакции, то SQLite ее откатит. Это очень хорошо. &lt;br /&gt;
2 SQLite кэширует запросы для ускорения работы. Первый пункт очень важен, так как мы собираемся писать за раз сразу несколько строк. Если у вас работает 10 Mono-приложений, будем писать 10 строк – по одной для каждой программы. Процесс в SQLite будет выглядеть следующим образом:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;1.&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Начать транзакцию &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;2.&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Записать строку &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;3.&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Закончить строку &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;4.&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Начать транзакцию &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;5.&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Записать строку &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;6.&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Закончить транзакцию… и так далее.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Врезка|right|&lt;br /&gt;
Заголовок=Слабости Mono|&lt;br /&gt;
Содержание=&amp;amp;nbsp;&amp;amp;nbsp;Да, я вовсю расхваливал Mono, но теперь вы в состоянии заметить и недостатки – там, где Mono не так хорош, как официальная реализация Microsoft .NET; но это только пока. Во-первых, при работе в официальной .NET- среде эта программа снабдит вас данными обо всех работающих программах, .NET или других. Во-вторых, официальная среда поставляет информацию о том, сколько памяти использует каждый процесс. В-третьих, официальная среда содержит глобальные счетчики производительности, измеряющие использование CPU, объем свободной глобальной памяти и т.д. Каждый из этих пунктов сделал бы нашу программу куда полезнее, но на беду, Mono не имеет ни одной из перечисленных возможностей – что, конечно, вредит программе этого месяца!|&lt;br /&gt;
Ширина=250px&lt;br /&gt;
}}&lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Это очень медленно, но необходимо, так как SQLite требует, чтобы каждая команда записи была частью транзакции. Той же цели можно достичь, если велеть SQLite начать транзакцию, записать все строки сразу же, затем закончить транзакцию самим: &lt;br /&gt;
 1 2 3 4 5 6 Начать транзакцию &lt;br /&gt;
 Записать строку &lt;br /&gt;
 Записать строку &lt;br /&gt;
 Записать строку &lt;br /&gt;
 ... &lt;br /&gt;
 Закончить транзакцию. &lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Такой способ работает много быстрее, и он также более надежен: если наш компьютер откажет (или же другое несчастье прервет работу SQLite), то у нас не будет недоделанных записей – у нас будут либо все записи, либо ничего.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Второй пункт важен потому, что подобные запросы очень просто писать: &lt;br /&gt;
 for (int i = 0; i &amp;lt; 10; i++){&lt;br /&gt;
 $query = &amp;quot;SELECT Foo FROM Bar WHERE Baz = &amp;quot;+i; ... { &lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Выполнится 10 различных запросов к SQLite. Лучше использовать приготовленные заранее запросы и сообщать SQLite максимум информации о запросе, помечая заменяемые части вопросительными знаками. &lt;br /&gt;
Из примера все будет ясно, поэтому углубимся в код. Пока что TimesUp() у нас распечатывал информацию; а надо заточить его на запись в базу данных. Вот как TimesUp() должен выглядеть: &lt;br /&gt;
 static void TimesUp(object sender, ElapsedEventArgs e) {&lt;br /&gt;
 Process[] proclist = Process.GetProcesses();&lt;br /&gt;
 SqliteTransaction transaction = (SqliteTransaction)Conn.&lt;br /&gt;
 BeginTransaction();&lt;br /&gt;
 dbcmd = Conn.CreateCommand();&lt;br /&gt;
 dbcmd.CommandText = &amp;quot;INSERT INTO processes VALUES (?,?, ?);&amp;quot;;&lt;br /&gt;
 SqliteParameter date = new SqliteParameter();&lt;br /&gt;
 SqliteParameter name = new SqliteParameter();&lt;br /&gt;
 SqliteParameter id = new SqliteParameter();&lt;br /&gt;
 date.Value = DateTime.Now.ToLongTimeString();&lt;br /&gt;
 dbcmd.Parameters.Add(date);&lt;br /&gt;
 dbcmd.Parameters.Add(name);&lt;br /&gt;
 dbcmd.Parameters.Add(id);&lt;br /&gt;
 foreach(Process proc in proclist) { &lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Это еще не вся функция, но я хочу притормозить и взглянуть на подготовленные запросы в действии. Запрос, который мы используем, передает вместо знаков вопроса информацию о процессе, так как только эта часть будет изменяться. Однако параметр date изменяется только один раз за время выполнения TimesUp(), поэтому его можно назначить сразу. Другие параметры просто оставляются как пустые объекты SqliteParameter, чтобы потом заполнять их отдельно для каждого процесса. Знаю, что это тривиально, но ради ясности ситуации скажу: необходимо вызывать dbcmd.Paramters.Add() для каждого параметра SQL-запроса, в порядке их появления в запросе.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Ладно, продолжим с того места, на котором остановились... &lt;br /&gt;
 foreach(Process proc in proclist) {&lt;br /&gt;
 name.Value = proc.processName;&lt;br /&gt;
 id.Value = proc.Id;&lt;br /&gt;
 dbcmd.ExecuteNonQuery();&lt;br /&gt;
 }&lt;br /&gt;
 dbcmd.Dispose();&lt;br /&gt;
 dbcmd = null;&lt;br /&gt;
 transaction.Commit(); } &lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Действительно, все, что меняется между вызовами ExecuteNonQuery() – это значения двух подставляемых параметров, поэтому SQLite может использовать кэшированные запросы для получения наивысшей производительности. Последнее выражение в коде особенно важно: пока транзакция не зафиксирована, никаких записей внесено не будет – не забудьте вызывать Commit(), если, конечно, вы не любитель охоты за странными ошибками! Написано тут много, но смотреть все равно не на что, кроме как на медленное разрастание файла monocular.db. Но скоро все пойдет по-другому...&amp;lt;br&amp;gt;&lt;br /&gt;
=== К чтению готовы! ===&lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Последнее, что нам предстоит сделать – это считать всю информацию из базы данных, так что вернемся к методу Main() и проделаем коекакие изменения. Если пользователь запускает Monocular без параметров, то она будет бесконечно работать в фоновом режиме, считывая информацию каждые 10 секунд и записывая ее в базу данных. Но если ей предоставить параметр – любой параметр – Monocular будет выводить всю хранимую информацию. На DVD я поместил код, позволяющий выполнять сортировку по имени процессов или по идентификатору, но ради экономии места мы пока проигнорируем его значение. Сейчас нам важен параметр как таковой — он будет сигнализировать о том, что пользователю нужен режим чтения.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Врезка|right|&lt;br /&gt;
Заголовок= Скорая помощь|&lt;br /&gt;
Содержание=&amp;amp;nbsp;&amp;amp;nbsp;На смену Fedora Core 6 пришла Fedora 7, а значит, у нас есть возможность поиграть с новой версией Mono. Со следующего выпуска мы будем ориентироваться на Mono 1.2.3. Обновляйтесь!|&lt;br /&gt;
Ширина=250px&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;В отличие от предыдущих запросов, теперь вам действительно потребуются данные – результаты SQL-запроса; добудем их с помощью специального объекта SQLiteDataReader: &lt;br /&gt;
 string currenttime = &amp;quot;&amp;quot;;&lt;br /&gt;
 // this loops over all the rows returned by the query&lt;br /&gt;
 while (reader.Read()) {&lt;br /&gt;
 string datestamp = reader.GetString(0);&lt;br /&gt;
 string name = reader.GetString(1);&lt;br /&gt;
 int id = reader.GetInt32(2);&lt;br /&gt;
 // we'll put some more code in here shortly&lt;br /&gt;
 Console.WriteLine(&amp;quot; {0}\1{1}\2&amp;quot;, id, name);&lt;br /&gt;
 }&lt;br /&gt;
 reader.Close(); &lt;br /&gt;
 reader = null; } &lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;GetString() и GetInt32() оба принимают один параметр: какое поле вы хотите считать. То есть GetString(0) считывает первое поле (DateStamp), GetString(1) считывает второе поле, и так далее. Как и с командами, вам надо на всякий случай освободить память, выделенную для считывателей, так как SQLite может этого не сделать. &lt;br /&gt;
Данный код выводит хранимую в таблице информацию обо всех процессах, но игнорирует поле даты. Это потому, что я хочу внести немного разнообразия: буду выводить каждый временной штамп при его изменении, тогда наш вывод будет разделяться чем-то вроде заголовков. Вы заметили пустую переменную currenttime. В нее мы занесем дату первой строки, считываемой из таблицы. Если в последующей строке окажется отличное от currenttime время, то выведется новый заголовок для нового времени, и это значение запишется в currenttime. На C# получится следующее: &lt;br /&gt;
 if (datestamp != currenttime) {&lt;br /&gt;
 Console.WriteLine(&amp;quot;&amp;quot;);&lt;br /&gt;
 Console.WriteLine(&amp;quot;Readings from &amp;quot; + datestamp);&lt;br /&gt;
 Console.WriteLine(&amp;quot; PID\tName&amp;quot;); currenttime = datestamp; } &lt;br /&gt;
&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp;Вот и все – проект завершен! Я знаю, он не так полезен, как остальные проекты, но у нас связаны руки, так как в Mono отсутствуют некоторые интересные возможности официальной реализации Microsoft. Не горюйте: работа над добавлением недостающих возможностей в Mono ведется постоянно. А пока вы можете много чего еще добавить в эту программу: например, возможность старта и остановки программы, определения периодов наибольшей загрузки системы и так далее. Творите! ''LXF''&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF90:Mono</id>
		<title>LXF90:Mono</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF90:Mono"/>
				<updated>2008-04-27T15:24:38Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: Шаблон:Цикл/Mono  AWB&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/Mono}}&lt;br /&gt;
&lt;br /&gt;
== Mono: Связь с библиотеками ==&lt;br /&gt;
''Создать супер-поиск по файловой системе меньше чем за час? Наш штатный вождь обезьян '''Пол Хадсон''' делает невозможное не только возможным, но и простым...''&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
Ваша миссия, если вы за нее беретесь, состоит в написании консольной программы, которая индексирует файловую систему пользователя в фоновом режиме, сканирует почту, RSS-ленты, историю браузера и содержимое файлов, а затем позволяет производить во всем этом молниеносный поиск. Уловили? ОК, увидимся через час – удачи вам!&lt;br /&gt;
&lt;br /&gt;
Да, мы собрались создать шедевр менее чем за 60 минут; по-вашему, без чуда не обойтись? Но прикиньте: какое небезызвестное Linux-приложение умеет осуществлять поиск по всем источникам данных? Думайте, думайте! Ясное дело, ''Beagle''. А на какой платформе построен ''Beagle''? Mono! А о чем этот учебник? О Mono! Итак, мы позаимствуем возможности у проекта ''Beagle'' – точнее, у его библиотек.&lt;br /&gt;
&lt;br /&gt;
Что хорошо в .NET – это шанс встать на плечи гигантам, использовав их библиотеки. Конечно, С тоже такое допускает – например, программа ''Ark RPG'' имеет библиотеку ''libarkrpg0c2a'', позволяющую другим программам на С вызывать ее функции, а не реализовывать их заново. Но такой подход не лишен проблем: например, ''Gstreamer'' разделен на несколько библиотек, и у каждой собственный номер версии. Рядовой пример – ''libgstdataprotocol-0.10.so.0.8.1''. C не воспринимает новые версии библиотек без обновления самой программы, поэтому номера версий так важны – приложению подавай непременно ''libgstdataprotocol-0.10'', а не 0.9 или 0.11.&lt;br /&gt;
&lt;br /&gt;
Mono позволяет программистам просто потребовать «давай Beagle» и получить любую доступную версию. Такой подход не всегда срабатывает, особенно с некоторыми новыми Linux-приложениями, не достигшими версии 1.0. Причина, по которой у них такие маленькие номера версий (Beagle находится на стадии 0.2.14) – недостаточно стабильный программный интерфейс (application programming interface, API). API – это термин для обозначения имен функций, типов параметров и возвращаемых значений для данной библиотеки. Стабильность API означает, что если функция {{oncolor||green|DoFoo()}} в версии 1.0 принимает целый аргумент и возвращает строку, то любая использующая ее программа будет работать и с версией библиотеки 1.01, потому что функция не меняется.&lt;br /&gt;
&lt;br /&gt;
Самое главное в API – это 'I'-часть, собственно интерфейс (имя, параметры, возвращаемое значение): если он фиксирован, то неважно, как библиотека выполняет свою задачу, и пусть себе её версии меняются как угодно.&lt;br /&gt;
&lt;br /&gt;
Резюмирую:&lt;br /&gt;
&lt;br /&gt;
* Мы используем Mono, и Beagle тоже – значит, нам доступны преимущества Beagle.&lt;br /&gt;
* Beagle имеет API, предоставляющий в наше распоряжение его функциональность, но он не стабилен и в будущем может измениться (в прошлом он менялся довольно круто).&lt;br /&gt;
* Чтобы использовать Beagle, достаточно знать имена его функций и как к ним обратиться.&lt;br /&gt;
&lt;br /&gt;
Вам это все еще кажется трудным? А так оно и есть. Но я ведь обещал научить вас всем навыкам, необходимым, чтобы к концу нашей серии уроков вы стали профессионалом, поэтому перейдем к делу...&lt;br /&gt;
&lt;br /&gt;
Начнем с имени нашего приложения. Приложениям Gnome на основе Mono уже приелись имена с буквой G, и я решил выбрать что-нибудь смешное и продвинутое. Предлагаю Poochy, это имя малоизвестного песьеголового персонажа игры Nintendo (даже Майк про него не слыхал!) – оно вполне подходит к собачьей теме, заданной Beagle {{oncolor||green|[англ. «гончий пес»]}}.&lt;br /&gt;
&lt;br /&gt;
Итак, запустите MonoDevelop, выберите {{oncolor||green|File &amp;gt; New Project}}, затем {{oncolor||green|C# &amp;gt; Console Project}}, уберите галочку с {{oncolor||green|Create Separate Solution Subdirectory}}, затем введите имя 'Poochy' в поле {{oncolor||green|Name}} и нажмите кнопку {{oncolor||green|New}} внизу. Вы получите старое доброе приложение Hello World – мы его 'программировали' в начале серии уроков; удалите строчки {{oncolor||green|Console.WriteLine()}} и оставьте метод {{oncolor||green|Main()}} пустым.&lt;br /&gt;
&lt;br /&gt;
=== GTK и командная строка ===&lt;br /&gt;
&lt;br /&gt;
Для этого проекта нам нужно использовать ''Beagle'' и – не удивляйтесь – ''GTK'', поэтому нажмите правой кнопкой мыши на References на панели слева (сразу над ''Resources'', ''AssemblyInfo.cs'' и ''Main.cs'') и выберите Edit References. В появившемся окне переключитесь на вкладку Packages, где выберите ''Beagle'' (версия 0.0.0.0 – я предупреждал, что он далеко не стабилен, не так ли?) и ''GTK-sharp'' (версия 2.10.0.0). Эти номера просто сообщают, какие версии установлены в данный момент – если у кого-то другая версия ''Beagle'', Mono преспокойно обойдется той, что есть.&lt;br /&gt;
&lt;br /&gt;
Тем самым мы запросили для использования библиотеки ''Beagle'' и ''GTK#'', но чтобы действительно их использовать, необходимо прописать операторы {{oncolor||green|using}} в начале исходного кода. По умолчанию, единственная строка {{oncolor||green|using}} –&lt;br /&gt;
&lt;br /&gt;
 using System;&lt;br /&gt;
&lt;br /&gt;
Библиотека System включает основные функции для написания консольного приложения, включая доступ к самой консоли для обеспечения ввода-вывода. Мы хотим включить в этот список ''Beagle'' и ''GTK'', так что добавим следующие две строки:&lt;br /&gt;
&lt;br /&gt;
 using Beagle;&lt;br /&gt;
 using Gtk;&lt;br /&gt;
&lt;br /&gt;
В методе {{oncolor||green|Main()}} необходимо вызвать ''Beagle'' и сказать ему, что искать. Это можно сделать через {{oncolor||green|Query}}, специальный объект ''Beagle''. Этот объект также умеет запускать наши собственные методы при наступленииопределенных событий – например, найдя что-нибудь, отвечающее поисковому запросу. Вот как все это выглядит в C# – поместите этот код туда, где находился {{oncolor||green|Console.WriteLine()}}:&lt;br /&gt;
&lt;br /&gt;
 // Создаем новый запрос и добавляем два метода обработчика событий&lt;br /&gt;
  Query q = new Query();&lt;br /&gt;
  q.HitsAddedEvent += OnHitsAdded;&lt;br /&gt;
  q.FinishedEvent += OnFinished;&lt;br /&gt;
 // Сообщаем Beagle, что запрос содержится в первом параметре командной строки&lt;br /&gt;
  q.AddText(args[0]);                                                       &lt;br /&gt;
 // Начинаем поиск&lt;br /&gt;
  q.SendAsync();&lt;br /&gt;
&lt;br /&gt;
В общем, несложно, но это еще не вся сказка: найдя файл, RSS-ленту или что там еще совпадет с нашим запросом, ''Beagle'' всегда в вызывает метод {{oncolor||green|OnHitsAdded()}}, а закончив поиск, вызовет метод {{oncolor||green|OnFinished()}} – чтобы код скомпилировался, необходимо реализовать оба этих метода. Для успешной компиляции достаточно вставить два пустых метода:&lt;br /&gt;
&lt;br /&gt;
  static void OnHitsAdded (HitsAddedResponse response) { }&lt;br /&gt;
  static void OnFinished(FinishedResponse response) { }&lt;br /&gt;
&lt;br /&gt;
Объекты {{oncolor||green|HitsAddedResponse}} и {{oncolor||green|FinishedResponse}} вообще-то дают массу полезной информации, но пока мы их проигнорируем. Продолжим: нажмем F8, чтоб скомпилировать первый релиз ''Poochy'' (храбро назовем его 0.1), затем откроем окно терминала и перейдем в '''/каталог/где/находится/poochy/bin/Debug'''. Пора протестировать нашу ищейку.&lt;br /&gt;
&lt;br /&gt;
''Poochy'' необходимо запускать из командной строки, потому что он читает {{oncolor||green|arg[0]}}, который мы должны передать из командной строки. Запустите следующую команду:&lt;br /&gt;
&lt;br /&gt;
 mono poochy.exe foo&lt;br /&gt;
&lt;br /&gt;
Эта команда заставит ''Beagle'' искать в своем кэше аргумент {{oncolor||green|'foo'}}, и для выполнения запроса понадобится около секунды (замените {{oncolor||green|foo}} на что-нибудь заведомо присутствующее в вашем кэше ''Beagle''). Но тут вы обнаружите, что ничего не выводится – ни файлов, ни чего-либо еще,&lt;br /&gt;
содержащего {{oncolor||green|'foo'}}. Чья это проблема – ''Beagle'' или наша? ''Beagle'' вне подозрений, значит, проблема в нашем коде. Расследуем...&lt;br /&gt;
&lt;br /&gt;
=== Гонка на время ===&lt;br /&gt;
&lt;br /&gt;
Наша программа не работает по двум причинам. Более заметная из них – пуст метод {{oncolor||green|OnHitsAdded()}}, вызываемый ''Beagle'' при нахождении совпадения, в который ''Poochy'' должен вывести результат. Поэтому Mono безмолвствует, даже и получив что-то от ''Beagle''. Проще всего заставить ''Poochy'' выводить URL каждого найденного ''Beagle'' объекта, например, так:&lt;br /&gt;
&lt;br /&gt;
 foreach(Hit hit in response.Hits)&lt;br /&gt;
  {&lt;br /&gt;
   Console.WriteLine(&amp;quot;Hit: &amp;quot; + hit.Uri);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
Если вы запустите программу, то увидите, что она опять ничего не выдает, хотя ''Beagle'' должен бы найти то, что вы просили. Проблема том, что наш поиск использует метод '''SendAsync()''', то есть ''Beagle'' выполняет поиск асинхронно. Мысленно прокрутите программу: компьютер выполняет первую строчку, переходит ко второй, затем к третьей, и так далее до конца. Конечно, иногда программа перескакивает с места на место, но смысл в том, что в один момент времени исполняется одна строка кода.&lt;br /&gt;
&lt;br /&gt;
У ''Beagle'' есть два способа поиска: синхронный и асинхронный. Первый означает «выполняй поиск, а я буду ждать его окончания», а второй – «начинай поиск, а я продолжу выполнение программы; когда закончишь, прерви меня». Они также известны как блокирующий и неблокирующий, потому что синхронный метод блокирует выполнение следующей строки, пока сам не завершит работу, в то время как асинхронный метод позволит вам выполнять код, а сам будет работать параллельно.&lt;br /&gt;
&lt;br /&gt;
Вам необходимо это знать, чтобы учесть такую возможность: вдруг ваша программа завершится раньше, чем асинхронный метод успеет что-либо сделать? То есть завершится до того, как ''Beagle'' найдет какое-либо совпадение? Ответ состоит в том, что программа успешно отключится, и вызванный метод сгинет, не успев ничего напечатать. Вот почему мы не получили никакого результата, и, значит, нам надо ждать, пока ''Beagle'' завершит поиск.&lt;br /&gt;
&lt;br /&gt;
Вот здесь на сцену и выходит GTK. Когда вы используете программы с графическим интерфейсом, приложение ждет, пока вы чтонибудь сделаете: выберете пункт меню или хотя бы наведете курсор мыши на кнопку. Фактически, любое действие посылает сигнал приложению, чтобы оно смогло отреагировать, то есть приложение просто ждет сигнала. Очевидно, такие приложения не отключаются, выполнив то или иное действие, иначе, например, в Abiword вам пришлось бы непрерывно что-то печатать, чтобы редактор не закрылся. Вместо этого они используют так называемый главный цикл [сообщений], который выглядит примерно так:&lt;br /&gt;
&lt;br /&gt;
 while (1) {&lt;br /&gt;
   LookForSignals();&lt;br /&gt;
   ActOnSignals();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Вы, конечно, сообразили, что это бесконечный цикл, но он практически не потребляет процессорное время и позволяет другим частям приложения (графическому интерфейсу или, в нашем случае, ''Beagle'') работать на полную катушку. Нам того и надо, вот почему мы собираемся сесть на главный цикл GTK: пусть наша программа простаивает, пока ''Beagle'' производит поиск и вывод результата. Чтобы это сделать, добавим в конец метода {{oncolor||green|Main()}} две строчки:&lt;br /&gt;
&lt;br /&gt;
 Gtk.Application.Init();&lt;br /&gt;
 Gtk.Application.Run();&lt;br /&gt;
&lt;br /&gt;
Этот код велит GTK запуститься и работать. Скомпилируйте программу, нажав {{oncolor||green|F8}}, и запустите ее из командной строки. На этот раз вы должны получить список результатов, похожих на следующие:&lt;br /&gt;
&lt;br /&gt;
 Hit: file:///home/paul/foo.xml&lt;br /&gt;
 Hit: file:///usr/share/doc/tzdata-2006m/tz-link.html&lt;br /&gt;
 Hit: file:///usr/share/gtk-doc/html/libuser/libuser-config.html&lt;br /&gt;
 Hit: file:///usr/share/doc/nant-0.85/releasenotes.html&lt;br /&gt;
 Hit: file:///usr/share/gtk-doc/html/libgnome/libgnome-gnomeconfig.html&lt;br /&gt;
 Hit: file:///usr/share/gtk-doc/html/gtk/gtk-question-index.html&lt;br /&gt;
 Hit: file:///usr/share/gtk-doc/html/gtk/gtk-Resource-Files.html&lt;br /&gt;
&lt;br /&gt;
=== Два шага вперед, один назад ===&lt;br /&gt;
&lt;br /&gt;
Кроме основного результата, мы также получили побочный: выхода из приложения не происходит. Когда ''Beagle'' вернет все возможные результаты, Poochy будет по-прежнему чего-то ждать. Вы видели, что основной цикл приложения – бесконечный, и коль скоро мы вызвали метод {{oncolor||green|Application.Run()}}, то вошли в состояние вечного исполнения. Пока программа не даст сбой, машина не перезагрузится или мы не нажмем {{oncolor||green|Ctrl+C}}, ''Poochy'' так и будет находиться в этом состоянии.&lt;br /&gt;
&lt;br /&gt;
Может, вам того и надо – к примеру, вы хотите периодически проверять ресурс или дожидаться, пока данные поиска доберутся до вас через сокет. Но ''Poochy'' задуман как программа, выполняющая поиск по требованию, а затем завершающаяся. Мы уже написали заглушку метода {{oncolor||green|OnHitsAdded}}, а теперь займемся методом {{oncolor||green|OnFinished()}}, который покамест пуст.&lt;br /&gt;
&lt;br /&gt;
Когда ''Beagle'' вернет все результаты, он посмотрит, зарегистрирован ли метод для свойства {{oncolor||green|FinishedEvent}}. Мы уже делали это с нашим методом {{oncolor||green|OnFinished()}}, который вызывается по окончании работы ''Beagle''. А сейчас нам нужно сообщить GTK, чтобы программа покинула основной цикл, тогда наше приложение сможет корректно завершиться. Это довольно просто – вот как выглядит новый метод {{oncolor||green|OnFinished()}}:&lt;br /&gt;
&lt;br /&gt;
  static void OnFinished(FinishedResponse response)&lt;br /&gt;
  {&lt;br /&gt;
    Application.Quit();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
{{oncolor||green|Application.Quit()}} – это GTK-метод, который прерывает главный цикл, очищает все использованные GTK-ресурсы (в нашем случае их немного, так как мы не работаем с графикой), затем передает управление нашему приложению сразу же после строки {{oncolor||green|Application.Run()}} в методе {{oncolor||green|Main()}}. Поэтому путь работы программы будет следующим: {{oncolor||green|Main() &amp;gt; SendAsync() &amp;gt; Application.Run()}} &amp;gt; основной цикл GTK &amp;gt; {{oncolor||green|OnFinished() &amp;gt; Application.Quit() &amp;gt; Main()}}.&lt;br /&gt;
&lt;br /&gt;
Скомпилируйте, запустите и восхититесь собственным умом: ваша программа делает все, что задумано, и потребовала всего десять строк значащего кода!&lt;br /&gt;
&lt;br /&gt;
''Poochy'' выводит на экран все URL, RSS-ленты, документы OpenOffice.org, MP3, презентации PowerPoint, заметки Tomboy, исходный код, JPEG файлы, приложения... (глубокий вдох)... email, видео, встречи, zip-файлы и установленные пакеты на вашей системе, которые соответствуют запросу, передаваемому в {{oncolor||green|AddText()}}. А если вас интересуют только файлы, находящиеся на вашем диске, а не все что ни попадя?&lt;br /&gt;
&lt;br /&gt;
=== Погодите... еще не все! ===&lt;br /&gt;
&lt;br /&gt;
Два урока назад мы рассматривали метод {{oncolor||green|EndsWith()}}, применимый к строкам, который принимает строку в качестве аргумента и возвращает true, если строка А оканчивается строкой B. Например:&lt;br /&gt;
&lt;br /&gt;
 string foo = &amp;quot;bar&amp;quot;;&lt;br /&gt;
 bool baz = foo.EndsWith(&amp;quot;r&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Когда этот код выполнится, переменная {{oncolor||green|baz}} установится в '''{{oncolor||green|true}}''', так как {{oncolor||green|foo}} оканчивается на 'R'. В .NET также есть метод {{oncolor||green|StartsWith()}}, который действует наоборот – возвращает '''{{oncolor||green|true}}''', если одна строка начинается с другой. Выходит, мы можем заставить наш код выводить только файлы, поменяв метод {{oncolor||green|OnHitsAdded()}} на следующий:&lt;br /&gt;
&lt;br /&gt;
 static void OnHitsAdded (Beagle.HitsAddedResponse response)&lt;br /&gt;
  {&lt;br /&gt;
    foreach(Hit hit in response.Hits)&lt;br /&gt;
     {&lt;br /&gt;
       if (hit.Uri.StartsWith(&amp;quot;file&amp;quot;))&lt;br /&gt;
        {&lt;br /&gt;
         Console.WriteLine(&amp;quot;Hit: &amp;quot; + hit.Uri);&lt;br /&gt;
        }&lt;br /&gt;
     }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
Это метод грубой силы: ''Beagle'' ищет все подряд, а мы фильтруем результаты перед выводом. Но ''Beagle'' можно научить искать и конкретный тип совпадений, с помощью метода {{oncolor||green|AddHitType()}}: он позволит описать то, что вы ищете, обычным текстом. Корректные параметры включают {{oncolor||green|Application}}, {{oncolor||green|Calendar}}, {{oncolor||green|Contact}}, {{oncolor||green|Feeditem}} (для RSS), {{oncolor||green|Image}}, {{oncolor||green|IMLog}}, {{oncolor||green|MailMessage}} и – вот оно! – {{oncolor||green|File}}.&lt;br /&gt;
&lt;br /&gt;
Вернувшись к методу {{oncolor||green|Main()}}, найдите строку {{oncolor||green|q.AddText(args[0])}} и добавьте перед ней строку:&lt;br /&gt;
&lt;br /&gt;
 q.AddHitType(&amp;quot;File&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Запустите программу, и увидите, что выводятся только файлы – никакой переписки из чатов, засоряющей результаты! [http://www.linuxformat.ru LXF]&lt;br /&gt;
&lt;br /&gt;
=== Часто задаваемые вопросы ===&lt;br /&gt;
&lt;br /&gt;
'''Mono FAQ – часть I'''&lt;br /&gt;
&lt;br /&gt;
''Если тонкие моменты Mono вызывают у вас вопросы, то вот ответы на них...''&lt;br /&gt;
&lt;br /&gt;
* '''Не понял. Зачем мы пометили Reference, а потом еще и прописали строку {{oncolor||red|using}}?'''&lt;br /&gt;
&lt;br /&gt;
Добавление чего-то через Reference позволяет воспользоваться соответствущим кодом; добавление чего-то с помощью строки {{oncolor||red|using}} позволяет сэкономить набор кода при вызове методов. Для подключения ''Beagle'' необходимо добавить его как Reference – тогда станут доступны его объекты и методы, и мы можем немедля их использовать, но только под полным именем, включающим ссылку на пространство имен. Строка {{oncolor||red|using Beagle}}; сообщает .NET, что когда мы пишем {{oncolor||red|Query}}, подразумевается {{oncolor||red|Beagle.Query}}. В нашем случае экономия невелика; а вот, например, алгоритм SHA1 в .NET находится в пространстве {{oncolor||red|System.Encryption.Cryptography}}, и пришлось бы писать {{oncolor||red|System.Encryption.Cryptography.SHA1CryptoServiceProvider foo &amp;amp;#61; new System.Encryption.Cryptography.SHA1CryptoServiceProvider()}} – согласитесь, довольно утомительно! Вместо этого можно поместить в начале {{oncolor||red|using System.Encryption.Cryptography;}}, затем {{oncolor||red|SHA1CryptoServiceProvider foo &amp;amp;#61; new SHA1CryptoServiceProvider()}}. Помните, что MonoDevelop по умолчанию добавляет System в Reference.&lt;br /&gt;
* '''Почему мы используем +=, чтобы добавить метод к событию Beagle? Я думал, что += для добавления значения к переменной.'''&lt;br /&gt;
&lt;br /&gt;
Да, += используется для сложения переменных, но почему бы не расширить эту метафору на события, происходящие во время работы Beagle, и не использовать += для добавления методов. Это также известно как подписка. Используя +=, вы можете 'подписать' несколько методов на одно событие – Mono просто запустит их по одному последовательно в порядке их добавления.&lt;br /&gt;
* '''Зачем нужен файл AssemblyInfo.cs?'''&lt;br /&gt;
&lt;br /&gt;
Вы будете смеяться, но там и правда информация о вашей сборке! В терминах .NET сборка может быть как разделяемым объектом (SO файл в Linux или DLL в Windows), так и исполняемым файлом. Номер версии вашего исполняемого файла, имя программиста и другая информация находится в конечном двоичном файле poochy, и все это вы устанавливаете в AssemblyInfo.cs.&lt;br /&gt;
* '''Надо ли располагать открывающую и закрывающую фигурные скобки на отдельных строках?'''&lt;br /&gt;
&lt;br /&gt;
Нет – вовсе нет! Лично я люблю ставить { на той же строке, что и оператор, ей предшествующий. Этот стиль известен как Единственно Верный Скобочный Стиль, потому что его приняли Брайан Керниган и Деннис Ритчи, когда они изобрели язык программирования С. Однако MonoDevelop по умолчанию использует стиль BSD, когда каждая скобка располагается на своей строке. Выбирайте, что вам больше нравится, главное – соблюдать единый стиль во всей программе!&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF89:Mono</id>
		<title>LXF89:Mono</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF89:Mono"/>
				<updated>2008-04-27T15:24:31Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: Шаблон:Цикл/Mono  AWB&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/Mono}}&lt;br /&gt;
&lt;br /&gt;
== Mono: Работаем с файлами ==&lt;br /&gt;
''Подогрев ваш интерес пространствами имен и объектно-ориентированным программированием, '''Пол Хадсон''' покажет, как пишется полезный код...''&lt;br /&gt;
&lt;br /&gt;
{{Врезка|left|&lt;br /&gt;
Заголовок=Наш эксперт&lt;br /&gt;
|Содержание=&lt;br /&gt;
'''Пол Хадсон'''&amp;lt;br&amp;gt;полагает, что Mono – лучшая вещь со времен мультфильма ''Pinky and the Brain'', и сейчас поддерживает два проекта на основе Mono на SourceForge.&lt;br /&gt;
|Ширина=150px}}&lt;br /&gt;
&lt;br /&gt;
Вы когда-нибудь смотрели мультсериал ''Thundercats'' [Громо-Коты, – прим. пер.]? В детстве я считал его гениальным: вы действительно могли ощущать «колдовство и рык звериный», глядя в телевизор, благодаря крутой анимации, симпатичным персонажам и замечательным сценариям. Сейчас, однако, я понимаю, что он был не лишен шаблонности. Среди ГромоКотов были такие персонажи, как Лева-O, Тигра и Пантро, и они боролись против обезьяноподобного индивида по имени Обезмен, шакаловидного Шаклмена и коршунообразного Коршмена. Их родная страна называлась Громада. Машина Пантро называлась Громокар. Уловили закономерность?&lt;br /&gt;
&lt;br /&gt;
Такая предсказуемость может показаться чересчур лобовой, зато дети легко улавливают, что происходит, и легко это запоминают, чтобы пересказать сюжет друзьям. Теперь, повзрослев, я уяснил две вещи. Во-первых, я не стану космонавтом. Я бы и пошел, но вряд ли туда возьмут «очкарика». Во вторых, лучший способ что-то выучить – сделать это запоминающимся.&lt;br /&gt;
&lt;br /&gt;
К примеру, я использую PHP уже много лет и никак не могу запомнить, принимает ли функция '''strpos()''' (поиск вхождения одной строки в другую) параметры как '''$иголка''', '''$стог_сена''' или как '''$стог_сена''', '''$иголка'''.&lt;br /&gt;
&lt;br /&gt;
Проблема PHP в том, что функция '''strpos()''' принимает параметры как '''$стог_сена''', '''$иголка''', в то время как функция '''in_array()''' (она отвечает на вопрос, встречается ли элемент в массиве) принимает параметры как '''$иголка''', '''$стог_сена'''. Вдобавок '''strpos()''' пишется в одно слово, а '''str_replace()''' содержит разделяющий две части знак подчеркивания. По своей природе, PHP не очень запоминающийся язык программирования. Программистам PHP не быть ГромоКотами.&lt;br /&gt;
&lt;br /&gt;
К счастью, вы не учитесь программировать на PHP, а работаете на платформе Mono с С#, а C# – язык более новый и менее набитый ляпсусами, чем PHP – не имеет таких проблем. Собственно говоря, некоторые части C# так прямолинейны, что вы можете вставлять имена методов по догадке. На нашем втором уроке мы рассмотрим управление файлами. Вы напишете программу, которая пройдется по файловой системе и составит указатель по всем имеющимся файлам, а вы потом сможете его распечатать. Не волнуйтесь, если это звучит сложно – C#, Mono и .NET сделают всю трудную работу за вас.&lt;br /&gt;
&lt;br /&gt;
=== Ощутите колдовство ===&lt;br /&gt;
Начнем с простейшего чтения и записи файлов. Вообще-то точнее будет сказать – простейшего ввода-вывода: в терминах программирования, «писать» означает «вывести» или «отобразить» (то, что делает команда write). Запустите ''MonoDevelop'' (который мы установили в прошлый раз) и создайте консольный проект C# ('''File &amp;gt; New Project &amp;gt; C# &amp;gt; Console Project'''). Это не временный проект, поэтому дайте ему такое имя, чтобы не стыдно было выложить его на SourceForge. Я выбрал имя Snarf, потому что оно означает «брать» (эта программа будет читать содержимое кучи файлов), а также хорошо сочетается с темой ''ГромоКотов''.&lt;br /&gt;
&lt;br /&gt;
[[Изображение:Img 89 58 1.jpg|thumb|right|300px|Велите ''MonoDevelop'' компилировать программы в каталог вашего проекта, чтобы программа могла читать кэш файлов.]]&lt;br /&gt;
Нам понадобится кое-что из новой функциональности .NET 2.0, но в большинстве версий ''MonoDevelop'' по умолчанию используется .NET 1.1. Чтобы поправить дело, нажмите '''Project &amp;gt; Options''', затем выберите '''Runtime Options''' из списка '''Categories''' в появившемся окне. Справа помещен выбор среды исполнения, варианты: '''1.1''' и '''2.0''', вот и выберите '''2.0'''. Пока вы еще в этом окне, откройте категорию '''Configurations &amp;gt; Debug''', выберите '''Output''', затем измените '''Output Path''', удалив раздел '''/bin/Debug'''. Теперь ''MonoDevelop'' будет сохранять исполняемый файл в корневом каталоге вашего проекта. Нажмите '''OK''', чтобы запомнить изменения.&lt;br /&gt;
&lt;br /&gt;
И чтение, и запись файлов осуществляются с помощью библиотеки ''System.IO'' (сокращение от Input/Output – ввод/вывод, т.е. чтение и запись), поэтому нужно поместить ''''using System.IO'''' вверху вашего главного файла проекта. Измените '''class MainClass''' на '''class Snarf''' и удалите строку '''Console.WriteLine()''', оставив метод '''Main()''' пустым.&lt;br /&gt;
&lt;br /&gt;
Первое, что мы сделаем – считаем содержимое одного файла. Содержимое файлов – по крайней мере, тех, что нас интересуют – простой текст, а значит, его можно легко сохранить как данные строкового типа. Создайте файл с именем '''myfile.txt''' в корневом каталоге вашего проекта (там, где ''MonoDevelop'' будет сохранять вашу программу), и введите любой текст.&lt;br /&gt;
&lt;br /&gt;
Встает вопрос: как прочесть содержимое файла в строку? А попробуйте так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
string myfile = File.ReadAllText(&amp;quot;myfile.txt&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вот и все – все, что требуется, чтобы прочитать файл в строку средствами Mono. Для ее вывода можете использовать метод '''Console.Write()''', рассмотренный на прошлом уроке:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
Console.Write(myfile);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Нажмите '''F5''', программа скомпилируется и запустится, и вы должны увидеть содержимое вашего файла в панели '''Application Output''' ['''Вывод приложения'''] внизу MonoDevelop.&lt;br /&gt;
&lt;br /&gt;
=== Алло, оператор? ===&lt;br /&gt;
Пойдем дальше: заставим нашу программу записывать изменения обратно в файл. Добавьте следующие строчки после вызова '''Console.Write()''':&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
myfile += &amp;quot;\nМои крылья как щит... ой, это из другого мультика.&amp;quot;;&lt;br /&gt;
File.WriteAllText(&amp;quot;myfile.txt&amp;quot;, myfile);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Изображение:Img 89 59 1.jpg|thumb|right|300px|Левая панель ''MonoDevelop'' показывает файл решения (по умолчанию) или онлайн-справку. Учтите: некоторые страницы помощи устарели!]]&lt;br /&gt;
В этом коде '''+=''' является оператором: это такой символ, который выполняет операцию (лихо закручено, а?). Из школьной арифметики вы знаете операторы '''+''', '''*''', '''-''', '''/''', они выполняются над двумя числами, по-научному – операндами. А оператор '''=''' берет значение одного операнда и присваивает его другому. Так, выражение '''a=10''' означает, что переменная '''а''' принимает значение '''10'''.&lt;br /&gt;
&lt;br /&gt;
Сейчас ваш труд окупится. Если '''а''' равно '''10''', то как прибавить к нему еще 10? Ага-ага…&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
a = a + 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Работает! Согласно принципу «бритвы Оккама» («при прочих равных условиях, лучшим объяснением будет простейшее»), этот код вообще является наилучшим. Принцип, однако, имеет малоизвестное добавление, под названием «поправка Оккама»: в простейшем решении непременно кроются недостатки. В нашем случае, недостаток тот, что для набора строки требуется 11 нажатий клавиш, а C# позволяет сделать то же самое за 8:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
a += 10;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь применен оператор '''+=''', дитя любви операторов '''+''' (сложения) и '''=''' (присваивания): он прибавляет то, что справа от него, к тому, что слева. Класс! Теперь, с новообретенными знаниями, вы поймете, что код нашей программы добавляет строку ('''Мои крылья как щит...''' – ну, вы знаете, откуда это) к уже существующей строке. Языку C# хватает ума различить, когда '''+=''' используется над числами (для сложения двух чисел), а когда – над строками (для конкатенации двух строк). Мы начинаем новую строку с '''\n''', это информирует Mono о необходимости добавить символ новой строки в существующем файле.&lt;br /&gt;
&lt;br /&gt;
Метод '''WriteAllText()''' относится к методу '''ReadAllText()''' как Wilykit к Wilykat: дайте ему имя файла в качестве первого параметра и текст для записи в качестве второго, а он выполнит всю работу.&lt;br /&gt;
&lt;br /&gt;
Пора вдарить по газам Громокара и ввести конструкции посерьезнее: рассмотрим условные выражения и циклы. Условные выражения нужны, чтобы выполнять действия только при выполнении (истинности) определенного нами условия. Если условное выражение ложно – небо не голубое, возраст пользователя не 26, или что мы там проверяем – то код исполняться не будет. Например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
string Name = &amp;quot;Cheetara&amp;quot;;&lt;br /&gt;
if (Name == &amp;quot;Snarf&amp;quot;) {&lt;br /&gt;
    Console.WriteLine(&amp;quot;Snarf snarf!&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Врезка|&lt;br /&gt;
Заголовок=Когда = ведет к ошибке&lt;br /&gt;
|Содержание=&lt;br /&gt;
Используя одиночный знак '''=''' в условных выражениях, вы рискуете нарваться на проблемы. Например, рассмотрим код&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
if (Name = &amp;quot;Snarf&amp;quot;) {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Этот код на самом деле означает «присвоить &amp;quot;'''Snarf'''&amp;quot; переменной '''Name''', и если это произойдет удачно, то выполнить код внутри фигурных скобок». Такое присваивание, естественно, проходит всегда, и в качестве возвращаемого значения вернется '''true''' и будет выведено сообщение. Если вы часто пишете '''=''', вместо '''==''', то можете решить проблему, просто поменяв местами параметры. То есть, следующие два выражения делают одно и тоже:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
if (Name == &amp;quot;Snarf&amp;quot;) {&lt;br /&gt;
// или...&lt;br /&gt;
if (&amp;quot;Snarf&amp;quot; == Name) {&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Разница состоит в том, что если вы наберете '''=''' вместо '''==''' во втором варианте, то ''MonoDevelop'' откажется компилировать программу, потому что нельзя присвоить строке переменную – &amp;quot;'''Snarf'''&amp;quot; всегда останется &amp;quot;'''Snarf'''&amp;quot;, и никак иначе.&lt;br /&gt;
|Ширина=350px}}&lt;br /&gt;
Данный код ничего не напечатает: хотя переменная '''Name''' существует, ее содержимое не '''Snarf''', а '''Cheetara'''. Заметим, что '''==''' просто еще один оператор, означающий «равняется». Он отличается от оператора присваивания '''=''' (см. врезку ''«Когда = ведет к ошибке»'').&lt;br /&gt;
&lt;br /&gt;
=== Знакомство с циклом ===&lt;br /&gt;
Циклы позволяют выполнять определенный блок кода несколько раз. Например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
Console.Write(&amp;quot;Громо... &amp;quot;);&lt;br /&gt;
Console.Write(&amp;quot;Громо... &amp;quot;);&lt;br /&gt;
Console.Write(&amp;quot;Громо... &amp;quot;);&lt;br /&gt;
Console.Write(&amp;quot;Громокот! Хо!\n&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Строка '''«Громо»''' не раз повторяется, поэтому для ее многократного вывода на экран мы можем запихать ее вовнутрь так называемого «цикла '''for'''»:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
for (int i = 1; i &amp;lt;= 3; ++i) {&lt;br /&gt;
    Console.WriteLine(&amp;quot;Громо... &amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
Console.WriteLine(&amp;quot;Громокот! Хо!\n&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Согласен, в этом примере оба варианта кода имеют те же четыре строчки; ну, а если пришлось бы выполнить операцию 100 раз? Или 100000? Заметим, что '''++''' это сокращение C# для выражения '''+=1''' – оно просто прибавляет единицу к выражению. C# предусматривает несколько разных циклов, и '''for''' – один из них.&lt;br /&gt;
&lt;br /&gt;
=== Идем дальше ===&lt;br /&gt;
Сейчас мы расширим нашу программу таким образом, что она будет считывать все файлы в каталоге, и если у файла расширение '''txt''' – распечатывать его содержимое. Тут нужны и цикл, и условное выражение – о меч Завета, помоги мне постичь непостижимое!&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
string[] files = Directory.GetFiles(&amp;quot;/home/paul&amp;quot;);&lt;br /&gt;
foreach(string file in files) {&lt;br /&gt;
    if (file.EndsWith(&amp;quot;.txt&amp;quot;)) {&lt;br /&gt;
        Console.Write(File.ReadAllText(file));&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Изображение:Img 89 60 1.jpg|thumb|right|200px|Так будет выглядеть наш кэш файлов: в каждой строке по одному имени '''txt'''-файла.]]&lt;br /&gt;
Здесь показано аж 5 нововведений, поэтому позвольте мне разбить все по этапам:&lt;br /&gt;
&lt;br /&gt;
* Если мы передадим '''Directory.GetFiles()''' каталог в качестве единственного параметра, то он вернет нам массив строк ('''string[]''', помните?), содержащий все имена файлов этого каталога.&lt;br /&gt;
* Элементы почти всех массивов можно перебрать с помощью цикла '''foreach''': он извлекает каждый элемент массива, а мы присваиваем значение элемента переменной. В нашем примере, мы заставляем Mono присваивать каждое имя файла строке ''''file''''.&lt;br /&gt;
* У каждой строки есть метод '''EndsWith()''', который возвращает '''true''', если строка заканчивается подстрокой, которую мы передали ей в качестве параметра. Если метод возвращает '''true''', то мы выполняем код внутри фигурных скобок ('''Console.Write(...)''').&lt;br /&gt;
* Вместо того, чтобы присвоить возвращаемое значение '''File.ReadAllText()''' другой строке, мы сразу же передаем его в метод '''Console.Write'''. Так делать можно, и это помогает сделать код чуть короче.&lt;br /&gt;
* Отметим, что C# различает '''File''' (особый класс, позволяющий читать и записывать файлы) и '''file''', строковую переменную, которую мы создали. Все переменные в C# чувствительны к регистру.&lt;br /&gt;
&lt;br /&gt;
{{Врезка|left|&lt;br /&gt;
|Заголовок=Скорая помощь&lt;br /&gt;
|Содержание=Если хотите красиво обработать несколько параметров командной строки, перестаньте использовать конструкцию&lt;br /&gt;
'''args[0]'''. Вместо этого попробуйте использовать цикл '''foreach''' для извлечения каждого параметра командной строки и его последующей обработки.&lt;br /&gt;
|Ширина=250px}}&lt;br /&gt;
&lt;br /&gt;
{{Врезка&lt;br /&gt;
|Заголовок=Говорите в скобках!&lt;br /&gt;
|Содержание=&lt;br /&gt;
Как мы видели в прошлый раз, C# широко использует фигурные скобки '''{''' и '''}''' как маркеры блоков – они отмечают начало и конец блоков кода. Хотя они необходимы для пространств имен, классов и методов, после условных выражений и циклов их использовать не обязательно. В данном случае скобки описывают, какой код исполнит C#, если условное выражение будет истинно или пока условие цикла истинно. При отсутствии скобок выполнится только одно выражение; если оно и вправду одно, зачем писать скобки? Вот, например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
if (Name == &amp;quot;Snarf&amp;quot;) {&lt;br /&gt;
    Console.WriteLine(&amp;quot;Snarf snarf!&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
С тем же результатом можно использовать следующий код:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
if (Name == &amp;quot;Snarf&amp;quot;) Console.WriteLine(&amp;quot;Snarf snarf!&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В этом коде метод '''WriteLine()''' выполнится только тогда, когда Name будет содержать строку '''«Snarf»'''. А все последующие выражения будут выполнены несмотря ни на что – даже если они расположены на той же строке, что вызов '''WriteLine()'''. Использование фигурных скобок рекомендуется при обучении: можно наглядно видеть, какой код относится к циклам и условным выражениям.&lt;br /&gt;
|Ширина=45%}}&lt;br /&gt;
Замените содержимое метода '''Main()''' новым кодом, подставьте вместо '''/home/paul''' ваш собственный каталог с текстовыми '''.txt'''-файлами. Нажмите '''F5''': вы увидите, что все работает, но это скорее код Громомальчика, чем Громомужа.&lt;br /&gt;
&lt;br /&gt;
Вы когда-либо слышали фразу «быстро, качественно, дешево – выбери любые два»? Что ж, раз Linux связан с Open Source, «дешевизна» присутствует по определению. Но вот чудо: Mono позволяет еще и сделать «быстро» и «качественно»! Немного поколдуем, чтоб сделать наш код более быстрым и более функциональным.&lt;br /&gt;
&lt;br /&gt;
Колдовство сидит в методе '''Directory.GetFiles()'''. Сейчас мы передаем ему один параметр, то есть каталог, где хотим искать файлы. Но в C# методы могут выполнять разные действия в зависимости от числа передаваемых параметров. Мы можем ускорить работу нашего кода, задав второй параметр метода '''GetFiles()''', который позволит нам определить фильтр поиска для наших файлов. А именно, вместо того, чтобы использовать '''file.EndsWith(&amp;quot;.txt&amp;quot;)''', используем второй параметр метода '''Directory.GetFiles''', то есть '''*.txt'''. Тогда массив строк '''files''' будет содержать только файлы, заканчивающиеся на '''.txt'''. Можно заставить наш код делать даже больше, определив еще один параметр метода '''Directory.GetFiles''', а именно '''SearchOption.AllDirectories'''. Параметр заставляет Mono искать не только в указанном каталоге, но и во всех его подкаталогах.&lt;br /&gt;
&lt;br /&gt;
Поэтому новый супер-пупер метод Main() будет выглядеть следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
string[] files = Directory.GetFiles(&amp;quot;/home/paul&amp;quot;, &amp;quot;*.txt&amp;quot;, SearchOption.AllDirectories);&lt;br /&gt;
foreach (string file in files) {&lt;br /&gt;
    Console.Write(File.ReadAllText(file));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Эффектный финал ===&lt;br /&gt;
Места в статье уже не хватает – поэтому пора просить древних духов C# превратить этот загнивший код во что-то действительно работающее! Мы уже видели, как можно получить все имена файлов в данном каталоге (и его подкаталогах), и знаем, как читать и записывать файлы. Теперь нам необходимо, чтобы программа выполняла две вещи:&lt;br /&gt;
&lt;br /&gt;
* Если параметры не указаны, то просканировать файловую систему и сохранить список в файле. То есть кэше файлов.&lt;br /&gt;
* Если параметр указан, то использовать его для поиска подходящих файлов, а затем вывести их содержимое на печать.&lt;br /&gt;
&lt;br /&gt;
Наша программа будет делать нечто очень похожее на работу Linux-команды ''updatedb'', используемую для генерации кэша поиска для ''locate''. Но ''updatedb'' не выводит содержимого найденных файлов, значит, наша программа хоть чуть-чуть, да получше!&lt;br /&gt;
&lt;br /&gt;
Вы уже знаете большую часть кода, которая необходима для выполнения этой работы, поэтому давайте сосредотчимся и начнем кодировать. Замените ваш метод '''Main()''' следующим кодом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
if (args.Length == 0) {&lt;br /&gt;
    string[] files = Directory.GetFiles(&amp;quot;/home/paul&amp;quot;, &amp;quot;*.txt&amp;quot;, SearchOption.AllDirectories);&lt;br /&gt;
    File.WriteAllLines(&amp;quot;filecache.snarf&amp;quot;, files);&lt;br /&gt;
} else {&lt;br /&gt;
    string[] cache = File.ReadAllLines(&amp;quot;filecache.snarf&amp;quot;);&lt;br /&gt;
    foreach(string file in cache) {&lt;br /&gt;
        if (file.Contains(args[0])) {&lt;br /&gt;
            Console.Write(File.ReadAllText(file));&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Этот код содержит нечто совершенно новое: '''args.Length'''. В прошлый раз мы видели, что C# передает аргументы в метод '''Main()''' через массив строк ''''args'''' (помните, что массив – это группа объектов одного типа). '''args.Length''' используется, чтобы узнать размер массива (т.е. сколько параметров было передано). Если он равен '''0''', то есть параметры не передавались, то нам необходимо создать кэш имен файлов.&lt;br /&gt;
&lt;br /&gt;
{{Врезка|left|&lt;br /&gt;
|Заголовок=Скорая помощь&lt;br /&gt;
|Содержание=&lt;br /&gt;
Наш код генерирует '''filecache.snarf''', когда запускается без параметров, но вдруг пользователь сначала захочет запустить ее с параметром? В данной ситуации программа даст сбой, так как файла не было создано. Решение – использовать метод '''File.Exists()''': если файл существует, то запускаем поиск. Если нет, то сначала создаем его и потом запускаем поиск.&lt;br /&gt;
|Ширина=150px}}&lt;br /&gt;
Метод '''WriteAllLines()''' очень похож на метод '''WriteAllText()''', за исключением того, что он принимает в качестве второго параметра не одну строку, а массив строк. Нам это очень полезно, так как '''Directory.GetFiles()''' возвращает массив строк, поэтому мы можем просто передать его в '''WriteAllLines()''', нам не понадобится осуществлять построчную запись.&lt;br /&gt;
&lt;br /&gt;
{{Врезка&lt;br /&gt;
|Заголовок=Состояние .NET&lt;br /&gt;
|Содержание=&lt;br /&gt;
На данный момент Microsoft выпустила три версии .NET: 1.0, 1.1 и 2.0. Mono – свободная реализация .NET – поддерживает почти всю реализацию 1.0 и 1.1, и в большинстве случае вы можете на это рассчитывать. В новые версии Mono добавляются многие новые возможности .NET 2.0, включая новые виджеты ''Windows.Forms'' (строительные блоки пользовательского интерфейса в Windows), а также новые методы, например, '''ReadAllText()''' и '''WriteAllText()''', которые мы использовали на этом уроке.&lt;br /&gt;
&lt;br /&gt;
Хотя .NET 2.0 была выпущена только в ноябре 2005, Microsoft уже готова выпустить .NET 3.0, капитальное изменение платформы. Не беспокойтесь: внутренности по большей части останутся прежними. Видите ли, .NET 3.0 был изначально известен как WinFX, и был спроектирован на основе .NET 2.0 с добавлением новых библиотек для поддержки нового пользовательского интерфейса, коммуникаций и тому подобных вещей. Фактически, .NET 3.0 – это .NET 2.0 плюс новый набор библиотек, и Mono не обязательно их реализовывать, если они не требуются.&lt;br /&gt;
|Ширина=30%}}&lt;br /&gt;
И опять мы встречаем нечто новое: '''else'''. Вы уже знакомы с '''if''', условным оператором, выполняющим код при истинности условия. А что если условие ложно? Здесь приходит на помощь '''else'''. Например, следующий код выведет «Ты Громокот!»:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
string Home = &amp;quot;Третья планета&amp;quot;;&lt;br /&gt;
if (Home == &amp;quot;Средиземье&amp;quot;) {&lt;br /&gt;
    Console.WriteLine(&amp;quot;Ты хоббит!&amp;quot;);&lt;br /&gt;
} else {&lt;br /&gt;
    Console.WriteLine(&amp;quot;Ты Громокот!&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В нашей программе ''Snarf'' выражение '''else''' означает «если число передаваемых параметров не 0», то есть параметры были переданы. В этом случае вызывается метод '''ReadAllLines()''', который считывает каждую строку текстового файла в строковый массив.&lt;br /&gt;
&lt;br /&gt;
Наконец, мы переходим к главному блоку кода: мы просматриваем каждую строку в кэше файлов и проверяем ее на соответствие передаваемому параметру. Соответствие осуществляется с помощью специального метода '''Contains()''', выполняемого над строками: передаем в качестве параметра подстроку, а метод возвращает '''true''', если она содержится в строке. Переменная '''args[0]''', как вы узнали из прошлого раза, содержит первый параметр, переданный в командной строке. Если имя файла соответствует параметру, то мы считываем текст файла и выводим его на экран. Между прочим, кроме '''EndsWith()''' и '''Contains()''', к строкам применимы методы '''Replace()''' (заменить одну подстроку другой), '''ToUpper()''' (преобразовать строку в верхний регистр) и '''Trim()''' (чтобы удалить пробелы, символы табуляции и символы новой строки, расположенные в начале и в конце строки).&lt;br /&gt;
&lt;br /&gt;
Вот и все: наш проект закончен. ''Snarf'' роется в файловой системе, выводит на экран все файлы, соответствующие запросу, а Третья планета в очередной раз спасена от Mымм-Ра – и все благодаря Mono! На диске к журналу вы найдете полный код ''Snarf'', а также дополнительные материалы. Обратите внимание на сообщения, которые выводятся при создании кэша файлов; '''numfilesfound''' – это переменная, которая увеличивается каждый раз при нахождении подходящего файла, чтоб мы могли вывести сообщение, если ни одного файла не обнаружится; а также, в случае успеха будет напечатаны имена всех файлов.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Mono: Читаем RSS-ленты ==&lt;br /&gt;
''На минутку оторвались от новостей на Slashdot, и уже боитесь, что отстали от жизни? '''Пол Хадсон''' говорит: прочтите обо всем с Mono – это проще, чем сосчитать до трех...''&lt;br /&gt;
&lt;br /&gt;
{{Врезка|left|&lt;br /&gt;
Заголовок=Наш эксперт&lt;br /&gt;
|Содержание=&lt;br /&gt;
'''Пол Хадсон'''&amp;lt;br&amp;gt;полагает, что Mono – лучшая вещь со времен мультфильма ''Pinky and the Brain'', и сейчас поддерживает два проекта на основе Mono на SourceForge.&lt;br /&gt;
|Ширина=150px}}&lt;br /&gt;
&lt;br /&gt;
[[Изображение:Img 89 62 1.jpg|thumb|right|300px|http://BBC.co.uk применяет таблицу стилей XSL к своей ленте RSS – для ее просмотра в неформатированном виде используйте пункт «Просмотреть исходный код» в контекстном меню браузера.]]&lt;br /&gt;
Интернет завален хламом – блогами людей, страдающих от своих детских страхов, бесчисленными «разборками» фанатов и миллионами часов видео про котят на YouTube. Возникает проблема: как пробраться через этот хлам к вещам действительно интересным? Поможет RSS: эта технология позволяет людям подписаться на интересующие их сайты и затем получать обновления по мере появления изменений. Например, если вы любитель новостей с сайта BBC News, но вам неохота что ни час лазать на него в поисках свежатинки, то RSS – для вас.&lt;br /&gt;
&lt;br /&gt;
В прошлый раз мы разобрались, как работать с файлами, а теперь зайдем дальше: поработаем с XML. Формат XML очень похож на HTML: здесь тоже особым образом помечаются блоки текста. Но, в отличие от HTML, XML определяет не внешний вид текста, а его содержание, и это делает XML идеальным средством для пересылки данных. XML используется во множестве форматов, в том числе и RSS: Really Simple Syndication [очень простое приобретение информации]. RSS определяет способ хранения ленты новостей, обновляемой при каждом изменении на сайте; вы можете скомандовать компьютеру обновлять RSS-ленту каждые десять минут и читать заголовки новостей, не запуская web-браузер.&lt;br /&gt;
&lt;br /&gt;
Mono поставляется с массой инструментов работы с XML, и нам не придется беспокоиться о том, как прочесть файл. Значит, можно сконцентрироваться на том, что мы хотим сделать, а именно:&lt;br /&gt;
&lt;br /&gt;
# Создать программу для скачивания и красивого вывода RSS-лент.&lt;br /&gt;
# Заставить программу отслеживать содержимое ленты и отображать изменения, произошедшие с момента последнего просмотра.&lt;br /&gt;
# Заставить программу сохранять выбранные пользователем ленты новостей.&lt;br /&gt;
&lt;br /&gt;
Как и в прошлый раз, постараемся создать действительно полезную программу. Вперед!&lt;br /&gt;
&lt;br /&gt;
=== Охота на RSS ===&lt;br /&gt;
Во-первых, необходимо ясно понять, как выглядит RSS. Ниже представлена RSS-лента, и вы можете видеть, что у канала ('''channel''', новостная лента) есть заголовок, описание и ссылка. Но это скорее метаинформация – если вас интересуют только новости, можете ее игнорировать. Вы также видите два элемента '''&amp;lt;item&amp;gt;''', хотя их может быть сотня и более, в зависимости от ленты RSS. Эти элементы и есть пункты новостей, содержащие заголовок, описание и ссылки, на сей раз к конкретным новостям. Вот пример:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; ?&amp;gt;&lt;br /&gt;
&amp;lt;rss version=&amp;quot;2.0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;channel&amp;gt;&lt;br /&gt;
        &amp;lt;title&amp;gt;Мой превосходный сайт&amp;lt;/title&amp;gt;&lt;br /&gt;
        &amp;lt;description&amp;gt;Здесь представлено много интересного – не забудьте подписаться!&amp;lt;/description&amp;gt;&lt;br /&gt;
        &amp;lt;link&amp;gt;http://www.example.com&amp;lt;/link&amp;gt;&lt;br /&gt;
        &amp;lt;item&amp;gt;&lt;br /&gt;
            &amp;lt;title&amp;gt;Mono рулит!&amp;lt;/title&amp;gt;&lt;br /&gt;
            &amp;lt;description&amp;gt;Бесплатная реализация .NET покоряет мир&amp;lt;/description&amp;gt;&lt;br /&gt;
            &amp;lt;link&amp;gt;http://www.example.com/news/mono&amp;lt;/link&amp;gt;&lt;br /&gt;
            &amp;lt;guid&amp;gt;http://www.example.com/news/mono&amp;lt;/guid&amp;gt;&lt;br /&gt;
        &amp;lt;/item&amp;gt;&lt;br /&gt;
        &amp;lt;item&amp;gt;&lt;br /&gt;
            &amp;lt;title&amp;gt;Mono побеждает PHP&amp;lt;/title&amp;gt;&lt;br /&gt;
            &amp;lt;description&amp;gt;Согласованные функции – это круто&amp;lt;/description&amp;gt;&lt;br /&gt;
            &amp;lt;link&amp;gt;http://www.example.com/news/monovsphp&amp;lt;/link&amp;gt;&lt;br /&gt;
            &amp;lt;guid&amp;gt;http://www.example.com/news/monovsphp&amp;lt;/guid&amp;gt;&lt;br /&gt;
        &amp;lt;/item&amp;gt;&lt;br /&gt;
    &amp;lt;/channel&amp;gt;&lt;br /&gt;
&amp;lt;/rss&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вы заметите, что у каждого пункта '''&amp;lt;item&amp;gt;''' есть элементы '''&amp;lt;link&amp;gt;''' и '''&amp;lt;guid&amp;gt;'''. 'GUID' (сокращение от Globally Unique Id, уникальный глобальный идентификатор) – любое значение, уникальное для данной новости во всей Сети. Этот пункт обязателен для лент RSS, так как именно по нему программы RSS определяют, видели они новость или нет. Будьте внимательны: GUID обязан быть уникальным не только на своем сайте, но и на других. Простейший (и наиболее распространенный) способ выбора GUID – сделать его ссылкой на новость: уникальность гарантируется.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим реальный пример. Начните новый консольный проект в ''MonoDevelop'' и назовите его по своему вкусу. Наверху, где находятся строки ''''using'''', добавьте следующую:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
using System.XML;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Изображение:Img 89 63 1.jpg|thumb|right|300px|Среда ''MonoDevelop'' превосходна для кодирования, но нам придется использовать CLI, чтобы вставить собственные параметры. Обратите внимание на ссылку System.XML на левой панели!]]&lt;br /&gt;
Далее, на панели '''Solution''' (слева в окне ''MonoDevelop''), правой кнопкой щелкните на '''References''' и в появившемся меню выберите '''Edit References'''. Убедитесь, что там выбрано '''System.XML''', и нажмите '''OK'''. Теперь приведите метод '''Main()''' к следующему виду:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
XmlDocument doc = new XmlDocument();&lt;br /&gt;
doc.Load(&amp;quot;http://tinyurl.com/8mwkm&amp;quot;);&lt;br /&gt;
Console.Write(doc.InnerXml);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ссылка TinyURL вставлена для экономии места – если угодно, укажите полный URL: http://newsrss.bbc.co.uk/rss/newsonline_uk_edition/front_page/rss.xml.&lt;br /&gt;
&lt;br /&gt;
Этот код использует класс '''XmlDocument''' для чтения URL и вывода его на экран. Пока мы ничего особенно не делаем: просто выводим документ на консоль. Нажмите '''F5''', чтобы скомпилировать и запустить программу. Вы увидите в окне '''Application Output''' в ''MonoDevelop'' большой кусок текста. Это наша RSS-лента – не беда, что она выглядит довольно зверообразно: мы ее приручим!&lt;br /&gt;
&lt;br /&gt;
=== Просто заголовки ===&lt;br /&gt;
Для дрессировки RSS есть отличные методы .NET: '''SelectSingleNode()''' и '''SelectNodes()'''. Они позволяют осуществлять поиск нужных данных в XML-документе и извлекать либо самый первый XML-узел (т.е. XML-элемент '''&amp;lt;item&amp;gt;''', прочитанный нашей программой), либо все подходящие узлы.&lt;br /&gt;
&lt;br /&gt;
Итак, мы хотим, чтобы версия номер два нашей программы считывала все новости и для каждой выводила ее заголовок и описание. Вот мой рецепт для ''Hudson RSS Reader v2'':&lt;br /&gt;
&lt;br /&gt;
# Пропустить RSS через '''XmlDocument.load()'''.&lt;br /&gt;
# Отделить интересующие нас элементы '''&amp;lt;item&amp;gt;'''.&lt;br /&gt;
# Просеять элементы с предыдущего шага и при необходимости откинуть их данные на '''Console.Write()'''.&lt;br /&gt;
# Подсолить и подать на стол. Или – по-простому, в синтаксисе C#...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
XmlDocument doc = new XmlDocument();&lt;br /&gt;
doc.Load(&amp;quot;http://tinyurl.com/8mwkm&amp;quot;);&lt;br /&gt;
XmlNodeList items = doc.SelectNodes(&amp;quot;//item&amp;quot;);&lt;br /&gt;
foreach (XmlNode item in items) {&lt;br /&gt;
    Console.WriteLine(item.SelectSingleNode(&amp;quot;title&amp;quot;).InnerText);&lt;br /&gt;
    Console.WriteLine(&amp;quot; &amp;quot; + item.SelectSingleNode(&amp;quot;description&amp;quot;).InnerText);&lt;br /&gt;
    Console.WriteLine(&amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Параметр, передаваемый в '''SelectNodes''' – '''//item''' – известен как '''Xpath'''. Это особый способ поиска элементов внутри XML, и в нашем случае он требует 'брать из XML-документа все элементы '''&amp;lt;item&amp;gt;''''. Двойной слэш '''//''' именно и означает ''''взять любое вхождение''''. Взгляните на следующий XML-документ:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;stuff&amp;gt;&lt;br /&gt;
    &amp;lt;clothing&amp;gt;&lt;br /&gt;
        &amp;lt;item&amp;gt;Брюки&amp;lt;/item&amp;gt;&lt;br /&gt;
        &amp;lt;item&amp;gt;Носки&amp;lt;/item&amp;gt;&lt;br /&gt;
    &amp;lt;/clothing&amp;gt;&lt;br /&gt;
    &amp;lt;news&amp;gt;&lt;br /&gt;
        &amp;lt;item&amp;gt;Релиз Wii состоялся&amp;lt;/item&amp;gt;&lt;br /&gt;
        &amp;lt;item&amp;gt;Xbox 360 - отстой!&amp;lt;/item&amp;gt;&lt;br /&gt;
    &amp;lt;/news&amp;gt;&lt;br /&gt;
&amp;lt;/stuff&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Извлекая из него элементы '''&amp;lt;item&amp;gt;''' при помощи '''Xpath //item''', вы довольны не останетесь: ваш запрос свалит в кучу и новости, и штаны с носками! Вместо использования '''// 'найти любого'''', уточним запрос: скажем, что нам нужны элементы '''&amp;lt;item&amp;gt;''', являющиеся частью элементов '''&amp;lt;news&amp;gt;'''. В '''XPath''' это выглядит как '''/news/item'''.&lt;br /&gt;
&lt;br /&gt;
Впрочем, RSS-лента использует элементы '''&amp;lt;item&amp;gt;''' только для обозначения новостей, поэтому использовать '''//item''' вполне безопасно. Этот поиск возвращает переменную, известную как '''XmlNodeList'''. Если XML-узел (XML node) содержит один XML-элемент, то в '''XmlNodeList''', видимо, находится несколько XML-элементов, верно? Верно. Я просто хотел убедиться, что вы не запутались при обсуждении '''Xpath'''!&lt;br /&gt;
&lt;br /&gt;
Раз уж список новостей получен, остается только их распечатать. В прошлый раз я познакомил вас с циклом '''foreach''', теперь он снова вернулся – и будет работать с '''XmlNodes''', а не просто со строками. Этот цикл перебирает каждую новость, которую возвращает метод '''SelectNodes()''', и присваивает ее переменной item, которую мы можем прочесть. Каждый пункт '''&amp;lt;item&amp;gt;''' в нашем XML-документе содержит несколько интересных подпунктов: заголовок новости, описание, ссылку и т.д. Чтобы извлечь любой из них, необходимо применить к нашему пункту метод '''SelectSingleNode''', который возвращает '''XmlNode'''. Например, чтобы получить заголовок новости, необходимо применить '''item.SelectSingleNode(&amp;quot;title&amp;quot;)'''. Однако метод вернет просто XML-узел, являющийся .NET-представлением XML-элемента '''&amp;lt;item&amp;gt;''', а не содержание XML-узла. Тут пригодится '''InnerText''': он возвращает текстовое содержимое объекта '''XmlNode'''.&lt;br /&gt;
&lt;br /&gt;
Держа все это в голове, посмотрим снова на эту строчку:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
Console.WriteLine(item.SelectSingleNode(&amp;quot;title&amp;quot;).InnerText);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Она работает так: берет текущий узел, затем его заголовок и текстовое содержимое, и выводит на консоль.&lt;br /&gt;
&lt;br /&gt;
Когда все это выведено, вызывается '''Console.WriteLine()''' для вывода пустой строки между новостями.&lt;br /&gt;
&lt;br /&gt;
Вот и все – скомпилируйте и запустите вашу программу с помощью '''F5''' и наслаждайтесь: ваши кулинарные навыки превратили сырые ингредиенты RSS-ленты в вывод на вашем экране!&lt;br /&gt;
&lt;br /&gt;
=== Что нового, малыш? ===&lt;br /&gt;
У нашей программы есть проблема: RSS-ленты бывают очень большими, а людям подавай только свежие новости, появившиеся после последнего опроса ленты. Это действительно проблема: как уследить, что некоторые новости уже прочитаны, и показать только те, которые вы еще не видели? Что ж, возвратитесь назад на 1000 слов, к уникальным глобальным идентификаторам. Вот что я говорил: «Этот пункт обязателен для лент RSS, так как именно по нему программы RSS определяют, видели они новость или нет.» Каждой RSS-новости необходим GUID, однозначно определяющий ее в сети, и его можно использовать для решения проблемы.&lt;br /&gt;
&lt;br /&gt;
Вот алгоритм:&lt;br /&gt;
# Получить ленту RSS.&lt;br /&gt;
# Сохранить все GUID в файле, по одному на строку.&lt;br /&gt;
# В следующий раз, когда будет загружена RSS-лента, будут показаны только новые новости, отсутствующие в кэше GUID.&lt;br /&gt;
&lt;br /&gt;
Всего три шага, но их кодирование немного сложнее. Вот как будет выглядеть метод '''Main()''' – я добавил комментарии, поясняющие, как все работает:&lt;br /&gt;
&lt;br /&gt;
{{Врезка&lt;br /&gt;
|Заголовок=Скорая помощь&lt;br /&gt;
|Содержание=&lt;br /&gt;
Для создания файла есть метод '''File.Create()''', но мы обойдемся без него – метод '''File.AppendAllText()''' автоматически создаст файл, если его не существует.&lt;br /&gt;
|Ширина=120px}}&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
XmlDocument doc = new XmlDocument();&lt;br /&gt;
doc.Load(&amp;quot;http://tinyurl.com/8mwkm&amp;quot;);&lt;br /&gt;
// Этот массив строк будет хранить содержимое кэш-файла&lt;br /&gt;
string[] guidcache;&lt;br /&gt;
if (File.Exists(&amp;quot;guidcache.txt&amp;quot;)) {&lt;br /&gt;
    // У нас есть кэш-файл – так прочтем его!&lt;br /&gt;
    guidcache = File.ReadAllLines(&amp;quot;guidcache.txt&amp;quot;);&lt;br /&gt;
} else {&lt;br /&gt;
    // У нас нет кэш-файла – создадим новый массив строк из 0 элементов (то есть пустой)&lt;br /&gt;
    guidcache = new string[0];&lt;br /&gt;
}&lt;br /&gt;
// Получить все новости…&lt;br /&gt;
XmlNodeList items = doc.SelectNodes(&amp;quot;//item&amp;quot;);&lt;br /&gt;
foreach (XmlNode item in items) {&lt;br /&gt;
    // Положим, что мы собираемся показать эту новость по умолчанию&lt;br /&gt;
    bool showthisitem = true;&lt;br /&gt;
    // Теперь переберем каждый GUID в кэше…&lt;br /&gt;
    foreach (string guid in guidcache) {&lt;br /&gt;
        // … и сравним его с GUID этой новости.&lt;br /&gt;
        if (guid == item.SelectSingleNode(&amp;quot;guid&amp;quot;).InnerText) {&lt;br /&gt;
            // Если у нас есть совпадение – то не показываем эту новость!&lt;br /&gt;
            showthisitem = false;&lt;br /&gt;
            // Следующее выражение говорит C# выйти из цикла – мы уже нашли GUID,&lt;br /&gt;
            // поэтому не надо проверять остальной кэш GUID.&lt;br /&gt;
            break;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    if (showthisitem) {&lt;br /&gt;
        // Сюда попадаем только если GUID не находится в нашем кэше – выводим его на экран!&lt;br /&gt;
        Console.WriteLine(item.SelectSingleNode(&amp;quot;title&amp;quot;).InnerText);&lt;br /&gt;
        Console.WriteLine(&amp;quot; &amp;quot; + item.SelectSingleNode(&amp;quot;description&amp;quot;).InnerText);&lt;br /&gt;
        Console.WriteLine(&amp;quot;&amp;quot;);&lt;br /&gt;
        // … теперь добавим GUID в конец кэш-файла.&lt;br /&gt;
        File.AppendAllText(&amp;quot;guidcache.txt&amp;quot;, item.SelectSingleNode(&amp;quot;guid&amp;quot;).InnerText + &amp;quot;\n&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это простейший вариант кода, но если вы ищете нечто побыстрее в работе, предлагаю вам вставить следующую строку сразу после выражения '''bool showthisitem''':&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
string thisguid = item.SelectSingleNode(&amp;quot;guid&amp;quot;).InnerText;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вместо того, чтобы вызывать '''SelectSingleNode()''' для каждого GUID в кэше и для каждой новости, этот код кэширует GUID в строке символов, и вы можете использовать ее вместо вызовов '''SelectSingleNode()'''.&lt;br /&gt;
&lt;br /&gt;
=== Подпишись сегодня! ===&lt;br /&gt;
Давайте разгоним нашу программу: сейчас в нашем исходном коде навеки прописан URL BBC. А вдруг люди захотят увидеть другие новостные источники? Или читать несколько новостных сайтов и одновременно обновлять их? Для этого требуется кодирование посложнее, но тут-то наша программа и станет по-настоящему полезной.&lt;br /&gt;
&lt;br /&gt;
Вот какой я ее вижу:&lt;br /&gt;
# Когда программа запускается с параметром '''sub''', за которым следует URL, она должна подписаться на эту ленту.&lt;br /&gt;
# Когда программа запускается с параметром '''unsub''', за которым следует URL, она должна отписаться от данной ленты.&lt;br /&gt;
# Когда она запускается без параметров, то должна обновить все RSS-ленты и показать все новые записи.&lt;br /&gt;
# Когда программа запускается с параметром '''reset''', она должна очистить список GUID и обновить ленты, показав все записи во всех лентах.&lt;br /&gt;
&lt;br /&gt;
В общем, не очень далеко от уже готового кода, но есть одна особенность: пунктам 2 и 3 необходимо выводить на экран RSS-ленты. Самый тупой способ это сделать – взять кусок кода с печатью ленты, скопировать его и вставить второй раз, но куда лучше создать отдельный метод: его можно вызывать откуда угодно, и код будет сосредоточен в одном месте.&lt;br /&gt;
&lt;br /&gt;
Но сначала надо написать код для подписки на новостные ленты и отказа от нее. Здесь вы можете изучить новую классную штуку – блок '''switch/case'''. Вам уже попадалось условное выражение (вспомните: '''if/else'''), однако его трудновато использовать при проверке множества условий. Блок '''switch/case''' позволяет проверять значение переменной, не засоряя код. Например, простейший код для проверки того, что должна делать программа, выглядит так:&lt;br /&gt;
&lt;br /&gt;
{{Врезка&lt;br /&gt;
|Заголовок=Скорая помощь&lt;br /&gt;
|Содержание=&lt;br /&gt;
Очень важно проверять, сколько аргументов передается в массив '''args''', прежде чем работать с ним, потому что Mono вылетит, если вы попытаетесь прочитать элемент, которого не существует. Будьте внимательны!&lt;br /&gt;
|Ширина=200px}}&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
switch (args.Length) {&lt;br /&gt;
    case 0:&lt;br /&gt;
        // обновить ленты!&lt;br /&gt;
        break;&lt;br /&gt;
    case 1:&lt;br /&gt;
        // осуществить сброс лент!&lt;br /&gt;
        break;&lt;br /&gt;
    case 2:&lt;br /&gt;
        // подписаться или отписаться на новостные ленты!&lt;br /&gt;
        break;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это код проверяет значение переменной '''args.Length''' на равенство '''0''', '''1''' или '''2'''. Значение '''args.Length''' автоматически устанавливается равным числу параметров, передаваемых программе из командной строки, поэтому фактически оно определяет «Как эта программа была запущена?» Если параметры отсутствуют, значит, достаточно обновить ленты новостей. Если имеется один параметр, можно сразу выполнить сброс лент новостей, даже не проверяя, что это за параметр: единственное действие, описываемое одиночным параметром – перегрузка новостных лент [в «настоящей» программе не помешало бы сделать проверку, что этот единственный параметр – ''''reset''''; никто не запрещает пользователю запустить программу с единственным параметром ''''sub'''' или даже ''''asdfghj''''! В последних двух случаях его следует известить об ошибке – например, распечатать список допустимых опций командной строки, – прим. ред.]. Наконец, если передается два параметра, то необходимо проверить, '''sub''' это или '''unsub''', а затем предпринять соответствующее действие.&lt;br /&gt;
&lt;br /&gt;
=== Принимаем решение ===&lt;br /&gt;
[[Изображение:Img 89 65 1.jpg|thumb|right|300px|'''Готовый продукт:''' Программа чтения RSS-лент, помнящая, что вы читали.]]&lt;br /&gt;
Когда '''switch''' натыкается на совпадение, то выполняет код, начиная с найденного места, пока не упрется в другую строку '''case''' или инструкцию '''break'''. Строка ''''break'''' просто сообщает: «С совпадением покончено, переходи в конец блока '''switch/case'''.» В предшественнике C# – C++, если вы не ставили инструкцию '''break''', программа продолжала выполнение следующего выражения '''case''', вне зависимости от того, произошло совпадение или нет. В C# этого не происходит, но '''break''' все равно является обязательным.&lt;br /&gt;
&lt;br /&gt;
Сначала разберемся с подпиской и отказом от лент новостей. Для этого требуется проверить, что аргумент – либо '''sub''', либо '''unsub''', затем добавить ленту в список подписки. Вот как это происходит:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
case 2:&lt;br /&gt;
    // Подпишись или откажись!&lt;br /&gt;
    if (args[1] == &amp;quot;&amp;quot;) return;&lt;br /&gt;
    if (args[0] == &amp;quot;sub&amp;quot;) {&lt;br /&gt;
        // Добавить сайт в существующий список&lt;br /&gt;
        File.AppendAllText(&amp;quot;sitelist.txt&amp;quot;, args[1] + &amp;quot;\n&amp;quot;);&lt;br /&gt;
    } else {&lt;br /&gt;
        if (File.Exists(&amp;quot;sitelist.txt&amp;quot;)) {&lt;br /&gt;
            // Удалить сайт из списка&lt;br /&gt;
            string[] sitelist = File.ReadAllLines(&amp;quot;sitelist.txt&amp;quot;);&lt;br /&gt;
            File.Delete(&amp;quot;sitelist.txt&amp;quot;);&lt;br /&gt;
            foreach (string site in sitelist) {&lt;br /&gt;
                if (site == args[1]) {&lt;br /&gt;
                    // Да! именно этот сайт надо удалить; игнорируем его&lt;br /&gt;
                } else {&lt;br /&gt;
                    File.AppendAllText(&amp;quot;sitelist.txt&amp;quot;, site + &amp;quot;\n&amp;quot;);&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    break;&lt;br /&gt;
&amp;lt;/source&amp;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;
Мы используем параметр '''reset''', чтобы очистить GUID'ы для всех наших RSS-лент – тогда наша программа скачает все новости из новостных лент. Если вы хотите разрешить людям предоставлять параметр URL для '''reset''', чтобы сбросить только конкретную ленту, то самый простой способ это сделать – хранить GUID в отдельных файлах: вместо '''guidcache.txt''' у вас может быть '''guid-news.bbc.co.uk.txt'''. Чтобы очистить кэш GUID для одного сайта, просто удалите соответствующий ему файл.&lt;br /&gt;
|Ширина=250px}}&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
switch (args.Length) {&lt;br /&gt;
    case 0:&lt;br /&gt;
        // Обновить!&lt;br /&gt;
        ReadFeeds();&lt;br /&gt;
        break;&lt;br /&gt;
    case 1:&lt;br /&gt;
        // Сброс!&lt;br /&gt;
        File.Delete(&amp;quot;guidcache.txt&amp;quot;);&lt;br /&gt;
        ReadFeeds();&lt;br /&gt;
        break;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Метод '''ReadFeeds()''' – то самое повторное использование кода, о котором я говорил: можно было вставить весь код для чтения новостей прямо в case-выражение, но гораздо лучше создать собственный метод, '''ReadFeeds()'''. Итак, если ваша программа выполняется без параметров, сразу же вызывается метод '''ReadFeeds()'''; а если с параметром, мы очищаем кэш GUID, а уж потом вызываем '''ReadFeeds()'''.&lt;br /&gt;
&lt;br /&gt;
Метод '''ReadFeeds()''' в принципе такой же, что и старый код для чтения RSS, но я боюсь, что его придется модифицировать, если вы захотите читать ленты с нескольких сайтов. Для этого необходимо в списке подписки перебрать в цикле все сайты, а в каждом сайте – все его новости. Вот главная часть:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
string[] sitelist;&lt;br /&gt;
if (File.Exists(&amp;quot;sitelist.txt&amp;quot;)) {&lt;br /&gt;
    sitelist = File.ReadAllLines(&amp;quot;sitelist.txt&amp;quot;);&lt;br /&gt;
} else {&lt;br /&gt;
    sitelist = new string[0];&lt;br /&gt;
}&lt;br /&gt;
foreach (string site in sitelist) {&lt;br /&gt;
    XmlDocument doc = new XmlDocument();&lt;br /&gt;
    doc.Load(site);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь нет ничего нового, но этот код идеально завершает нашу программу. Нажмите '''F8''', чтобы скомпилировать ее, затем откройте терминал и перейдите туда, где расположен проект ''MonoDevelop''. Далее зайдите в каталог '''bin/Debug''', там находится исполняемый файл. Запустите его – и, я думаю, вы согласитесь, что программа и вправду полезна!&lt;br /&gt;
&lt;br /&gt;
Мы прошли немалый путь: вы больше не боитесь XML, вы поняли, что создавать свои методы – это хороший стиль, и изучили блок '''switch/case''', благодаря которому условные выражения выглядят опрятно. А главное, вы создали свое второе полезное рабочее приложение на C# с помощью Mono – молодцы!&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/%D0%A8%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD:%D0%A6%D0%B8%D0%BA%D0%BB/Mono</id>
		<title>Шаблон:Цикл/Mono</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/%D0%A8%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD:%D0%A6%D0%B8%D0%BA%D0%BB/Mono"/>
				<updated>2008-04-27T15:21:52Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: Новая: {{цикл|C# для начинающих| * Часть 1: И снова Hello World * Часть 2: Работаем с файлами * [[LXF90:Mono|Ч...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{цикл|C# для начинающих|&lt;br /&gt;
* [[LXF87-88:Mono|Часть 1: И снова Hello World]]&lt;br /&gt;
* [[LXF89:Mono|Часть 2: Работаем с файлами]]&lt;br /&gt;
* [[LXF90:Mono|Часть 3: Связь с библиотеками]]&lt;br /&gt;
* [[LXF91:Mono|Часть 4: Программируйте с GTK]]&lt;br /&gt;
* [[LXF92:Mono|Часть 5: Объекты и обобщённые типы]]&lt;br /&gt;
* [[LXF93:Mono|Часть 6:]]&lt;br /&gt;
* [[LXF94:Mono|Часть 7: Используем многопоточность]]&lt;br /&gt;
* [[LXF95:Mono|Часть 8: Работа с базами данных]]&lt;br /&gt;
* [[LXF96:Mono|Часть 9: Создание чат-клиента]]&lt;br /&gt;
* [[LXF97:Mono|Часть 10:]]&lt;br /&gt;
* [[LXF98:Mono|Часть 11: Назад в Unix]]&lt;br /&gt;
* [[LXF99:Mono|Часть 12: Рецепты]]&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF99:%D0%A4%D0%B0%D0%B9%D0%BB%D1%8B</id>
		<title>LXF99:Файлы</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF99:%D0%A4%D0%B0%D0%B9%D0%BB%D1%8B"/>
				<updated>2008-04-27T15:05:15Z</updated>
		
		<summary type="html">&lt;p&gt;Lockal: восстановление кавычек в коде  AWB&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Файлы: ищите и обрящете ==&lt;br /&gt;
&lt;br /&gt;
Засунули что-то неизвестно куда? Рецепт майонеза? Письма тетушки Гвен? Огромный скачанный файл? Не беда! Д-р '''Крис Браун''' все вам найдет.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Один из способов оценки относительной важности задач, ради которых люди используют Linux — определение количества различных приложений, написанных для решения этих задач. Исходя из огромного количества программ «поиска чего-нибудь», можно заключить, что чаще всего люди сразу же что-то теряют! На этом уроке мы проведем обзор ряда приложений, с помощью которых можно искать файлы и прочие данные по их названию, атрибутам или содержимому.&lt;br /&gt;
&lt;br /&gt;
=== Поиск по имени файла ===&lt;br /&gt;
&lt;br /&gt;
Самый простой поиск — это поиск по имени файла, и здесь удобно начать с шаблона имени файла в оболочке. Например, команда&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  $ ls *invoice*&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
выведет список всех файлов текущего каталога, имена которых содержат строку '''invoice'''. Не очень впечатляет? Тогда попробуйте&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  $ ls */*invoice*&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Эта команда выведет список всех файлов со строкой '''invoice''' в имени, которые содержатся в текущем каталоге и во всех его подкаталогах. Можно расширить диапазон поиска до любого желаемого уровня, например, так:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  $ ls *invoice* */*invoice* */*/*invoice*&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для поиска файла по имени во всей файловой системе подойдет утилита ''slocate''. Например, команда&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  $ slocate invoice&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
найдет все файлы, имена которых содержат строку '''invoice'''. Так как ''slocate'' использует индексированный список имен файлов, то работает она с молниеносной быстротой. Этот индекс формируется программой ''updatedb'' (то же самое делает команда ''slocate'' с ключом '''-u'''), обычно запускаемой раз в день с помощью ''cron'' или ''anacron''. В моем дистрибутиве Ubuntu 7.04 база данных ''slocate'' находится в файле '''/var/lib/slocate/slocate.db'''. Это единственный недостаток ''slocate'' — команда не найдет файлы, которые были созданы после последнего запуска ''updatedb''.&lt;br /&gt;
&lt;br /&gt;
{{Врезка&lt;br /&gt;
    |Заголовок=Прочь, дурные вести…&lt;br /&gt;
    |Содержание=В выводе ''find'' часто можно видеть вереницы сообщений об ошибках, касающихся каталогов, к которым у вас нет прав доступа. Иногда из-за них невозможно добраться до значимой информации. А подавить их легко: отправьте их в устройство «черной дыры» – '''/dev/null''', приписав к командной строке '''2&amp;gt; /dev/null'''.&lt;br /&gt;
    |Ширина=200px}}&lt;br /&gt;
&lt;br /&gt;
=== S значит «безопасный» ===&lt;br /&gt;
&lt;br /&gt;
Если вам интересно, то '''s''' в названии команды ''slocate'' восходит к слову «безопасный» ('secure'). И вот в чем здесь дело: программа ''updatedb'' (которая строит индекс) работает с привилегиями администратора, чтобы иметь доступ ко всем файлам. Поэтому в индексе '''slocate.db''' могут быть файлы, невидимые обычным пользователям (например, системные файлы или личные файлы других пользователей). Индекс ''slocate'' включает информацию о владельце файла и правах доступа, и программа ''slocate'' не покажет те файлы, соваться в которые вам не полагается. По-моему, раньше была еще программа ''locate'', не отличавшаяся такой щепетильностью, но в современных дистрибутивах Linux ''slocate'' и ''locate'' указывают на одну и ту же утилиту.&lt;br /&gt;
&lt;br /&gt;
=== Спецпоиск: which и whereis ===&lt;br /&gt;
&lt;br /&gt;
{{Врезка&lt;br /&gt;
    |Заголовок=Почему это не команда?&lt;br /&gt;
    |Содержание=Иногда результат команды ''which'' может ввести в заблуждение, если переданная ей команда окажется также и встроенной командой оболочки ''bash''. Например, результат выполнения команды&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 $ which kill&lt;br /&gt;
 /bin/kill&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
сообщает, что утилита ''kill'' находится в каталоге '''/bin'''. Однако ''kill'' – это и встроенная команда ''bash'', поэтому если я введу команду типа &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 $ kill -HUP 1246,&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
будет выполнена встроенная команда ''kill'', а не внешняя.&lt;br /&gt;
&lt;br /&gt;
Чтобы узнать, является ли команда встроенной, псевдонимом ('''alias''') или внешней, можно использовать команду '''type''', например, так:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 $ type kill&lt;br /&gt;
 kill is a shell builtin&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
    |Ширина=200px}}&lt;br /&gt;
&lt;br /&gt;
Для полноты картины упомянем о более узко направленных утилитах для поиска: ''whereis'' и ''which''. Программа ''whereis'' производит поиск исполняемого файла, исходного кода и документации (страницы руководства) для заданной команды, просматривая каталоги из заранее определенного списка. Например, команда:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 $ whereis ls&lt;br /&gt;
 ls: /bin/ls /usr/share/man/man1/ls.1.gz&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
выводит информацию о местонахождении исполняемого (двоичного) файла и ''man''-страницы для команды ''ls''. Команда ''which'' еще более специализирована. Она просто ищет путь до заданной команды и выводит первый результат. Например, команда&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 $ which vi&lt;br /&gt;
 /usr/bin/vi&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
сообщает, что команда ''vi'' — это исполняемый файл '''/usr/bin/vi'''. По сути, это ответ на вопрос: «Если бы я ввел команду ''vi'', то какая программа запустилась бы на самом деле?»&lt;br /&gt;
&lt;br /&gt;
=== Накачанный поиск: find ===&lt;br /&gt;
&lt;br /&gt;
На другом конце шкалы — утилита-чемпион поиска, ''find''. Кроме поиска по имени файла, через ''find'' возможен поиск по владельцу, правам доступа, времени последнего доступа, размеру файла и многим другим критериям. Плата за эту гибкость, естественно, сложный синтаксис командной строки. Вот вам пример, чтобы вы ухватили идею, а в детали мы углубимся позже:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 $ find /etc -name '*.conf' -user cupsys -print&lt;br /&gt;
 find: /etc/ssl/private: Permission denied&lt;br /&gt;
 find: /etc/cups/ssl: Permission denied&lt;br /&gt;
 /etc/cups/cupsd.conf&lt;br /&gt;
 /etc/cups/printers.conf&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В этом примере команда ''find'' ищет в каталоге '''/etc''' (и во вложенных каталогах) все файлы, имена которых заканчиваются на '''.conf''' и владельцем которых является пользователь ''cupsys''.&lt;br /&gt;
&lt;br /&gt;
В общем случае синтаксис команды find таков:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  $ find &amp;lt;где искать&amp;gt; &amp;lt;что искать&amp;gt; &amp;lt;что с этим делать&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Часть «где искать» — просто список каталогов для поиска, разделенных пробелами. Для каждого из них ''find'' рекурсивно спустится во все вложенные каталоги. В таблице «Критерии поиска ''find''» в конце сттьи перечислены самые полезные критерии поиска — часть «что искать», а во врезке в таблице поменьше, «Действия ''find''», перечислены самые полезные действия (часть «что с этим делать»). Оба эти перечня не полны: для более подробной информации обратитесь к ''man''-странице. Если никакого действия не задано, подразумевается '''-print''', в результате которого путь и имя файла передаются в стандартный поток вывода — так команда ''find'' используется чаще всего. Пожалуй, стоит упомянуть, что многие критерии поиска ''find'' используются скорее с целью выполнения над найденными файлами каких-либо административных операций (допустим, резервного копирования), чем для того, чтобы помочь найти файлы, которые вы случайно посеяли.&lt;br /&gt;
&lt;br /&gt;
=== Действия find ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! ДЕЙСТВИЕ&lt;br /&gt;
! ОПИСАНИЕ&lt;br /&gt;
|-&lt;br /&gt;
| -print&lt;br /&gt;
| Выводит полный путь с именем файла в стандартный вывод&lt;br /&gt;
|-&lt;br /&gt;
| -ls&lt;br /&gt;
| Выводит полный листинг файла (эквивалентно команде ls -dils)&lt;br /&gt;
|-&lt;br /&gt;
| -delete&lt;br /&gt;
| Удаляет файл&lt;br /&gt;
|-&lt;br /&gt;
| -exec command&lt;br /&gt;
| Выполняет указанную команду. Все последующие аргументы до появления; считаются аргументами команды. Строка {} заменяется именем текущего файла.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Критерии поиска для find ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! СИНТАКСИС&lt;br /&gt;
! ОПИСАНИЕ&lt;br /&gt;
! ПРИМЕР&lt;br /&gt;
|-&lt;br /&gt;
| -name string&lt;br /&gt;
| Имя файла соответствует строке (можно употреблять шаблоны)&lt;br /&gt;
| -name '*.jpg'&lt;br /&gt;
|-&lt;br /&gt;
| -iname string&lt;br /&gt;
| То же самое, что -name, но без учета регистра&lt;br /&gt;
| -iname '*tax*'&lt;br /&gt;
|-&lt;br /&gt;
| -user username&lt;br /&gt;
| Владельцем файла является username&lt;br /&gt;
| -user chris&lt;br /&gt;
|-&lt;br /&gt;
| -group groupname&lt;br /&gt;
| Группой владельца файла является groupname&lt;br /&gt;
| -group admin&lt;br /&gt;
|-&lt;br /&gt;
| -type x&lt;br /&gt;
| Файл типа 'x'. Возможные типы:&lt;br /&gt;
  f – обыкновенный файл&lt;br /&gt;
  d – каталог&lt;br /&gt;
  l – символическая ссылка&lt;br /&gt;
  c – символьное устройство&lt;br /&gt;
  b – блочное устройство&lt;br /&gt;
  p – именованный канал (FIFO)&lt;br /&gt;
| -type d&lt;br /&gt;
|-&lt;br /&gt;
| -size +N&lt;br /&gt;
| Размер файла больше N блоков по 512 байт (суффикс c — для байт, k — для килобайт, M — для мегабайт)&lt;br /&gt;
| -size +100M&lt;br /&gt;
|-&lt;br /&gt;
| -size -N&lt;br /&gt;
| Размер файла меньше N блоков (суффикс c — для байт, k — для килобайт, M — для мегабайт)&lt;br /&gt;
| -size -50c&lt;br /&gt;
|-&lt;br /&gt;
| -mtime -N&lt;br /&gt;
| Последнее изменение файла было менее чем N дней назад&lt;br /&gt;
| -mtime -1&lt;br /&gt;
|-&lt;br /&gt;
| -mtime +N&lt;br /&gt;
| Последнее изменение файла было менее чем N дней назад&lt;br /&gt;
| -mtime -1&lt;br /&gt;
|-&lt;br /&gt;
| -mmin -N&lt;br /&gt;
| Последнее изменение файла было менее чем N минут назад&lt;br /&gt;
| -mmin -10&lt;br /&gt;
|-&lt;br /&gt;
| -perm mode&lt;br /&gt;
| Точное соответствие прав доступа к файлам. Права доступа могут быть записаны в восьмеричном виде или в символьной нотации, поддерживаемой chmod&lt;br /&gt;
| -perm 644&lt;br /&gt;
|-&lt;br /&gt;
| -perm -mode&lt;br /&gt;
| Установлены все биты разрешений, указанные в mode&lt;br /&gt;
| -perm -ugo=x&lt;br /&gt;
|-&lt;br /&gt;
| -perm /mode&lt;br /&gt;
| Установлен любой из битов разрешений, указанных в mode&lt;br /&gt;
| -perm /011&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Учимся на примерах ===&lt;br /&gt;
&lt;br /&gt;
{{Врезка&lt;br /&gt;
    |Заголовок=Правда о find&lt;br /&gt;
    |Содержание=Отдельные части синтаксиса команды ''find'' называют выражениями (или, более формально, предикатами). Например, '''-uname cupsys''' – это предикат. Команда ''find'' проверяет каждый файл в заданном каталоге и вычисляет значения всех предикатов для этого файла. Каждый предикат возвращает '''true''' или '''false''', и результаты всех предикатов объединяются логическим «И». Если хотя бы один предикат возвращает значение '''false''', значения остальных не вычисляются.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим команду:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 $ find . -user chris -name '*.txt' -print&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Если предикат '''-user chris''' возвращает значение '''false''' (т.е. '''chris''' не является владельцем файла), то значения остальных предикатов не вычисляются. Только если каждый из предикатов '''-user chris''' и '''-name '*.txt'''' возвращает '''true''', вычисляется предикат '''–print''' (который выводит имя файла в стандартный поток вывода и тоже возвращает '''true''').&lt;br /&gt;
&lt;br /&gt;
Этот подход ликвидирует проблему переполнения списка аргументов, которая повредила нам в предыдущем случае. Помните, что ''find'' может искать файлы не только по имени, но и по многим другим параметрам, а ''grep'' позволяет использовать регулярные выражения, а не только фиксированный текст, поэтому возможности здесь гораздо шире, чем может показаться из этого простого примера. Если его синтаксис непонятен, прочтите врезку «Правда о ''find''» слева вверху. В этом примере предикат '''-exec grep -q Hudson {} \;''' возвращает ''true'', если ''grep'' находит вхождение строки '''Hudson''' в заданном файле, и '''false''', если нет. Если значение предиката – '''false''', ''find'' не вычисляет следующие выражения, т.е. не выполняет действие '''-print'''.&lt;br /&gt;
    |Ширина=400px}}&lt;br /&gt;
Чтобы разобраться во всем синтаксисе команды, потребуется время, поэтому, быть может, пригодятся некоторые примеры…&lt;br /&gt;
&lt;br /&gt;
'''Пример 1''' Это простой поиск по имени файла. Поиск начинается в моем домашнем каталоге, ищутся все файлы '''PowerPoint (.ppt)'''. Обратите внимание, что мы поместили шаблон имени файла в кавычки, чтобы оболочка не развернула его. Мы хотим передать команде именно аргумент ''''*.ppt'''', а о соответствии шаблону пусть заботится ''find''.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 $ find ~ -name '*.ppt'&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Пример 2''' В разделе «что искать» может быть несколько условий, и по умолчанию они объединяются через «логическое И», то есть при поиске отбираются файлы, для которых выполняются все условия. К примеру, поищем подкаталоги в '''/var''', владельцем которых является '''daemon''':&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 $ find /var -type d -user daemon&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Пример 3''' Показывает, как объединить условия по «ИЛИ» вместо объединения по «И». В каталоге '''/etc''' мы ищем либо файлы, владельцем которых является '''cupsys''', либо пустые файлы:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 $ find /etc -user cupsys -or -size 0&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Пример 4''' Оператор '''!''' используется, чтобы получить отрицание от условия. Найдем файлы в каталоге '''/bin''', владельцем которых не является '''root''':&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 $ find /usr/bin ! -user root&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Пример 5''' Условия, содержащие числовые сравнения, часто сбивают с толку. Помните, что «+» перед числом означает «больше чем», «-» — «меньше чем», а если нет ни того, ни другого — ''find'' ищет точное соответствие. В трех строках ниже производится три поиска файлов: тех, что были изменены за последние десять минут, более чем год назад и ровно 4 дня назад (третий поиск, наверное, не самый остро необходимый).&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 $ find ~ -mmin -10&lt;br /&gt;
 $ find ~ -mtime +365&lt;br /&gt;
 $ find ~ -mtime 4&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Пример 6''' Из всех условий, наверное, сложнее всего те, в которых есть проверка по правам доступа к файлу. Вот неплохой пример — он производит поиск файлов с правами доступа '''644''' (в символьном виде их можно представить как '''rw-r--r--'''):&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 $ find ~ -perm 644&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Пример 7''' Поищем файлы, изменять которые разрешено каждому (то есть и владельцу, и группе и всем остальным). Приведенные варианты одинаковы; в первом используется традиционная запись в восьмеричной системе, во втором — символьная запись, применяемая командой ''chmod'':&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 $ find ~ -perm -222&lt;br /&gt;
 $ find ~ -perm -ugo=w&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Пример 8''' Теперь ищем файлы, изменять которые можно кому-то конкретно: или владельцу, или группе владельца, или остальному миру&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 $ find ~ -perm /222&lt;br /&gt;
 $ find ~ -perm /ugo=w&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Пример 9''' Пока мы использовали только действие по умолчанию '''-print''', которое выводит список файлов. Вот пример, в котором используется действие '''-exec''', которое перемещает все найденные файлы в каталог для резервного копирования. Здесь есть несколько вещей, которые нужно отметить. Обозначение '''{}''' будет заменено на полный путь найденного файла, а '''';'''' используется для обозначения окончания команды, следующей за '''-exec'''. Помните, что '''';'''' — это также специальный символ оболочки, и нужно поставить перед ним обратный слэш, чтобы оболочка его не обрабатывала.&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  $ find ~ -mtime +365 -exec mv {} /tmp/mybackup \;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Врезка&lt;br /&gt;
    |Заголовок=Скорая помощь&lt;br /&gt;
    |Содержание=В Linux доступен поиск через '''Google Desktop 1.0'''. Для запуска он требует ''glibc 2.3.2+'' и ''gtk+ 2.2.0'' и выше. В нашем обзоре в [[LXF97:Google Desktop|LXF97]] мы дали ему '''6/10''', так как сочли, что ему еще есть куда расти. Загрузите его и сделайте выводы сами!&lt;br /&gt;
    |Ширина=200px}}&lt;br /&gt;
&lt;br /&gt;
=== Неважно, как его звать; внутри-то что? ===&lt;br /&gt;
&lt;br /&gt;
Как мы убедились, средства поиска типа ''find'' могут искать файлы по имени, размеру, владельцу, времени доступа и многим другим параметрам, но не могут искать файлы по содержимому. Оказывается, файлы достаточно изящно находятся по содержимому при помощи ''grep'', используемой совместно с шаблонами оболочки для файлов. Вот пример, взятый из моей собственной файловой системы:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 $ grep -l Hudson */*&lt;br /&gt;
 Desktop/suse_book_press_release.txt&lt;br /&gt;
 google-earth/README.linux&lt;br /&gt;
 Mail/inbox.ev-summary&lt;br /&gt;
 Mail/sent-mail.ev-summary&lt;br /&gt;
 snmp_training/enterprise_mib_list&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь мы просим ''grep'' вывести имена файлов, содержащих строку '''Hudson'''. Шаблон '''*/*''' разворачивается оболочкой и означает список всех файлов, находящихся на один уровень ниже текущего каталога. Если нужно наложить некоторые условия на имя файла, это можно сделать примерно так:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 $ grep -l Hudson */*.txt&lt;br /&gt;
 Desktop/search_tools.txt&lt;br /&gt;
 Desktop/suse_book_press_release.txt&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
тогда команда будет искать только файлы с расширением '''.txt'''. В принципе, можно расширить диапазон поиска и на большее количество уровней, но на практике весьма вероятна ситуация, когда подставленных файлов будет столько, что строка со списком аргументов превысит допустимую длину. С этим я и столкнулся, попробовав&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 $ grep -l Hudson */* */*/*&lt;br /&gt;
 bash: /bin/grep: Argument list too long&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Более эффективный подход — использовать ''grep'' совместно с ''find''. Поиск файлов с расширением '''.txt''', содержащих строку '''Hudson''' и находящихся в моем домашнем каталоге (''''~''''), выглядит так:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 $ find ~ -name '*.txt' -exec grep -q Hudson {} \; -print&lt;br /&gt;
 /home/chris/Desktop/search_tools.txt&lt;br /&gt;
 /home/chris/Desktop/suse_book_press_release.txt&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Графические средства ===&lt;br /&gt;
&lt;br /&gt;
[[Изображение:LXF99 find1.jpg|thumb|В этом примере добавлен еще один критерий поиска, но при желании можно задать их намного больше.]]&lt;br /&gt;
&lt;br /&gt;
До сих пор мы занимались утилитами поиска, работающими в командной строке; но, конечно, имеются и графические средства. В '''Gnome''' есть графический инструмент поиска ''gnome-search-tool'', показанный на рис. 1. После запуска программа предоставляет минимально необходимый интерфейс, через который указывается маска для имени файла и каталог для поиска. Постепенно можно добавить новые критерии поиска; некоторые из них показаны на рисунке. Эти критерии понятны из нашего разговора о ''find'', и, честно говоря, для поиска ''gnome-search-tool'' в фоновом режиме запускает ''find''. Откуда я это знаю? Ну, мы попробовали переименовать исполняемый файл ''find'' и обнаружили, что после этого ''gnome-search-tool'' выдал ошибку «Не могу запустить дочерний процесс '''find'''».&lt;br /&gt;
&lt;br /&gt;
В KDE есть похожее средство под названием ''KFind'', с немного иначе организованным интерфейсом: критерии поиска разделены на три вкладки, показанные на рис. 2.&lt;br /&gt;
&lt;br /&gt;
[[Изображение:LXF99 find2.jpg|thumb|Мои эксперименты показали, что KFind не использует find.]]&lt;br /&gt;
&lt;br /&gt;
=== Пустим ищейку по следу ===&lt;br /&gt;
&lt;br /&gt;
{{Врезка&lt;br /&gt;
    |Заголовок=ПК против людей&lt;br /&gt;
    |Содержание=Хотя такие программы, как ''find'' и ''Beagle'', впечатляют, нам пока еще далеко до машинных средств поиска, имитирующих возможности человека. Например, мы не можем спросить компьютер: «Где та картинка с коровами на пляже?» (если, конечно, не позаботились назвать ее cows_on_beach.jpg). Нельзя также потребовать найти все MP3-файлы с соло на виолончели. Поэтому – эй, молодежь! Где ваши таланты? Пора кодировать!&lt;br /&gt;
    |Ширина=200px}}&lt;br /&gt;
&lt;br /&gt;
Названный по имени ищейки, известной острым нюхом и умением выслеживать, ''Beagle'' — в другой лиге средств поиска. Цитирую страницу проекта ''Beagle'' (http://beagleproject.org): «''Beagle'' — это средство поиска, которое исследует ваше личное информационное пространство и находит все, что бы вы ни искали». Оно может искать в документах самого различного типа: обычном тексте, документах '''OpenOffice.org''' и '''Microsoft Office''', файлах '''PDF''' и '''HTML''', '''man'''-страницах, в других источни ках информации, таких как почтовые папки и адресные книги ''Evolution'' и ''KMail'', заметки в ''Tomboy'' и ''KNotes'' и '''RSS'''-листы. (Полный список мож но найти на странице http://beagle-project.org/Supported_Filetypes).&lt;br /&gt;
&lt;br /&gt;
''Beagle'' написан на '''.NET''', и ему необходимы среда выполнения ''Mono'' и несколько библиотек. Полтора года назад я писал книгу, и, пытаясь получить для нее рабочую версию ''Beagle'', столкнулся с мириадами зависимостей и проблемой несовместимости версий. Сейчас, похоже, программа созрела — с большинством современных дистрибутивом поставляется ''Beagle'', который работает «из коробки», а иногда ''Beagle'' интегрируется в ''Gnome''. Внизу показан снимок ''Beagle'' в Ubuntu 7.04. Я поискал по фразе «Linux Format» и нашел немало вхождений в файло вой системе и в почтовом архиве. Для рабочего стола KDE есть графи ческий клиент ''Kerry Beagle''; на экранном снимке в верхней части страницы он показан запущенным в SUSE Linux. Если вам интересно, '''Kerry Beagle''' — другая разновидность гончих; то, что ее название начинается с ''''K'''' — сущий подарок для фанатов KDE.&lt;br /&gt;
&lt;br /&gt;
Для быстрого поиска ''Beagle'' использует предварительно сформи рованный индекс, но этот индекс гораздо динамичнее того, что раз в день создает программа ''slocate''. При первом запуске, ''Beagle'' забирается в ваш домашний каталог и индексирует все данные. Если у вас много файлов, сообщений электронной почты или других документов, или ваш компьютер сильно загружен, для полного индексирования всех данных может потребоваться несколько часов. ''Beagle'' также использует ''inotify'' — индекс динамически обновляется, если в системе происходят какие-то изменения. Индексирование выполняется демоном ''beagled'', который запускается под обычным пользователем (не под администратором) и имеет доступ только к вашему домашнему каталогу. ''Beagle'' — отличное средство поиска информации в вашем личном пространстве, но не в системных файлах. Процесс индексации специально ограничивает использование ресурсов процессора во избежание чрезмерной загрузки компьютера. Однако знайте, что индексы съедают много дискового пространства. '''FAQ''' по ''Beagle'' предупреждает, что размер индекса составляет 5-10 процентов от размера индексируемых данных, но в моей системе он занял около двух процентов (размер индекса — 71 МБ, а файловой системы — 3,6 ГБ). Индекс в виде иерархического набора файлов хранится в каталоге '''~/.beagle'''.&lt;br /&gt;
&lt;br /&gt;
Хотя ''Beagle''' чаще всего используется через графический интерфейс, в нем есть и инструменты командной строки — в частности, ''beagle-query'', и удобные средства администрирования, включая ''beagle-config'', с помощью которого можно настроить процесс индексирования, и ''beagle-status'', который предоставляет регулярно обновляемую информацию о ходе индексирования демоном ''beagled''. '''LXF'''&lt;br /&gt;
&lt;br /&gt;
=== Другой софт ===&lt;br /&gt;
&lt;br /&gt;
''Searchmonkey'' — средство для сравнения файлов и их содержимого на Gtk+. http://searchmonkey.sourceforge.net&lt;br /&gt;
&lt;br /&gt;
''Strigi'' — небольшой поисковый демон для извлечения данных из файлов, например, длительности&lt;br /&gt;
аудиороликов, содержимого документов или разрешения изображений. Не привязан к конкретному рабочему столу (Gnome или KDE). http://strigi.sourceforge.net&lt;br /&gt;
&lt;br /&gt;
''Tracker'' позволяет искать документы так же, как ''Spotlight'' в OS X. http://www.gnome.org/projects/tracker&lt;/div&gt;</summary>
		<author><name>Lockal</name></author>	</entry>

	</feed>