<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>JL&#039;s blog &#187; программирование</title>
	<atom:link href="http://john.5070.info/category/%d0%bf%d1%80%d0%be%d0%b3%d1%80%d0%b0%d0%bc%d0%bc%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5/feed/" rel="self" type="application/rss+xml" />
	<link>http://john.5070.info</link>
	<description>:-)</description>
	<lastBuildDate>Sun, 06 Dec 2009 17:11:56 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>сумасшедший алгоритм</title>
		<link>http://john.5070.info/2009/11/%d1%81%d1%83%d0%bc%d0%b0%d1%81%d1%88%d0%b5%d0%b4%d1%88%d0%b8%d0%b9-%d0%b0%d0%bb%d0%b3%d0%be%d1%80%d0%b8%d1%82%d0%bc/</link>
		<comments>http://john.5070.info/2009/11/%d1%81%d1%83%d0%bc%d0%b0%d1%81%d1%88%d0%b5%d0%b4%d1%88%d0%b8%d0%b9-%d0%b0%d0%bb%d0%b3%d0%be%d1%80%d0%b8%d1%82%d0%bc/#comments</comments>
		<pubDate>Mon, 16 Nov 2009 16:37:40 +0000</pubDate>
		<dc:creator>John Lepikhin</dc:creator>
				<category><![CDATA[Performance]]></category>
		<category><![CDATA[программирование]]></category>
		<category><![CDATA[cluster]]></category>
		<category><![CDATA[алгоритмы]]></category>
		<category><![CDATA[хостинг]]></category>

		<guid isPermaLink="false">http://john.5070.info/?p=220</guid>
		<description><![CDATA[Уже 3-й день размышляю над алгоритмом следующей задачки.
Дано:

Есть кластер. В кластере живёт несколько узлов. В узле живёт несколько веб-серверов. В веб-сервере живёт несколько аккаунтов. В аккаунте живёт несколько сайтов.
Для каждого сайта известна текущая нагрузка. Соответственно, известна нагрузка для каждого из аккаунтов.
Известно количество сайтов в каждом из аккаунтов.
Для каждого аккаунта сказано, на скольких минимум узлах (не [...]]]></description>
			<content:encoded><![CDATA[<p>Уже 3-й день размышляю над алгоритмом следующей задачки.</p>
<p>Дано:</p>
<ol>
<li>Есть кластер. В кластере живёт несколько узлов. В узле живёт несколько веб-серверов. В веб-сервере живёт несколько аккаунтов. В аккаунте живёт несколько сайтов.</li>
<li>Для каждого сайта известна текущая нагрузка. Соответственно, известна нагрузка для каждого из аккаунтов.</li>
<li>Известно количество сайтов в каждом из аккаунтов.</li>
<li>Для каждого аккаунта сказано, на скольких <em>минимум</em> узлах (не веб-серверах) он должен присутствовать. Пусть это будет <strong>μ</strong>.</li>
<li>Для каждого аккаунта известно, какие веб-серверы обрабатывают его в данный момент.</li>
</ol>
<p>Задача состоит в том, чтобы перераспределить аккаунты по веб-серверам так, чтобы</p>
<ol>
<li>Аккаунты с максимальной нагрузкой присутствовали на максимальном числе узлов. Ну и соразмерно все остальные.</li>
<li>Каждый аккаунт представлен минимум на <strong>μ</strong> узлах.</li>
<li>В пределах одного узла каждый аккаунт представлен лишь один раз.</li>
<li>Текущая нагрузка наиболее равномерно распределена между всеми узлами (или с каким-то коэффициентом — не суть).</li>
<li>Сайты максимально равномерно распределены между всеми веб-серверами, чтобы минимизировать объём памяти каждого из процессов веб-серверов.</li>
<li>Сделать это всё так, чтобы изменения коснулись по возможности минимального количества веб-серверов, чтобы затем минимум их пришлось заставить перечитывать конфиг.</li>
<li>Делать это каким-то хитрым алгоритмом т.к. простой перебор на потенциальные десятки тысяч сайтов может отожрать немало проца и памяти&#8230;</li>
</ol>
<p>Понятно, что идеально соблюсти все условия не получится. Соответственно, надо либо расставить приоритеты условиям, либо ввести коэффициент максимальной допустимой погрешности решения. Решение вырастает весьма объёмным даже для простого перебора. Мне страшно представить о часе, когда надо будет искать более изящные решения.</p>
]]></content:encoded>
			<wfw:commentRss>http://john.5070.info/2009/11/%d1%81%d1%83%d0%bc%d0%b0%d1%81%d1%88%d0%b5%d0%b4%d1%88%d0%b8%d0%b9-%d0%b0%d0%bb%d0%b3%d0%be%d1%80%d0%b8%d1%82%d0%bc/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>… И получился GFS :)</title>
		<link>http://john.5070.info/2009/10/%e2%80%a6-%d0%b8-%d0%bf%d0%be%d0%bb%d1%83%d1%87%d0%b8%d0%bb%d1%81%d1%8f-gfs/</link>
		<comments>http://john.5070.info/2009/10/%e2%80%a6-%d0%b8-%d0%bf%d0%be%d0%bb%d1%83%d1%87%d0%b8%d0%bb%d1%81%d1%8f-gfs/#comments</comments>
		<pubDate>Sat, 24 Oct 2009 06:17:27 +0000</pubDate>
		<dc:creator>John Lepikhin</dc:creator>
				<category><![CDATA[программирование]]></category>
		<category><![CDATA[ayatku]]></category>
		<category><![CDATA[Ocaml]]></category>
		<category><![CDATA[функтор]]></category>

		<guid isPermaLink="false">http://john.5070.info/?p=208</guid>
		<description><![CDATA[Доделал «сырую» реализацию тех самых функторов из предыдущего поста. Умеем хранить элементы размером до  эксабайт. Максимальное количество элементов точно не определено, но примерно равно  и изменением буквально десятка байт кода может быть увеличена до примерно . Правда, при этом увеличивается фактический размер ключей и чуть-чуть падает скорость.
Реализованы функторы: Sized (заодно храним фактический размер [...]]]></description>
			<content:encoded><![CDATA[<p>Доделал «сырую» реализацию тех самых функторов из предыдущего поста. Умеем хранить элементы размером до <img src="http://l.wordpress.com/latex.php?latex=2%5E%7B62%7D%20%3D%204611686018427387904%20%3D%204&#038;bg=FFFFFF&#038;fg=000000&#038;s=0" title="2^{62} = 4611686018427387904 = 4" style="vertical-align:-20%;" class="tex" alt="2^{62} = 4611686018427387904 = 4" /> эксабайт. Максимальное количество элементов точно не определено, но примерно равно <img src="http://l.wordpress.com/latex.php?latex=2%5E%7B200%7D&#038;bg=FFFFFF&#038;fg=000000&#038;s=0" title="2^{200}" style="vertical-align:-20%;" class="tex" alt="2^{200}" /> и изменением буквально десятка байт кода может быть увеличена до примерно <img src="http://l.wordpress.com/latex.php?latex=2%5E%7B450%7D&#038;bg=FFFFFF&#038;fg=000000&#038;s=0" title="2^{450}" style="vertical-align:-20%;" class="tex" alt="2^{450}" />. Правда, при этом увеличивается фактический размер ключей и чуть-чуть падает скорость.</p>
<p>Реализованы функторы: Sized (заодно храним фактический размер записи), Splitted (правильнее было бы назвать Striped), Distributed (записи раскидываются по нескольким нижележащим хранилищам), COW (обеспечение почти полной атомарности для всяких сложных хранилищ, типа Splitted, за счёт copy-on-write).</p>
<p>Каким-то сумасшедшим performance пока похвастаться не могу (около 12000 килобайтных выборок в секунду, в случае использования хранилища FileSystem), реализация всё-таки ещё сырая.</p>
<p>Коллега на работе сказанул: «Google BigTable что ли сделал?». Я подумал, и решил, что нет, это Google FS :)</p>
]]></content:encoded>
			<wfw:commentRss>http://john.5070.info/2009/10/%e2%80%a6-%d0%b8-%d0%bf%d0%be%d0%bb%d1%83%d1%87%d0%b8%d0%bb%d1%81%d1%8f-gfs/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Функционалы против классов</title>
		<link>http://john.5070.info/2009/10/%d1%84%d1%83%d0%bd%d0%ba%d1%86%d0%b8%d0%be%d0%bd%d0%b0%d0%bb%d1%8b-%d0%bf%d1%80%d0%be%d1%82%d0%b8%d0%b2-%d0%ba%d0%bb%d0%b0%d1%81%d1%81%d0%be%d0%b2/</link>
		<comments>http://john.5070.info/2009/10/%d1%84%d1%83%d0%bd%d0%ba%d1%86%d0%b8%d0%be%d0%bd%d0%b0%d0%bb%d1%8b-%d0%bf%d1%80%d0%be%d1%82%d0%b8%d0%b2-%d0%ba%d0%bb%d0%b0%d1%81%d1%81%d0%be%d0%b2/#comments</comments>
		<pubDate>Sun, 18 Oct 2009 16:57:30 +0000</pubDate>
		<dc:creator>John Lepikhin</dc:creator>
				<category><![CDATA[Ocaml]]></category>
		<category><![CDATA[программирование]]></category>
		<category><![CDATA[LWT]]></category>
		<category><![CDATA[функтор]]></category>

		<guid isPermaLink="false">http://john.5070.info/?p=203</guid>
		<description><![CDATA[Товарищ (RedChrom) задал вопрос, что я использую больше при разработке на Окамле. Не особо задумываясь ответил, что фифти-фифти. Потом сделал простой grep на свои исходники, и выяснил, что на 80% всё-таки модули и функторы. Причём, объекты и классы по большей части в очень старых исходниках. Сейчас 100% функторы.
Сейчас развлекаюсь написанием универсального интерфейса к разным хранилищам [...]]]></description>
			<content:encoded><![CDATA[<p>Товарищ (RedChrom) задал вопрос, что я использую больше при разработке на Окамле. Не особо задумываясь ответил, что фифти-фифти. Потом сделал простой grep на свои исходники, и выяснил, что на 80% всё-таки модули и функторы. Причём, объекты и классы по большей части в очень старых исходниках. Сейчас 100% функторы.</p>
<p><span id="more-203"></span>Сейчас развлекаюсь написанием универсального интерфейса к разным хранилищам (в первую очередь, это FS, memcached, memcachedb) с записями вида key+value. В качестве основы, создал универсальный интерфейс:</p>

<div class="wp_syntax"><div class="code"><pre class="ocaml" style="font-family:monospace;"><span style="color: #06c; font-weight: bold;">module</span> <span style="color: #06c; font-weight: bold;">type</span> STORAGE <span style="color: #a52a2a;">=</span>
        <span style="color: #06c; font-weight: bold;">sig</span>
                <span style="color: #06c; font-weight: bold;">type</span> t
                <span style="color: #06c; font-weight: bold;">type</span> storage_descr_t
&nbsp;
                <span style="color: #06c; font-weight: bold;">val</span> init<span style="color: #a52a2a;">:</span> storage_descr_t <span style="color: #a52a2a;">-&gt;</span> t init_result
&nbsp;
                <span style="color: #06c; font-weight: bold;">val</span> get<span style="color: #a52a2a;">:</span> t <span style="color: #a52a2a;">-&gt;</span> Key<span style="color: #a52a2a;">.</span><span style="color: #060;">t</span> <span style="color: #a52a2a;">-&gt;</span> get_result Lwt<span style="color: #a52a2a;">.</span><span style="color: #060;">t</span>
                <span style="color: #06c; font-weight: bold;">val</span> get_list<span style="color: #a52a2a;">:</span> t <span style="color: #a52a2a;">-&gt;</span> Key<span style="color: #a52a2a;">.</span><span style="color: #060;">t</span> list <span style="color: #a52a2a;">-&gt;</span> get_result Lwt<span style="color: #a52a2a;">.</span><span style="color: #060;">t</span> list
&nbsp;
                <span style="color: #06c; font-weight: bold;">val</span> delete<span style="color: #a52a2a;">:</span> t <span style="color: #a52a2a;">-&gt;</span> Key<span style="color: #a52a2a;">.</span><span style="color: #060;">t</span> <span style="color: #a52a2a;">-&gt;</span> delete_result Lwt<span style="color: #a52a2a;">.</span><span style="color: #060;">t</span>
&nbsp;
                <span style="color: #06c; font-weight: bold;">val</span> set<span style="color: #a52a2a;">:</span> t <span style="color: #a52a2a;">-&gt;</span> Key<span style="color: #a52a2a;">.</span><span style="color: #060;">t</span> <span style="color: #a52a2a;">-&gt;</span> ?value_size<span style="color: #a52a2a;">:</span>value_size <span style="color: #a52a2a;">-&gt;</span> value <span style="color: #a52a2a;">-&gt;</span> set_result Lwt<span style="color: #a52a2a;">.</span><span style="color: #060;">t</span>
                <span style="color: #06c; font-weight: bold;">val</span> add<span style="color: #a52a2a;">:</span> t <span style="color: #a52a2a;">-&gt;</span> Key<span style="color: #a52a2a;">.</span><span style="color: #060;">t</span> <span style="color: #a52a2a;">-&gt;</span> ?value_size<span style="color: #a52a2a;">:</span>value_size <span style="color: #a52a2a;">-&gt;</span> value <span style="color: #a52a2a;">-&gt;</span> add_result Lwt<span style="color: #a52a2a;">.</span><span style="color: #060;">t</span>
                <span style="color: #06c; font-weight: bold;">val</span> replace<span style="color: #a52a2a;">:</span> t <span style="color: #a52a2a;">-&gt;</span> Key<span style="color: #a52a2a;">.</span><span style="color: #060;">t</span> <span style="color: #a52a2a;">-&gt;</span> ?value_size<span style="color: #a52a2a;">:</span>value_size <span style="color: #a52a2a;">-&gt;</span> value <span style="color: #a52a2a;">-&gt;</span> replace_result Lwt<span style="color: #a52a2a;">.</span><span style="color: #060;">t</span>
        <span style="color: #06c; font-weight: bold;">end</span></pre></div></div>

<p>Написал модуль FileSystem, реализующий такой интерфейс. Поскольку файлы могут быть (условно) бесконечного размера, это стало самой простой реализацией интерфейса. Но не всё в жизни так легко. Например, memcached имеет максимальный размер пары key+value где-то в районе 64KB. А хочется в нём хранить побольше. Да и файловые системы бывают дурные. Напрмер, не позволяют создавать файлы больше 512MB. Поэтому на основе FileSystem (ключевое слово import) был написан маленький модуль FileSystemSized, который помимо value пишет в файлик размер value. Штука, на первый взгляд, бесполезная. Но идём дальше. Создаём функтор Splitted, который принимает модуль с интерфейсом STORAGE и делает модули с тем же уже знакомым нам интерфейсом STORAGE. Этот функтор хитрый: он знает, какого максимум размера value может хранить переданный ему модуль. Если в одну запись не влазит — он бьёт value на кусочки, для каждого кусочка генерит свой уникальный ключ, и таким образом пишет. В первом кусочке он сохраняет реальный размер всего value. Вот зачем нам нужен был модуль FileSystemSized. На основе этого функтора получается чудесный модуль FileSystemSplitted. По образу и подобию можно сделать MemcachedSplitted. Или даже FileSystemSplitted_and_again_Splitted, только я не придумал зачем :)</p>
<p>Мыслим вперёд. Ключ у нас — строчка строгой длины, с равной вероятностью имеющая в первом/втором/третьем/&#8230; байте любое из значений 0..255. На основе первого байта ключа, мы можем раскидать пары key+value на 256 физических хранилищ (ну, или меньше, как захочется). Назовём такой функтор Distributed, и он тоже будет создавать модули с интерфейсом STORAGE. Получается изумительная картинка:</p>

<div class="wp_syntax"><div class="code"><pre class="ocaml" style="font-family:monospace;"><span style="color: #5d478b; font-style: italic;">(* Создаём уже знакомый нам модуль для хранения больших значений
   в маленьких файлах.
*)</span>
<span style="color: #06c; font-weight: bold;">module</span> FileSystemSplitted <span style="color: #a52a2a;">=</span> Splitted<span style="color: #6c6;">&#40;</span>FileSystemSized<span style="color: #6c6;">&#41;</span>
&nbsp;
<span style="color: #5d478b; font-style: italic;">(* Каждое значение хранится в одном файлике, но файлики раскидываются
   по разным директориям.
*)</span>
<span style="color: #06c; font-weight: bold;">module</span> FileSystemDistributed <span style="color: #a52a2a;">=</span> Distributed<span style="color: #6c6;">&#40;</span>FileSystemSized<span style="color: #6c6;">&#41;</span>
&nbsp;
<span style="color: #5d478b; font-style: italic;">(* Каждое значение пилится на части, части раскидываются по разным директориям.
   С remote mount, получаем хранилище бесконечного размера для почти
   бесконечного количества значений.
*)</span>
<span style="color: #06c; font-weight: bold;">module</span> FileSystemDistributedSplitted <span style="color: #a52a2a;">=</span> Splitted<span style="color: #6c6;">&#40;</span>FileSystemDistributed<span style="color: #6c6;">&#41;</span>
&nbsp;
<span style="color: #5d478b; font-style: italic;">(* Каждое значение хранится в одной директории, но там оно пилится на части.
   Директорий для хранения может быть несколько. Хранилище получается тоже
   бесконечным, но наполняется не так равномерно.
 *)</span>
<span style="color: #06c; font-weight: bold;">module</span> FileSystemSplittedDistributed <span style="color: #a52a2a;">=</span> Distributed<span style="color: #6c6;">&#40;</span>FileSystemSplitted<span style="color: #6c6;">&#41;</span></pre></div></div>

<p>Как видите, с помощью фактически одного интерфейса и двух функторов, получаем невероятное, лютое количество вариантов хранилища. Даже круче, чем в GlusterFS или GNU Hurd. А ведь мысль можно продолжить ещё дальше, дописав функторы Raid0 (писать значение в несколько хранилищ), Clustered (создаётся на основе списка хранилищ, умеющих только читать и списка хранилищ, умеющих изменять), Flock (за счёт некоторого performace degradation, делать exclusive lock на записи)&#8230; чем я и занимаюсь :) Замечу, что всё это в функционально чисто, без side-effects (они есть только на уровне хранилища) и безумно типобезопасно.</p>
]]></content:encoded>
			<wfw:commentRss>http://john.5070.info/2009/10/%d1%84%d1%83%d0%bd%d0%ba%d1%86%d0%b8%d0%be%d0%bd%d0%b0%d0%bb%d1%8b-%d0%bf%d1%80%d0%be%d1%82%d0%b8%d0%b2-%d0%ba%d0%bb%d0%b0%d1%81%d1%81%d0%be%d0%b2/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>JavaScript: безопасный код</title>
		<link>http://john.5070.info/2009/10/javascript-%d0%b1%d0%b5%d0%b7%d0%be%d0%bf%d0%b0%d1%81%d0%bd%d1%8b%d0%b9-%d0%ba%d0%be%d0%b4/</link>
		<comments>http://john.5070.info/2009/10/javascript-%d0%b1%d0%b5%d0%b7%d0%be%d0%bf%d0%b0%d1%81%d0%bd%d1%8b%d0%b9-%d0%ba%d0%be%d0%b4/#comments</comments>
		<pubDate>Wed, 07 Oct 2009 03:00:56 +0000</pubDate>
		<dc:creator>John Lepikhin</dc:creator>
				<category><![CDATA[Ocaml]]></category>
		<category><![CDATA[программирование]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[O'Browser]]></category>
		<category><![CDATA[ocamljs]]></category>

		<guid isPermaLink="false">http://john.5070.info/?p=193</guid>
		<description><![CDATA[Давно собирался написать нечто подобное, да всё руки не доходили. Толчком послужил краткий пост на аналогичную тему у моего знакомого.
Как известно, JavaScript — язык c динамической (для классов с утиной) типизацией, с очень плохо развитой системой типов. Стандартный интерпретатор даже в браузерах Mozilla с расширениями разработчика отлавливает минимум ошибок. Практически все эти ошибки — синтаксические. [...]]]></description>
			<content:encoded><![CDATA[<p>Давно собирался написать нечто подобное, да всё руки не доходили. Толчком послужил краткий пост на аналогичную тему у моего знакомого.</p>
<p>Как известно, JavaScript — язык c динамической (для классов с утиной) типизацией, с очень плохо развитой системой типов. Стандартный интерпретатор даже в браузерах Mozilla с расширениями разработчика отлавливает минимум ошибок. Практически все эти ошибки — синтаксические. В результате, писать надёжный код на JavaScript предельно сложно. Положение усугубляет фактическая невозможность запуска программы без использования браузера, т.е. нет никакой песочницы для тестов.</p>
<p>В этой статье я попытаюсь описать некоторые технологии, которые помогут знакомому с Ocaml человеку существенно сократить время написания безопасного, стабильного и более-менее компактного JS-кода. Впрочем, описываемые техники есть и для некоторых других языков с развитой системой типов (например, Haskell).</p>
<p><span id="more-193"></span></p>
<h1>Ocamljs: компилятор Ocaml ⇒ JavaScript</h1>
<p>Скачать: <a href="http://code.google.com/p/ocamljs/">http://code.google.com/p/ocamljs/</a></p>
<p>Всё просто: вы пишете client-side код вашего сайта на Ocaml, а с помощью этого компилятора получаете готовый для использования в браузере JavaScript. Для обеспечения работы, непосредственно к вашему скрипту дописывается около 40KB дополнительного кода. Например. Ни к чему не обязывающий код:</p>

<div class="wp_syntax"><div class="code"><pre class="ocaml" style="font-family:monospace;"><span style="color: #06c; font-weight: bold;">type</span> tree <span style="color: #a52a2a;">=</span>
	<span style="color: #a52a2a;">|</span> Leaf <span style="color: #06c; font-weight: bold;">of</span> int
	<span style="color: #a52a2a;">|</span> Node <span style="color: #06c; font-weight: bold;">of</span> tree list
&nbsp;
<span style="color: #06c; font-weight: bold;">let</span> l <span style="color: #a52a2a;">:</span> tree list <span style="color: #a52a2a;">=</span> <span style="color: #6c6;">&#91;</span><span style="color: #6c6;">&#93;</span>
&nbsp;
<span style="color: #06c; font-weight: bold;">let</span> _ <span style="color: #a52a2a;">=</span>
	<span style="color: #06c; font-weight: bold;">match</span> l <span style="color: #06c; font-weight: bold;">with</span>
	<span style="color: #a52a2a;">|</span> <span style="color: #6c6;">&#91;</span><span style="color: #6c6;">&#93;</span> <span style="color: #a52a2a;">-&gt;</span> Dom<span style="color: #a52a2a;">.</span><span style="color: #060;">window</span><span style="color: #a52a2a;">#</span>alert <span style="color: #3cb371;">&quot;empty list&quot;</span>
	<span style="color: #a52a2a;">|</span> a <span style="color: #a52a2a;">::</span> <span style="color: #6c6;">&#91;</span><span style="color: #6c6;">&#93;</span> <span style="color: #a52a2a;">-&gt;</span> <span style="color: #6c6;">&#40;</span><span style="color: #6c6;">&#41;</span>
	<span style="color: #a52a2a;">|</span> a <span style="color: #a52a2a;">::</span> b <span style="color: #a52a2a;">::</span> <span style="color: #6c6;">&#91;</span><span style="color: #6c6;">&#93;</span> <span style="color: #a52a2a;">-&gt;</span> <span style="color: #6c6;">&#40;</span><span style="color: #6c6;">&#41;</span>
	<span style="color: #a52a2a;">|</span> _ <span style="color: #a52a2a;">-&gt;</span> Dom<span style="color: #a52a2a;">.</span><span style="color: #060;">window</span><span style="color: #a52a2a;">#</span>alert <span style="color: #3cb371;">&quot;unexpected list&quot;</span></pre></div></div>

<p>Компилируем:</p>
<pre>ocamljs -o test.js -I /usr/local/lib/ocaml/3.10.2/dom/ dom.cmjsa test.ml</pre>
<p>Получаем вот такой код:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// .....</span>
<span style="color: #003366; font-weight: bold;">var</span> oc$Dom$ <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #003366; font-weight: bold;">var</span> window$<span style="color: #CC0000;">717</span> <span style="color: #339933;">=</span> window<span style="color: #339933;">;</span>
                            <span style="color: #003366; font-weight: bold;">var</span> document$<span style="color: #CC0000;">718</span> <span style="color: #339933;">=</span> document<span style="color: #339933;">;</span>
                            <span style="color: #000066; font-weight: bold;">return</span> $<span style="color: #009900;">&#40;</span>window$<span style="color: #CC0000;">717</span><span style="color: #339933;">,</span> document$<span style="color: #CC0000;">718</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> oc$<span style="color: #CC0000;">1</span>$ <span style="color: #339933;">=</span>
  <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #003366; font-weight: bold;">var</span> l$<span style="color: #CC0000;">63</span> <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span>
    <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>l$<span style="color: #CC0000;">63</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #003366; font-weight: bold;">var</span> match$<span style="color: #CC0000;">71</span> <span style="color: #339933;">=</span> l$<span style="color: #CC0000;">63</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
      <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>match$<span style="color: #CC0000;">71</span><span style="color: #009900;">&#41;</span>
      <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>match$<span style="color: #CC0000;">71</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #003366; font-weight: bold;">var</span> v$<span style="color: #CC0000;">74</span> <span style="color: #339933;">=</span> oc$Dom$<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
                                      <span style="color: #000066; font-weight: bold;">return</span> _m<span style="color: #009900;">&#40;</span>v$74.<span style="color: #000066;">alert</span><span style="color: #339933;">,</span> v$<span style="color: #CC0000;">74</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#91;</span><span style="color: #3366CC;">&quot;unexpected list&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #339933;">;</span>
      <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #003366; font-weight: bold;">var</span> v$<span style="color: #CC0000;">73</span> <span style="color: #339933;">=</span> oc$Dom$<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
                        <span style="color: #000066; font-weight: bold;">return</span> _m<span style="color: #009900;">&#40;</span>v$73.<span style="color: #000066;">alert</span><span style="color: #339933;">,</span> v$<span style="color: #CC0000;">73</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#91;</span><span style="color: #3366CC;">&quot;empty list&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000066; font-weight: bold;">return</span> $<span style="color: #009900;">&#40;</span>l$<span style="color: #CC0000;">63</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> oc$Std_exit$ <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span>_<span style="color: #009900;">&#40;</span>oc$Pervasives$<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">80</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> $<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000066; font-weight: bold;">return</span> caml_named_value<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<h2>JavaScript compressor</h2>
<p>Как я уже сказал, код получается достаточно объёмным. Частично эту проблему решает gzip (при условии, что и сервер, и браузер имеют его поддержку). Однако, код можно существенно сократить за счёт оптимизации по размеру. Для этого есть ряд готовых online-утилит. Используемые техники:</p>
<ul>
<li>Удаление комментариев</li>
<li>Удаление не несущих синтаксической нагрузки пробелов и переносов строк</li>
<li>Назначение локальным переменным функций более коротких имён</li>
<li>Вынесение длинных повторяющихся констант в переменную с коротким именем</li>
</ul>
<p>Наилучшие результаты показывает Packer (<a href="http://dean.edwards.name/packer/">http://dean.edwards.name/packer/</a>), однако ocamljs компилирует не полностью корректный код — иногда забывает точки с запятой — поэтому Packer генерирует не работающий код. С учётом некорректности оригинального кода, наилучший результат показал Dojo ShrinkSafe (<a href="http://www.dojotoolkit.org/docs/shrinksafe">http://www.dojotoolkit.org/docs/shrinksafe</a>). Рекомендую прогнать код через валидатор (<a href="http://jslint.com/">http://jslint.com/</a>), это в любом случае неплохая идея. Пример кода, получающегося с помощью Dojo ShrinkSafe:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #006600; font-style: italic;">// .....</span>
<span style="color: #003366; font-weight: bold;">var</span> _213<span style="color: #339933;">=</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
<span style="color: #003366; font-weight: bold;">var</span> l$<span style="color: #CC0000;">63</span><span style="color: #339933;">=</span><span style="color: #CC0000;">0</span><span style="color: #339933;">;</span>
<span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>l$<span style="color: #CC0000;">63</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
<span style="color: #003366; font-weight: bold;">var</span> _215<span style="color: #339933;">=</span>l$<span style="color: #CC0000;">63</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>_215<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
<span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>_215<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
<span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
<span style="color: #003366; font-weight: bold;">var</span> v$<span style="color: #CC0000;">74</span><span style="color: #339933;">=</span>_210<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<span style="color: #000066; font-weight: bold;">return</span> _m<span style="color: #009900;">&#40;</span>v$74.<span style="color: #000066;">alert</span><span style="color: #339933;">,</span>v$<span style="color: #CC0000;">74</span><span style="color: #339933;">,</span><span style="color: #009900;">&#91;</span><span style="color: #3366CC;">&quot;unexpected list&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #000066; font-weight: bold;">else</span><span style="color: #009900;">&#123;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span><span style="color: #000066; font-weight: bold;">else</span><span style="color: #009900;">&#123;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span><span style="color: #000066; font-weight: bold;">else</span><span style="color: #009900;">&#123;</span>
<span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
<span style="color: #003366; font-weight: bold;">var</span> v$<span style="color: #CC0000;">73</span><span style="color: #339933;">=</span>_210<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
<span style="color: #000066; font-weight: bold;">return</span> _m<span style="color: #009900;">&#40;</span>v$73.<span style="color: #000066;">alert</span><span style="color: #339933;">,</span>v$<span style="color: #CC0000;">73</span><span style="color: #339933;">,</span><span style="color: #009900;">&#91;</span><span style="color: #3366CC;">&quot;empty list&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #000066; font-weight: bold;">return</span> $<span style="color: #009900;">&#40;</span>l$<span style="color: #CC0000;">63</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #003366; font-weight: bold;">var</span> _218<span style="color: #339933;">=</span><span style="color: #009900;">&#40;</span>_<span style="color: #009900;">&#40;</span>_106<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">80</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>$<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000066; font-weight: bold;">return</span> _9d<span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Код получается практически не читаемым, зато размер сокращается в 2-4 раза.</p>
<p>Быстро сравнить различные компрессоры можно на сайте: <a href="http://compressorrater.thruhere.net/">http://compressorrater.thruhere.net/</a></p>
<h1>O&#8217;Browser: виртуальная машина на JavaScript</h1>
<p>Скачать: <a href="http://ocsigen.org/obrowser/">http://ocsigen.org/obrowser/</a></p>
<p>Ваш код будет скомпилирован в байт-код, закодированный в UUE. Для вызова кода, достаточно вызвать его в виртуальной машине:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">&lt;script src=&quot;vm.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
<span style="color: #339933;">&lt;</span>script type<span style="color: #339933;">=</span><span style="color: #3366CC;">&quot;text/javascript&quot;</span><span style="color: #339933;">&gt;</span>
  <span style="color: #009966; font-style: italic;">/* &lt;![CDATA[ */</span>
    window.<span style="color: #000066;">onload</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
      exec_caml <span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;tutorial.exe.uue&quot;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
  <span style="color: #009966; font-style: italic;">/* ]]&gt; */</span>
<span style="color: #339933;">&lt;/</span>script<span style="color: #339933;">&gt;</span></pre></div></div>

<p>Байт-код получается достаточно объёмным, да и сжатию поддаётся только за счёт слоя gzip. Впрочем, код самой виртуальной машины вполне поддаётся обработке JavaScript компрессоров. Валидность кода получается даже выше, чем у ocamljs. Декомпиляция байт-кода в нормальный JavaScript становится нерешаемой проблемой :)</p>
]]></content:encoded>
			<wfw:commentRss>http://john.5070.info/2009/10/javascript-%d0%b1%d0%b5%d0%b7%d0%be%d0%bf%d0%b0%d1%81%d0%bd%d1%8b%d0%b9-%d0%ba%d0%be%d0%b4/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Программист спит</title>
		<link>http://john.5070.info/2009/07/%d0%bf%d1%80%d0%be%d0%b3%d1%80%d0%b0%d0%bc%d0%bc%d0%b8%d1%81%d1%82-%d1%81%d0%bf%d0%b8%d1%82/</link>
		<comments>http://john.5070.info/2009/07/%d0%bf%d1%80%d0%be%d0%b3%d1%80%d0%b0%d0%bc%d0%bc%d0%b8%d1%81%d1%82-%d1%81%d0%bf%d0%b8%d1%82/#comments</comments>
		<pubDate>Thu, 23 Jul 2009 04:38:50 +0000</pubDate>
		<dc:creator>John Lepikhin</dc:creator>
				<category><![CDATA[программирование]]></category>
		<category><![CDATA[жизнь]]></category>
		<category><![CDATA[психология]]></category>
		<category><![CDATA[работа]]></category>
		<category><![CDATA[сон]]></category>

		<guid isPermaLink="false">http://john.5070.info/?p=156</guid>
		<description><![CDATA[Скопировал этот шедевр из блога коллеги. Оригинальный источник и автор утерян. Читать всем не программистам!
Вот в отпуске побывал впервые в жизни&#8230; а некоторые так за всю жизнь ни разу там и не бывают как я подозреваю.
Не знаю полезно это или нет &#8211; отвлечься вот так от работы на почти целый месяц. Я пока не понял [...]]]></description>
			<content:encoded><![CDATA[<p>Скопировал этот шедевр из блога коллеги. Оригинальный источник и автор утерян. Читать всем <strong>не</strong> программистам!</p>
<p><span id="more-156"></span>Вот в отпуске побывал впервые в жизни&#8230; а некоторые так за всю жизнь ни разу там и не бывают как я подозреваю.</p>
<p>Не знаю полезно это или нет &#8211; отвлечься вот так от работы на почти целый месяц. Я пока не понял какой это возъимеет эффект на производительность труда. Зато во время отпуска я понял кое что о чём много раньше думал и никак не мог осознать.</p>
<p>Меня всегда мучал вопрос &#8211; как объяснить людям никогда не занимавшимся такого рода трудом, каким занимаюсь я то что вот происходит у меня и у таких как я в голове когда мы работаем. Как НЕ программисту представить себе работу программиста и понять наконец чего же происходит и как вообще с этим быть.</p>
<p>И вот я кажется понял. Наверное именно благодаря тому что почти на целый месяц выключился из этого процесса, но помнил что скоро придётся вернуться у нему опять.</p>
<p>Ну вобщем хватит предъистории. Как работает программист.</p>
<p>Работа программиста &#8211; это СОН.</p>
<p>Звучит нелепо, правда?</p>
<p>Если вы хотите представить что именно делает программист во время работы, то легче всего это представить именно так. Он спит!</p>
<p>Продукт труда программиста это продукт сна &#8211; химера. Сновидение записанное специальным языком и переданное электронному устройству для того чтобы продолжаться там когда программист уже проснулся или просто сменил один сон на другой.</p>
<p>Это вы думаете что программист взял задачу, написал программу и задача решилась. Всё не так.</p>
<p>Если взять к примеру задачу нахождения пути выхода из лабиринта. Программист в решении этой задачи не перст который ведёт воображаемую маленькую заблудившуюся девочку незнакомой тропой к выходу. Он и не эта девочка тоже. И не стены лабиринта. Он не выход который надо найти. Он всё это вместе разом.</p>
<p>Для решения задачи программисту приходится стать в своём сознании и лабиринтом, и искомым выходом, и заблудившейся девочкой, и тем перстом что ведёт её куда-то, и теми камушками которые она разбрасывает по дороге чтобы узнавать уже пройденные места. Всё это СНИТСЯ программисту во время работы.</p>
<p>Я не фигурально выражаюсь. Это БУКВАЛЬНО снится. Программист при решении задачи виртуально живёт в создаваемом мире химер, похожих каким-то образом на условия решаемой задачи.</p>
<p>Внешне наблюдение за работающим программистом это тоже самое что наблюдение за спящим человеком. Вы вот сразу засыпаете когда решаете отойти ко сну?</p>
<p>Большинство людей процесс засыпания воспринимают как определённый ритуал. У кого-то он довольно короткий, а у кого-то довольно сложный и длинный. У кого что. Кому-то надо непременно почитать перед сном, кто-то не засыпает если тридцать приседаний не выполнит перед тем как лечь. Так или иначе отход ко сну у каждого происходит по своему и это не просто ЧИК &#8211; и заснул. Хотя бывает у некоторых и так.</p>
<p>Вот тоже самое и в работе программиста. Процесс начала работы это тоже самое. Программист не может просто сесть и начать работать точно также как вот вы не можете сказать себе &#8220;СПИ УЖЕ СКОРЕЙ!&#8221; и отключиться. И общего какого-то способа тоже нет, как нет его в ритуале засыпания.</p>
<p>Кто-то вот считает баранов, которые будучи вызваны к жизни этим вот самым процессом счёта вынуждены потом как-то дальше жить у нас здесь в Новой Зеландии. А кто-то фантазирует. Кто-то следит за своим дыханием, а кто-то просто прилепит чаю с ромашкой и готов.</p>
<p>Это ведь ещё и меняется со временем. Сегодня вот вы легли спать и всё &#8211; уже сладкие грёзы. А завтра ворочаетесь час, два, три и ну никак. Тоже самое и в работе программиста. буквально тоже самое.</p>
<p>Ну и что делать всвязи с этим?</p>
<p>Ну скажем так. Если вы НЕ программист и вы каким-то образом заинтересованы впрямую или косвено в том чтобы он производил-таки продукт своего труда, то вам надлежит понять вот это всё хоть в какой-то более-менее мере.</p>
<p>Вот представьте что от вашего сна зависит ваша жизнь, жизнь выших детей и вообще всё. Представьте что от того как вы спите зависит будут-ли ваши дети учиться в университете или пойдут улицы мести. Представьте что от того насколько красивы, успешны, живучи и полны ваши сновидения зависит жизнь пассажиров в самолётах и качество обслуживания в супермаркетах, а главное от этого зависит содержимое вашего кармана в день зарплаты.</p>
<p>Представили?</p>
<p>Вот это именно так выглядит для нас &#8211; программистов. БУКВАЛЬНО ТАК.</p>
<p>Это вам со стороны кажется что вы просто подошли и спросили который час.</p>
<p>А давайте я вас подойду и спрошу в три часа ночи который час?<br />
Чего страшного-то? Ну и что такого что вы только что заснули?<br />
Я просто спрошу, вы ответите и спите дальше. Чего такого-то?</p>
<p>Так легче понять я думаю будет. На таком примере.</p>
<p>Вот вы представляйте что от вашего сна зависит ВСЁ! Всё при всё. Вот от того как вы сегодня поспите зависит будет завтра чего дома жрать или нет. Зависит будет ваша дочть замужем или нет. Вырастет ваш сын неудачником или добьётся чего-то в жизни. Всё это зависит от того как продуктивно вы сегодня поспите.</p>
<p>Представили?</p>
<p>И вот вы собираетесь начать этот сон. Этот вот самый сон от которого ВСЁ зависит и вы это отчётливо осознаёте.</p>
<p>Скажите вот теперь. Как насчёт спать и одновременно немножко, краем глаза разговаривать, чуть чуть помогать сыну решать арифметику, немножко подглядывать в телевизор и чуть чуть так совсем немного съездить в магазин? Не на долго&#8230;</p>
<p>Как спится, сладко?</p>
<p>Вот теперь подумайте что происходит с программистом к которому раза два-три в час подходят и просят чего-то подсказать, чего-то помочь там вот и тут, чего-то просят его где-то заполнить, отметить и ещё о чём-то не забыть.</p>
<p>Вы бы так смогли КАЖДЫЙ ДЕНЬ?</p>
<p>Ну тоесть каждый день вот вы ложитесь спать ЗНАЯ что от вашего сна зависит всё при всё при всё и даже больше. И вот в процессе вашего сна происходит вот это всё &#8211; напоминания, запоминания, помогания, звонки, разговоры посторонние под ухом и всё такое. И так каждую ночь. Как вам такая жизнь?</p>
<p>Хотите?</p>
<p>Призодите работать программистом в нашу контору. Получите в полной мере!</p>
<p>Хотя не всё так трагично. Конечно есть люди которые способны кимарить просто постоянно. Водители такие бывают что чуть-ли не на каждом сфетофоре способны чуток вздремнуть. Ну вы знаете &#8211; им чуть бибикнуть приходится чтобы вернуть к жизни. Наверняка вы знакомы с такой ситуацией.</p>
<p>Ну так вот и программисты тоже такие бывают. Они всегда находятся в состоянии близком ко сну. Чуть не мешает никто &#8211; сразу &#8220;брык&#8221; и в сон. Не глубоко, только на чуть чуть. Особо серьёзных никаких химер не успеешь понагрезить, но чуть-чуть немножко слабо-туманных вполне успеешь. Вот в такой сон.</p>
<p>Именно так и производится большая часть программного продукта. Она производится людьми которые либо вообще не понимают что они делают, либо теми кто в силу каких-то причин просто не может погрузиться в сон достаточно глубоко. Соответственные и результаты.</p>
<p>Ну потому что отвлекают постоянно. Потому что БУДЯТ же бля постоянно! Потому что люди не понимают что ты же спишь и что их ебучая менеджерская &#8220;организационная&#8221; активность она на самом деле только мешает работать. Большинство людей НЕ программистов этого не понимают.</p>
<p>Я надеюсь что осознав аналогию работы программиста со сном может быть люди лучше поймут как надо обходиться с программистами и откуда вообще берутся хорошие программы. Поймут наконец что вот этот ебучий ЖЖ &#8211; это то что пишу и читаю ПЕРЕД СНОМ. Вот также как вы. Вы не можете спать пока неначитаетесь или пока телевизор не насмотритесь. Не можете ведь?</p>
<p>Вот и я не могу я работать пока неначитаюсь, ненахожусь в туалет, неначищусь зубы, ненапишусь в жевом журнальчеге, ненавотэтовсёнаделаюсь. И если мне не дать закончить это до конца, до состояния наступления глубого сна, если вмешаться в этот ритуал, то его придётся потом начинать практически заново. Точно также как вам придётся снова считать баранов если вас разбудить когда вы только что заснули.</p>
<p>Хотите хороших программ?</p>
<p>Хотите чтобы ваш муж-программист был успешен и заработал все деньги?</p>
<p>Хотите чтобы ваши подчинённые программисты наконец-то сделали всё как надо?</p>
<p>Тогда вот вам простой рецепт:</p>
<p>НЕ БУДИТЕ СЛИШКОМ ЧАСТО ПРОГРАММИСТА!</p>
]]></content:encoded>
			<wfw:commentRss>http://john.5070.info/2009/07/%d0%bf%d1%80%d0%be%d0%b3%d1%80%d0%b0%d0%bc%d0%bc%d0%b8%d1%81%d1%82-%d1%81%d0%bf%d0%b8%d1%82/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Организация бэкапов с помощью LVM</title>
		<link>http://john.5070.info/2009/06/%d0%be%d1%80%d0%b3%d0%b0%d0%bd%d0%b8%d0%b7%d0%b0%d1%86%d0%b8%d1%8f-%d0%b1%d1%8d%d0%ba%d0%b0%d0%bf%d0%be%d0%b2-%d1%81-%d0%bf%d0%be%d0%bc%d0%be%d1%89%d1%8c%d1%8e-lvm/</link>
		<comments>http://john.5070.info/2009/06/%d0%be%d1%80%d0%b3%d0%b0%d0%bd%d0%b8%d0%b7%d0%b0%d1%86%d0%b8%d1%8f-%d0%b1%d1%8d%d0%ba%d0%b0%d0%bf%d0%be%d0%b2-%d1%81-%d0%bf%d0%be%d0%bc%d0%be%d1%89%d1%8c%d1%8e-lvm/#comments</comments>
		<pubDate>Fri, 19 Jun 2009 05:58:14 +0000</pubDate>
		<dc:creator>John Lepikhin</dc:creator>
				<category><![CDATA[программирование]]></category>
		<category><![CDATA[backup]]></category>
		<category><![CDATA[LVM]]></category>
		<category><![CDATA[lvm2]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[ZFS]]></category>

		<guid isPermaLink="false">http://john.5070.info/?p=132</guid>
		<description><![CDATA[Вдруг осознал, что я тут двигаю всякие классные технологии, а сам пребываю в каменном веке. Перенёс /home в LVM. Сразу захотелось использовать моментальные инкрементальные бэкапы LVM. Как это сделать в сети написано (точнее, раскопировано и переведено) уже не один десяток раз. Но я пока не встретил ни одной статьи, где простые примеры создания снимка эволюционировали [...]]]></description>
			<content:encoded><![CDATA[<p>Вдруг осознал, что я тут двигаю всякие классные технологии, а сам пребываю в каменном веке. Перенёс /home в LVM. Сразу захотелось использовать моментальные инкрементальные бэкапы LVM. Как это сделать в сети написано (точнее, раскопировано и переведено) уже не один десяток раз. Но я пока не встретил ни одной статьи, где простые примеры создания снимка эволюционировали до полноценного скрипта. Восполню этот пробел quick programming&#8217;ом.</p>
<p><span id="more-132"></span>Но сначала немного технических деталей. В снапшотах ZFS есть неоспоримые преимущества перед снапшотами LVM:</p>
<ol>
<li>В LVM надо заранее выделять место под снапшот (по сути, создавать ещё один logical volume). Если размер изменений в основном разделе превысили это место, снапшот становится неактивным. Его нельзя ни подмонтировать, ни растянуть. Только удалить. Но место под снапшоты можно налету увеличивать, это сомнительный, но плюс.</li>
<li>В LVM в каждом снапшоте хранится разница с основным разделом, а не с предыдущим разделом. В итоге, если мы сделали снапшот backup1, затем залили в FS файлик 30MB, затем сделали снапшот backup2, затем залили ещё один файлик на 30MB, то в backup1 будет занято 60MB, а в backup2 30MB. Логично было бы делать снапшот от снапшота, тогда разница накапливалась по-человечьи. Но LVM такое извращение не поддерживается.</li>
</ol>
<p>Но есть и преимущества:</p>
<ol>
<li>Снапшот является RW. Честно говоря, так и не придумал, зачем оно может понадобиться.</li>
<li>LVM живёт в kernel space, в отличие от порта ZFS на Linux zfs-fuse.</li>
<li>ZFS предоставляет и не нужный мне слой навороченной FS.</li>
</ol>
<p>Итак, надо периодически делать снапшот раздела, хранить определённое количество часовых и суточных копий. Для этого написал shell-скриптик lvm-home-snapshot. Вот он:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">#!/bin/sh</span>
&nbsp;
<span style="color: #007800;">name</span>=$<span style="color: #000000;">1</span>
<span style="color: #007800;"><span style="color: #c20cb9; font-weight: bold;">size</span></span>=$<span style="color: #000000;">2</span>
<span style="color: #007800;">vgname</span>=$<span style="color: #000000;">3</span>
<span style="color: #007800;">lvname</span>=$<span style="color: #000000;">4</span>
<span style="color: #007800;">copies</span>=$<span style="color: #000000;">5</span>
&nbsp;
<span style="color: #007800;"><span style="color: #000000; font-weight: bold;">time</span></span>=<span style="color: #000000; font-weight: bold;">`</span><span style="color: #c20cb9; font-weight: bold;">date</span> +<span style="color: #ff0000;">'%Y-%m-%d--%H-%M-%S'</span><span style="color: #000000; font-weight: bold;">`</span>
<span style="color: #007800;">sname</span>=<span style="color: #ff0000;">&quot;backup-<span style="color: #007800;">$time</span>-<span style="color: #007800;">$name</span>&quot;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">/</span>sbin<span style="color: #000000; font-weight: bold;">/</span>lvcreate <span style="color: #660033;">-p</span> r -L<span style="color: #007800;">$size</span> <span style="color: #660033;">-s</span> <span style="color: #660033;">-n</span> <span style="color: #007800;">$sname</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span><span style="color: #007800;">$vgname</span><span style="color: #000000; font-weight: bold;">/</span><span style="color: #007800;">$lvname</span>
&nbsp;
<span style="color: #007800;">lst</span>=<span style="color: #000000; font-weight: bold;">`/</span>sbin<span style="color: #000000; font-weight: bold;">/</span>lvdisplay <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">egrep</span> <span style="color: #ff0000;">'^ +LV Name'</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">egrep</span> <span style="color: #ff0000;">&quot;/dev/<span style="color: #007800;">$vgname</span>/backup-.*-<span style="color: #007800;">$name</span>&quot;</span><span style="color: #000000; font-weight: bold;">|</span><span style="color: #c20cb9; font-weight: bold;">awk</span> <span style="color: #ff0000;">'{print $3}'</span><span style="color: #000000; font-weight: bold;">`</span>
<span style="color: #007800;">snapshots_cnt</span>=<span style="color: #000000; font-weight: bold;">`</span><span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #007800;">$lst</span><span style="color: #000000; font-weight: bold;">|</span><span style="color: #c20cb9; font-weight: bold;">wc</span> -w<span style="color: #000000; font-weight: bold;">`</span>
<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #007800;">$snapshots_cnt</span> <span style="color: #660033;">-gt</span> <span style="color: #007800;">$copies</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span>
	<span style="color: #007800;">to_delete</span>=<span style="color: #000000; font-weight: bold;">`</span><span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000; font-weight: bold;">for</span> i <span style="color: #000000; font-weight: bold;">in</span> <span style="color: #007800;">$lst</span>; <span style="color: #000000; font-weight: bold;">do</span> <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #007800;">$i</span>; <span style="color: #000000; font-weight: bold;">done</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #000000; font-weight: bold;">|</span> <span style="color: #c20cb9; font-weight: bold;">head</span> $<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">$copies</span>-<span style="color: #007800;">$snapshots_cnt</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #000000; font-weight: bold;">`</span>
	<span style="color: #000000; font-weight: bold;">for</span> i <span style="color: #000000; font-weight: bold;">in</span> <span style="color: #007800;">$to_delete</span>; <span style="color: #000000; font-weight: bold;">do</span> <span style="color: #000000; font-weight: bold;">/</span>sbin<span style="color: #000000; font-weight: bold;">/</span>lvremove <span style="color: #660033;">-f</span> <span style="color: #007800;">$i</span>; <span style="color: #000000; font-weight: bold;">done</span>
<span style="color: #000000; font-weight: bold;">fi</span></pre></div></div>

<p>Как хорошо видно, принимает 5 параметров: имя снапшота, размер, имя группы разделов, имя раздела, количество хранимых копий. Пример использования:</p>
<p>lvm-home-snapshot hourly 768M home john 3</p>
<p>Создаст снапшот &#8220;/dev/home/backup-2009-06-19&#8211;14-45-01-hourly&#8221; раздела /dev/home/john размером 768MB. Если накопилось более трёх снапшотов с именем hourly — наиболее старые будут удалены. Итого, в крон написал:</p>
<p>0 14        * * *    /root/bin/lvm-home-snapshot day 2G home john 4<br />
0 0-4,15-23    * * *    /root/bin/lvm-home-snapshot hour 256M home john 8<br />
15,30,45 *    * * *    /root/bin/lvm-home-snapshot hourquot 128M home john 3</p>
<p>Итак снапшоты создаются, всё чудно. Но надо как-то минимизировать вероятность перезаполнения снапшотов. Для этого был написан ещё один скрипт, который заодно удаляет INACTIVE (переполнившиеся) снапшоты:</p>

<div class="wp_syntax"><div class="code"><pre class="perl" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">#!/usr/bin/perl</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">use</span> warnings<span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">use</span> strict<span style="color: #339933;">;</span>
&nbsp;
<span style="color: #b1b100;">my</span> <span style="color: #009900;">&#40;</span><span style="color: #0000ff;">$name</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$vgname</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$maxpct</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$addpct</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">@ARGV</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000066;">open</span> <span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$proc</span><span style="color: #339933;">,</span> <span style="color: #ff0000;">&quot;/sbin/lvdisplay|&quot;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #b1b100;">my</span> <span style="color: #009900;">&#40;</span><span style="color: #0000ff;">$d</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$s</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">$u</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">&lt;</span><span style="color: #0000ff;">$proc</span><span style="color: #339933;">&gt;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #000066;">chomp</span><span style="color: #339933;">;</span>
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #009966; font-style: italic;">/^ +LV Name +(.*)/</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #0000ff;">$d</span><span style="color: #339933;">=</span><span style="color: #0000ff;">$1</span> <span style="color: #009900;">&#125;</span>
	<span style="color: #b1b100;">elsif</span> <span style="color: #009900;">&#40;</span><span style="color: #009966; font-style: italic;">/^ +COW-table size +(\d+)\S* +(.*)/</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #0000ff;">$s</span><span style="color: #339933;">=</span><span style="color: #000066;">int</span> <span style="color: #0000ff;">$1</span><span style="color: #339933;">;</span> <span style="color: #0000ff;">$u</span><span style="color: #339933;">=</span><span style="color: #0000ff;">$2</span> <span style="color: #009900;">&#125;</span>
	<span style="color: #b1b100;">elsif</span> <span style="color: #009900;">&#40;</span><span style="color: #009966; font-style: italic;">/^ +Allocated to snapshot +(\d+)/</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$pct</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">$1</span><span style="color: #339933;">;</span>
		<span style="color: #b1b100;">next</span> <span style="color: #b1b100;">if</span> <span style="color: #0000ff;">$d</span> <span style="color: #339933;">!~</span> <span style="color: #000066;">m</span><span style="color: #339933;">|^</span><span style="color: #009966; font-style: italic;">/dev/</span><span style="color: #0000ff;">$vgname</span><span style="color: #339933;">/</span>backup<span style="color: #339933;">-.*-</span><span style="color: #0000ff;">$name</span><span style="color: #0000ff;">$|</span> <span style="color: #339933;">||</span> <span style="color: #0000ff;">$pct</span><span style="color: #339933;">&lt;</span><span style="color: #0000ff;">$maxpct</span><span style="color: #339933;">;</span>
&nbsp;
		<span style="color: #b1b100;">my</span> <span style="color: #0000ff;">$newsize</span> <span style="color: #339933;">=</span> <span style="color: #000066;">int</span> <span style="color: #0000ff;">$s</span><span style="color: #339933;">*</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">$addpct</span><span style="color: #339933;">/</span><span style="color: #cc66cc;">100</span><span style="color: #339933;">+</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #ff0000;">`/sbin/lvextend -L$newsize$u $d`</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
	<span style="color: #b1b100;">elsif</span> <span style="color: #009900;">&#40;</span><span style="color: #000066;">m</span><span style="color: #339933;">|^</span> <span style="color: #339933;">+</span><span style="color: #009900;">&#40;</span><span style="color: #009966; font-style: italic;">/dev/</span><span style="color: #0000ff;">$vgname</span><span style="color: #339933;">/</span>backup<span style="color: #339933;">-.*-</span><span style="color: #0000ff;">$name</span><span style="color: #009900;">&#41;</span> \<span style="color: #009900;">&#91;</span>INACTIVE\<span style="color: #009900;">&#93;</span><span style="color: #339933;">|</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #ff0000;">`/sbin/lvremove -f $1`</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #000066;">close</span> <span style="color: #0000ff;">$proc</span></pre></div></div>

<p>Принимает параметры: имя снапшота, имя группы разделов, максимальный процент занятости (при превышении снапшот увеличивается), на сколько процентов от текущего увеличить. Пример использования:</p>
<p>lvm-home-snapshot-extend hourly home 15 30</p>
<p>Все снапшоты с именем hourly в группе разделов home, занятые более чем на 15%, будут увеличены на 30%. В крон добавил строчки:</p>
<p>* *        * * *    /root/bin/lvm-home-snapshot-extend hourquot home 15 30<br />
* *        * * *    /root/bin/lvm-home-snapshot-extend hour home 25 30<br />
* *        * * *    /root/bin/lvm-home-snapshot-extend day home 35 20</p>
<p>Не слишком эффективно, но меня устраивает. Да и лень как-то дальше развивать.</p>
]]></content:encoded>
			<wfw:commentRss>http://john.5070.info/2009/06/%d0%be%d1%80%d0%b3%d0%b0%d0%bd%d0%b8%d0%b7%d0%b0%d1%86%d0%b8%d1%8f-%d0%b1%d1%8d%d0%ba%d0%b0%d0%bf%d0%be%d0%b2-%d1%81-%d0%bf%d0%be%d0%bc%d0%be%d1%89%d1%8c%d1%8e-lvm/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Решение для решателя Sudoku</title>
		<link>http://john.5070.info/2009/06/%d1%80%d0%b5%d1%88%d0%b5%d0%bd%d0%b8%d0%b5-%d0%b4%d0%bb%d1%8f-%d1%80%d0%b5%d1%88%d0%b0%d1%82%d0%b5%d0%bb%d1%8f-sudoku/</link>
		<comments>http://john.5070.info/2009/06/%d1%80%d0%b5%d1%88%d0%b5%d0%bd%d0%b8%d0%b5-%d0%b4%d0%bb%d1%8f-%d1%80%d0%b5%d1%88%d0%b0%d1%82%d0%b5%d0%bb%d1%8f-sudoku/#comments</comments>
		<pubDate>Wed, 10 Jun 2009 14:54:30 +0000</pubDate>
		<dc:creator>John Lepikhin</dc:creator>
				<category><![CDATA[Blogroll]]></category>
		<category><![CDATA[Ocaml]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[программирование]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Sudoku]]></category>

		<guid isPermaLink="false">http://john.5070.info/?p=126</guid>
		<description><![CDATA[Хотел вечерком размять мозг — набросать какой-нибудь особенно красивый решатель Sudoku на Ocaml. Но возникла мысль изучить вражеские аналоги. Итак, решатель Sudoku размером 800 с небольшим байт:

include Set.Make&#40;struct type t = &#40;int * int&#41; * int let compare = compare end&#41;
&#160;
let &#40;@&#41; g f x = g &#40;f x&#41; and id x = x and [...]]]></description>
			<content:encoded><![CDATA[<p>Хотел вечерком размять мозг — набросать какой-нибудь особенно красивый решатель Sudoku на Ocaml. Но возникла мысль изучить вражеские аналоги. Итак, решатель Sudoku размером 800 с небольшим байт:</p>

<div class="wp_syntax"><div class="code"><pre class="ocaml" style="font-family:monospace;"><span style="color: #06c; font-weight: bold;">include</span> <span style="color: #06c; font-weight: bold;">Set</span><span style="color: #a52a2a;">.</span><span style="color: #060;">Make</span><span style="color: #6c6;">&#40;</span><span style="color: #06c; font-weight: bold;">struct</span> <span style="color: #06c; font-weight: bold;">type</span> t <span style="color: #a52a2a;">=</span> <span style="color: #6c6;">&#40;</span>int <span style="color: #a52a2a;">*</span> int<span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">*</span> int <span style="color: #06c; font-weight: bold;">let</span> <span style="color: #06c; font-weight: bold;">compare</span> <span style="color: #a52a2a;">=</span> <span style="color: #06c; font-weight: bold;">compare</span> <span style="color: #06c; font-weight: bold;">end</span><span style="color: #6c6;">&#41;</span>
&nbsp;
<span style="color: #06c; font-weight: bold;">let</span> <span style="color: #6c6;">&#40;</span>@<span style="color: #6c6;">&#41;</span> g f x <span style="color: #a52a2a;">=</span> g <span style="color: #6c6;">&#40;</span>f x<span style="color: #6c6;">&#41;</span> <span style="color: #06c; font-weight: bold;">and</span> id x <span style="color: #a52a2a;">=</span> x <span style="color: #06c; font-weight: bold;">and</span> sw f x y <span style="color: #a52a2a;">=</span> f y x <span style="color: #06c; font-weight: bold;">and</span> zip x y <span style="color: #a52a2a;">=</span> <span style="color: #6c6;">&#40;</span>x, y<span style="color: #6c6;">&#41;</span>
&nbsp;
<span style="color: #06c; font-weight: bold;">let</span> fold9 f <span style="color: #a52a2a;">=</span> <span style="color: #06c; font-weight: bold;">let</span> <span style="color: #06c; font-weight: bold;">rec</span> loop i <span style="color: #a52a2a;">=</span> <span style="color: #06c; font-weight: bold;">if</span> i<span style="color: #a52a2a;">&gt;</span><span style="color: #c6c;">8</span> <span style="color: #06c; font-weight: bold;">then</span> id <span style="color: #06c; font-weight: bold;">else</span> loop <span style="color: #6c6;">&#40;</span>i<span style="color: #a52a2a;">+</span><span style="color: #c6c;">1</span><span style="color: #6c6;">&#41;</span> @ f i <span style="color: #06c; font-weight: bold;">in</span> loop <span style="color: #c6c;">0</span>
&nbsp;
<span style="color: #06c; font-weight: bold;">let</span> fold81 f <span style="color: #a52a2a;">=</span> fold9 <span style="color: #6c6;">&#40;</span>fold9 @ <span style="color: #6c6;">&#40;</span>@<span style="color: #6c6;">&#41;</span> f @ zip<span style="color: #6c6;">&#41;</span>
&nbsp;
<span style="color: #06c; font-weight: bold;">let</span> mark <span style="color: #6c6;">&#40;</span><span style="color: #6c6;">&#40;</span>i,j<span style="color: #6c6;">&#41;</span>,x <span style="color: #06c; font-weight: bold;">as</span> e<span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">:</span> t <span style="color: #a52a2a;">-&gt;</span> t <span style="color: #a52a2a;">=</span>
  add e @ fold9 <span style="color: #6c6;">&#40;</span><span style="color: #06c; font-weight: bold;">fun</span> k <span style="color: #a52a2a;">-&gt;</span> remove <span style="color: #6c6;">&#40;</span><span style="color: #6c6;">&#40;</span>i<span style="color: #a52a2a;">/</span><span style="color: #c6c;">3</span><span style="color: #a52a2a;">*</span><span style="color: #c6c;">3</span> <span style="color: #a52a2a;">+</span> k<span style="color: #a52a2a;">/</span><span style="color: #c6c;">3</span>, j<span style="color: #a52a2a;">/</span><span style="color: #c6c;">3</span><span style="color: #a52a2a;">*</span><span style="color: #c6c;">3</span> <span style="color: #a52a2a;">+</span> k <span style="color: #06c; font-weight: bold;">mod</span> <span style="color: #c6c;">3</span><span style="color: #6c6;">&#41;</span>, x<span style="color: #6c6;">&#41;</span> @
    remove <span style="color: #6c6;">&#40;</span><span style="color: #6c6;">&#40;</span>i,j<span style="color: #6c6;">&#41;</span>,k<span style="color: #6c6;">&#41;</span> @ remove <span style="color: #6c6;">&#40;</span><span style="color: #6c6;">&#40;</span>i,k<span style="color: #6c6;">&#41;</span>,x<span style="color: #6c6;">&#41;</span> @ remove <span style="color: #6c6;">&#40;</span><span style="color: #6c6;">&#40;</span>k,j<span style="color: #6c6;">&#41;</span>,x<span style="color: #6c6;">&#41;</span><span style="color: #6c6;">&#41;</span>
&nbsp;
<span style="color: #06c; font-weight: bold;">let</span> search <span style="color: #a52a2a;">=</span>
  <span style="color: #06c; font-weight: bold;">let</span> g p f s <span style="color: #a52a2a;">=</span> fold <span style="color: #6c6;">&#40;</span>f @ sw mark s<span style="color: #6c6;">&#41;</span> <span style="color: #6c6;">&#40;</span>filter <span style="color: #6c6;">&#40;</span><span style="color: #6c6;">&#40;</span><span style="color: #a52a2a;">=</span><span style="color: #6c6;">&#41;</span> p @ <span style="color: #06c; font-weight: bold;">fst</span><span style="color: #6c6;">&#41;</span> s<span style="color: #6c6;">&#41;</span> <span style="color: #06c; font-weight: bold;">in</span>
  fold81 g
&nbsp;
<span style="color: #06c; font-weight: bold;">let</span> read <span style="color: #6c6;">&#40;</span><span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">=</span>
  <span style="color: #06c; font-weight: bold;">let</span> f p <span style="color: #a52a2a;">=</span> <span style="color: #06c; font-weight: bold;">Scanf</span><span style="color: #a52a2a;">.</span><span style="color: #060;">scanf</span> <span style="color: #3cb371;">&quot;%d &quot;</span> <span style="color: #6c6;">&#40;</span><span style="color: #06c; font-weight: bold;">fun</span> x <span style="color: #a52a2a;">-&gt;</span> <span style="color: #06c; font-weight: bold;">if</span> x<span style="color: #a52a2a;">&gt;</span><span style="color: #c6c;">0</span> <span style="color: #06c; font-weight: bold;">then</span> mark <span style="color: #6c6;">&#40;</span>p,x<span style="color: #a52a2a;">-</span><span style="color: #c6c;">1</span><span style="color: #6c6;">&#41;</span> <span style="color: #06c; font-weight: bold;">else</span> id<span style="color: #6c6;">&#41;</span> <span style="color: #06c; font-weight: bold;">in</span>
  fold81 f <span style="color: #6c6;">&#40;</span>fold81 <span style="color: #6c6;">&#40;</span>fold9 @ <span style="color: #6c6;">&#40;</span><span style="color: #6c6;">&#40;</span>@<span style="color: #6c6;">&#41;</span> add @ zip<span style="color: #6c6;">&#41;</span><span style="color: #6c6;">&#41;</span> empty<span style="color: #6c6;">&#41;</span>
&nbsp;
<span style="color: #06c; font-weight: bold;">let</span> print s <span style="color: #6c6;">&#40;</span><span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">=</span>
  <span style="color: #06c; font-weight: bold;">let</span> pr <span style="color: #6c6;">&#40;</span><span style="color: #6c6;">&#40;</span>i,j<span style="color: #6c6;">&#41;</span>,x<span style="color: #6c6;">&#41;</span> <span style="color: #a52a2a;">=</span> <span style="color: #06c; font-weight: bold;">Printf</span><span style="color: #a52a2a;">.</span><span style="color: #060;">printf</span> <span style="color: #3cb371;">&quot;%d%c&quot;</span> <span style="color: #6c6;">&#40;</span>x<span style="color: #a52a2a;">+</span><span style="color: #c6c;">1</span><span style="color: #6c6;">&#41;</span> <span style="color: #6c6;">&#40;</span><span style="color: #06c; font-weight: bold;">if</span> j<span style="color: #a52a2a;">=</span><span style="color: #c6c;">8</span> <span style="color: #06c; font-weight: bold;">then</span> <span style="color: #a52a2a;">'</span>\n<span style="color: #a52a2a;">'</span> <span style="color: #06c; font-weight: bold;">else</span> <span style="color: #a52a2a;">'</span> <span style="color: #a52a2a;">'</span><span style="color: #6c6;">&#41;</span> <span style="color: #06c; font-weight: bold;">in</span>
  iter pr s<span style="color: #a52a2a;">;</span> <span style="color: #06c; font-weight: bold;">print_newline</span> <span style="color: #6c6;">&#40;</span><span style="color: #6c6;">&#41;</span><span style="color: #a52a2a;">;;</span>
&nbsp;
search print <span style="color: #6c6;">&#40;</span>read <span style="color: #6c6;">&#40;</span><span style="color: #6c6;">&#41;</span><span style="color: #6c6;">&#41;</span> <span style="color: #6c6;">&#40;</span><span style="color: #6c6;">&#41;</span></pre></div></div>

<p>Вы посмотрите эту красоту, это же [почти] совершенство! А если учесть, что 272 байта — это чтение задачи с STDIN и вывод результата, размер кода сокращается до менее чем 600 байт.</p>
<p><span id="more-126"></span>Впрочем, Perl традиционно отличился своей минималистической магической мешаниной:</p>

<div class="wp_syntax"><div class="code"><pre class="perl" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">use</span> integer<span style="color: #339933;">;</span><span style="color: #0000ff;">@A</span><span style="color: #339933;">=</span><span style="color: #000066;">split</span><span style="color: #339933;">//,&lt;&gt;;</span>sub R<span style="color: #009900;">&#123;</span><span style="color: #b1b100;">for</span><span style="color: #0000ff;">$i</span><span style="color: #009900;">&#40;</span>0<span style="color: #339933;">..</span>80<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><span style="color: #b1b100;">next</span> <span style="color: #b1b100;">if</span><span style="color: #0000ff;">$A</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$i</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>my<span style="color: #0000ff;">%t</span><span style="color: #339933;">=</span><span style="color: #000066;">map</span><span style="color: #009900;">&#123;</span><span style="color: #0000ff;">$_</span><span style="color: #339933;">/</span><span style="color: #cc66cc;">9</span>
<span style="color: #339933;">==</span><span style="color: #0000ff;">$i</span><span style="color: #339933;">/</span><span style="color: #cc66cc;">9</span><span style="color: #339933;">||</span><span style="color: #0000ff;">$_</span><span style="color: #339933;">%</span>9<span style="color: #339933;">==</span><span style="color: #0000ff;">$i</span><span style="color: #339933;">%</span>9<span style="color: #339933;">||</span><span style="color: #0000ff;">$_</span><span style="color: #339933;">/</span><span style="color: #cc66cc;">27</span><span style="color: #339933;">==</span><span style="color: #0000ff;">$i</span><span style="color: #339933;">/</span><span style="color: #cc66cc;">27</span><span style="color: #339933;">&amp;&amp;</span><span style="color: #0000ff;">$_</span><span style="color: #339933;">%</span>9<span style="color: #339933;">/</span><span style="color: #cc66cc;">3</span><span style="color: #339933;">==</span><span style="color: #0000ff;">$i</span><span style="color: #339933;">%</span>9<span style="color: #339933;">/</span><span style="color: #cc66cc;">3</span><span style="color: #339933;">?</span><span style="color: #0000ff;">$A</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$_</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">:</span><span style="color: #cc66cc;">0</span><span style="color: #339933;">=&gt;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#125;</span>0<span style="color: #339933;">..</span>80<span style="color: #339933;">;</span>R<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">$A</span><span style="color: #009900;">&#91;</span>
<span style="color: #0000ff;">$i</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #0000ff;">$_</span><span style="color: #009900;">&#41;</span><span style="color: #b1b100;">for</span> <span style="color: #000066;">grep</span><span style="color: #009900;">&#123;</span><span style="color: #339933;">!</span><span style="color: #0000ff;">$t</span><span style="color: #009900;">&#123;</span><span style="color: #0000ff;">$_</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#125;</span>1<span style="color: #339933;">..</span>9<span style="color: #339933;">;</span>return<span style="color: #0000ff;">$A</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">$i</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">=</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#125;</span><span style="color: #000066;">die</span><span style="color: #0000ff;">@A</span><span style="color: #009900;">&#125;</span>R</pre></div></div>

<p>Ну и специалисты по PHP тоже выразились: <a href="http://www.weberdev.com/get_example-4243.html">http://www.weberdev.com/get_example-4243.html</a></p>
]]></content:encoded>
			<wfw:commentRss>http://john.5070.info/2009/06/%d1%80%d0%b5%d1%88%d0%b5%d0%bd%d0%b8%d0%b5-%d0%b4%d0%bb%d1%8f-%d1%80%d0%b5%d1%88%d0%b0%d1%82%d0%b5%d0%bb%d1%8f-sudoku/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Микроязык OpQL</title>
		<link>http://john.5070.info/2009/06/%d0%bc%d0%b8%d0%ba%d1%80%d0%be%d1%8f%d0%b7%d1%8b%d0%ba-opql/</link>
		<comments>http://john.5070.info/2009/06/%d0%bc%d0%b8%d0%ba%d1%80%d0%be%d1%8f%d0%b7%d1%8b%d0%ba-opql/#comments</comments>
		<pubDate>Wed, 03 Jun 2009 13:36:58 +0000</pubDate>
		<dc:creator>John Lepikhin</dc:creator>
				<category><![CDATA[Ocaml]]></category>
		<category><![CDATA[программирование]]></category>
		<category><![CDATA[OpQL]]></category>
		<category><![CDATA[oProxy]]></category>
		<category><![CDATA[хостинг]]></category>

		<guid isPermaLink="false">http://john.5070.info/?p=115</guid>
		<description><![CDATA[Сделал микроязык запросов для oProxy. Служит, собственно, для управления ею. Что умеет:

Показать всякую текущую статистику (устаревшее show_workers, show_nodes и т.д.)
Управлять списками наблюдения.

Второй пункт интереснее. Немного предыстории. Часто бывает, что у клиентов на shared-хостинге случился перерасход ресурсов и они хотят знать, откуда эта нагрузка растёт. Резонное желание. Но беда в том, что ни я, &#8220;заведующий всем&#8221; [...]]]></description>
			<content:encoded><![CDATA[<p>Сделал микроязык запросов для oProxy. Служит, собственно, для управления ею. Что умеет:</p>
<ol>
<li>Показать всякую текущую статистику (устаревшее show_workers, show_nodes и т.д.)</li>
<li>Управлять списками наблюдения.</li>
</ol>
<p><span id="more-115"></span>Второй пункт интереснее. Немного предыстории. Часто бывает, что у клиентов на shared-хостинге случился перерасход ресурсов и они хотят знать, откуда эта нагрузка растёт. Резонное желание. Но беда в том, что ни я, &#8220;заведующий всем&#8221; © на хостинге, ни тем более техподдержка не может точно ответить на такой вопрос. Просто неоткуда брать данные. Чтобы разрешить эту проблему и были созданы списки наблюдения. Допустим, по MySQL-пользователю evlampiy случилось превышение нагрузки на MySQL. Пишем:</p>
<blockquote><p>start save time, sent, query from mysql where user = &#8220;evlampiy&#8221; into file &#8220;/home/evlampiy/mysql_load.txt&#8221;</p></blockquote>
<p>Всё, с этого момента прокся начнёт сохранять в указанный файлик все запросы к MySQL, пришедшие от пользователя evlampiy. Будет записано время выполнения запроса, количество посланных клиенту байт и сам запрос. Как только выяснили происхождение нагрузок, пишем:</p>
<blockquote><p>stop save time, sent, query from mysql where user = &#8220;evlampiy&#8221; into file &#8220;/home/evlampiy/mysql_load.txt&#8221;</p></blockquote>
<p>Запись прекратилась. Можно и понавороченней:</p>
<blockquote><p>start save current_time, time/60, sent/1024/1024, host, uri from http where host = &#8220;john.5070.info&#8221; and ((uri = &#8220;/&#8221; and time &lt; 0.5) or (uri = &#8220;/news/&#8221; and time &gt; 0.01)) into file &#8220;/tmp/crazy_requests.txt&#8221;; stop save host from http into file &#8220;/tmp/all_http.txt&#8221;</p></blockquote>
<p>Разумеется, можно посмотреть текущий список наблюдения:</p>
<blockquote><p>show queries</p></blockquote>
<p>На моей машине оверхед на один запрос со списком наблюдения длиной 5 получился 70 микросекунд, что примерно соответствует 2.3% на одно наблюдение при отдаче напрямую и 1.7% при проксировании.</p>
]]></content:encoded>
			<wfw:commentRss>http://john.5070.info/2009/06/%d0%bc%d0%b8%d0%ba%d1%80%d0%be%d1%8f%d0%b7%d1%8b%d0%ba-opql/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ocaml-epoll</title>
		<link>http://john.5070.info/2009/05/ocaml-epoll/</link>
		<comments>http://john.5070.info/2009/05/ocaml-epoll/#comments</comments>
		<pubDate>Fri, 29 May 2009 06:49:27 +0000</pubDate>
		<dc:creator>John Lepikhin</dc:creator>
				<category><![CDATA[Ocaml]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[программирование]]></category>
		<category><![CDATA[epoll]]></category>

		<guid isPermaLink="false">http://john.5070.info/?p=112</guid>
		<description><![CDATA[Написал биндинг для работы с epoll(7). Пока бета, но на ней уже ради эксперимента написал успешно работающий маленький веб-сервер :) Скачать можно со страницы Software. epoll является аналогом select() и poll(), но с увеличением количества обрабатываемых сокетов сложность остаётся O(1), что позволяет без особых задержек обрабатывать тысячи параллельных соединений.
]]></description>
			<content:encoded><![CDATA[<p>Написал биндинг для работы с epoll(7). Пока бета, но на ней уже ради эксперимента написал успешно работающий маленький веб-сервер :) Скачать можно со страницы <a title="Мой софт" href="http://john.5070.info/software/">Software</a>. epoll является аналогом select() и poll(), но с увеличением количества обрабатываемых сокетов сложность остаётся O(1), что позволяет без особых задержек обрабатывать тысячи параллельных соединений.</p>
]]></content:encoded>
			<wfw:commentRss>http://john.5070.info/2009/05/ocaml-epoll/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>oProxy release</title>
		<link>http://john.5070.info/2009/05/oproxy-release/</link>
		<comments>http://john.5070.info/2009/05/oproxy-release/#comments</comments>
		<pubDate>Wed, 20 May 2009 13:31:28 +0000</pubDate>
		<dc:creator>John Lepikhin</dc:creator>
				<category><![CDATA[oProxy]]></category>
		<category><![CDATA[программирование]]></category>
		<category><![CDATA[cluster]]></category>
		<category><![CDATA[LWT]]></category>
		<category><![CDATA[Ocaml]]></category>
		<category><![CDATA[хостинг]]></category>

		<guid isPermaLink="false">http://john.5070.info/?p=106</guid>
		<description><![CDATA[Не прошло и полгода, как я решил разродиться на релиз прокси. Назовём его &#8220;1.1&#8243;.
Самой большой моей ошибкой в проектировании была идея использовать POSIX треды. Всё замечательно, но только до тех пор, пока активных соединений не становится больше сотни. Дело в том, что такие треды, по сути, являются почти что отдельными процессами: у них свой стек, [...]]]></description>
			<content:encoded><![CDATA[<p>Не прошло и полгода, как я решил разродиться на релиз прокси. Назовём его &#8220;1.1&#8243;.</p>
<p><span id="more-106"></span>Самой большой моей ошибкой в проектировании была идея использовать POSIX треды. Всё замечательно, но только до тех пор, пока активных соединений не становится больше сотни. Дело в том, что такие треды, по сути, являются почти что отдельными процессами: у них свой стек, их обрабатывает шедулер ядра и т.д. Единственное отличие — у них в пределах одного процесса единое адресное пространство. Так вот, всё это вызывало такие проблемы, как переполнение стека, нелинейность масштабирования и пр. В качестве альтернатиы рассматривалось два варианта:</p>
<ol>
<li>Библиотека Equeue. Знаменита тем, что предоставляет низкий уровень к управлению очередями обработки дескрипторов. Это и минус — работать с ней не слишком комфортно: &#8220;есть только очередь и события, всё остальное на ваше усмотрение&#8221;.</li>
<li>Библиотека Lwt. По сути, то же самое, но выполнено совсем, совсем с другого бока. В интерфейсе предоставляется модель монад и псевдопотоков (отсюда название: LightWeight Threads). Быдлокодеру, навроде меня, достаточно лишь описать зависимости между состояниями: что делать, когда я получу данные из вон того сокета, и куда их записать потом.</li>
</ol>
<p>Выбор пал на Lwt. А вот тут следует сказать несколько восторженных слов о типизации Хиндли — Милнера, используемой, в том числе, в Ocaml. Как я уже сказал, потоки POSIX при разработке выглядят практически как отдельные процессы. Создал поток, и забыл о нём, а он варится сам по себе. В Lwt же надо отдельно позаботиться о последствиях каждой операции IO. Прежде всего, я заменил все вызовы Unix.socket (создание сокета) — благо в коде почти все они были в моей обёртке и реально вызов встречался только в 2-3 местах — на Lwt_unix.socket. И понеслось. Типовычислялка компилятора сразу указала мне, где я, дурень, пытаюсь подсунуть в нормальную сокетную функцию параметр с каким-то странным типом Lwt_unix.file_descr. Следующая неделя прошла за чрезвычайно интеллектуальной работой. Компилятор говорил мне, что нужно сделать чтобы впасть в нирвану, а я всячески пытался её достичь. Таким образом, буквально через несколько дней негритянской работы, передо мной предстал код, который мало того, что не содержал ни одного вызова к стандартным функциям IO, так ещё и компилился.</p>
<p>Каково же было моё удивление, когда с первым запуском оно ещё и заработало! После недели тупой работы, перехода с философии &#8220;одно соединение == один самостоятельный псевдопроцесс&#8221; на &#8220;одно соединение == один конечный автомат&#8221;, после исправления тучи кода <em>исключительно</em> по указаниям компилятора! Кривенько, но заработало, результат я увидел. Последующая неделя ушла на исправление совсем новых багов, багов ещё со старой версии и дописывания новых приятных мелочей.</p>
<p>Итого, имеем. Кластер с определённым количеством клиентов (пока меньше, чем на одной машине в среднем, но уже существенно). Прокся заведует как балансировкой нагрузки между HTTP-узлами, так и между MySQL. Т.е. гоняются вполне реальные данные настоящих сайтов. На одно <strong>соединение</strong> (не запрос) HTTP в среднем уходит чуть меньше миллисекунды CPU (это и проксирование динамики, и отдача статики с помощью системного sendfile). На соединение MySQL уходит несколько больше — около 5 миллисекунд, хотя алгоритм там наоборот в целом проще. Связываю это с</p>
<ul>
<li>sendfile() там не применишь, все проксируемые данные копируются в userspace</li>
<li> Имею богатый опыт разглядывания скриптов клиентов. А это совсем другая, удивительная, не поддающаяся научному изучению культура. У них принято сказать SELECT * на большую табличку, затем сложным алгоритмом с циклами тройной вложенности вычленить из многомегабайтного результата 2 строки, затем их отправить обратно в мускуль с целью join&#8217;а в непристойной позе с другой табличкой.</li>
</ul>
<p>Памяти жрёт в рабочем режиме при текущих нагрузках стабильно 12-15MB (один мастер, 4 рабочих).</p>
<p>Планы (или мечты?) на будущее:</p>
<ul>
<li>Пропатчить Lwt на предмет использования epoll() вместо select(). Чтобы в будущем не было мучительно больно обрабатывать 10000 одновременных соединений. Если, конечно, до этого дойдёт.</li>
<li>Написать некую глюкалу, которая сильно поможет в поиске причин высоких нагрузок как на сайтах, так и в БД. Пока мне это видится чем-то вроде: oproxyreport &#8220;select response_time-start_time, uri from http where host=&#8217;ispsystem.com&#8217; and uri begins with &#8216;/ru/&#8217; save to &#8216;/tmp/load.log&#8217;&#8221;. Если будет реализовано — сразу можно будет написать интерфейсик в ISPmanager, чтобы клиенты могли сами это делать.</li>
</ul>
<p>Я всё сказал.</p>
<p>p.s. Нет, не всё :) С переходом на Lwt, обнаружилась ещё одна приятная особенность: портабельность. Например, во FreeBSD 7.1. поломали те самые POSIX треды, из-за чего мне пришлось отказаться от альфа-тестирования прокси на ней в своё время. Lwt же ни от чего не зависит. Select() есть везде, а не блокирующие сокеты криво реализованы разве что в винде.</p>
]]></content:encoded>
			<wfw:commentRss>http://john.5070.info/2009/05/oproxy-release/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
