Ня по морде!
НЯША ж. сиб. перм. татарс. ил, грязь с тиною, жидкое, топкое дно озера; вязкая, жидкая топь. Караси в няше водятся. Конь засел в няше. || Арх. вязкая, илистая полоса морского берега, открытая только в малую воду, во время отлива; камч. лайда. Проступился в няше, увяз было. Няшистый, илистый, залитый жидкою грязью, илом. Няшеватый арх.
жидко-иловатый.
Толковый словарь Даля,
Сова → Жаворонок
Я тут за последний месяц получил аж 9 (!) писем на одну и ту же тему — читатели интересуются как мой поживает «эксперимент» перевоспитания моей внутренней «совы» в «жаворонка». Поскольку рука устала отвечать каждому в отдельности, давайте я отвечу со страниц блога.
Это не совсем эксперимент, скорее необходимость: с августа я работаю в сфере, где исторически принято начинать дела рано.
С того же августа «сова» во мне пытается помереть; несмотря на то, что я встаю каждый день максимум в 7:30 (что рано для «совы», товарищи «жаворонки»), у меня для многих плохие новости: моей «птичке» до смены ориентации далековато. Мне так же мучительно и тяжело вставать в половину восьмого, но…
Как мне говорили, когда я работал в одном из подразделений «Татнефти» — «первые десять лет тяжело, потом привыкнешь».
Все знают что такое «сеппуку» (иногда его путают с «харакири»): самурай читает нерифмованные стишки, вспарывает свой живот и созерцает свой богатый внутренний мир до самого конца. Я не пробовал, но подозреваю, что делать сеппуку больно, просто нереально, адски больно, тем не менее, самурай не бегает по двору с воплями, а красиво гадает на внутренностях. То есть он терпит, а его тренированная воля позволяет держать себя в узде.
У меня, извините уж за натуралистическое сравнение, примерно то же самое. Легче вставать не стало, более того, с утра у меня плохое настроение и мешки под глазами такие большие, что я вижу их без зеркала, но мои «десять лет» проходят, теперь я просто могу это терпеть. Это портит мою жизнь,
Производительность различных реализаций стека в ПХП

Я совсем перестал писать на технические темы в блоге. Это объяснимо: я много разрабатываю, но поделиться нечем, всё это весьма специфично для системы документооборота. Недавно, например, я думал над тем какой бы язык применить для описания фильтров в системе. Они должны срабатывать много и часто, и опосредованно управлять движением документов. Пользователь писать самостоятельно их не будет (или почти не будет), они будут составяться «конструктором», но система
Выбрал обратную польскую запись. Она компактна, просто парсится, для неё не нужно строить дерево, там нет скобок, но при этом по мощности польностью эквивалентна привычной всем со школы записи. Идея в том, что сначала на стек записываются операнды, а потом указывается операция, которая берёт их со стека и записывает обратно результат:
# традиционная запись:
(5 + 7) * 3
# обратная польская:
5 7 + 3 *
# а можно так:
3 5 7 + *Так как упор на производительность, я реализовал простенькую стековую машинку с операциями сложения, вычитания, умножения, проверки на равенство и дублирования вершины стека с использованием простых массивов, ArrayObject и SplStack, чтобы проверить как в ПХП (на котором пишется наша система) дела с производительностью стека. ArrayObject тут скорее для полноты картины, так как у него нет метода pop, который доставал бы элемент с вершины, так что пришлось заменить его на отдельную функцию.
Результаты следующие:
mac@mac ~/Sites/test $ php autoc/stack.php
Array: 0.27216792106628
Array Object: 0.7418909072876
SplStack: 0.29819416999817Как видно, примитивные типы
Для интереса, релизовал примерно то же самое на Пайтоне (только DUP немного иначе работает, для скорости):
from __future__ import print_function
import time
input = '10 20 100 + - 20 * DUP 10 20 + * =';
operations = {
'+': lambda: stack.append(stack.pop() + stack.pop()),
'-': lambda: stack.append(stack.pop() - stack.pop()),
'*': lambda: stack.append(stack.pop() * stack.pop()),
'=': lambda: stack.append(stack.pop() == stack.pop()),
'DUP': lambda: stack.append(stack[0]),
'DUMP': lambda: print(stack)
}
t = time.time()
for x in xrange(0, 10000):
stack = []
for chunk in input.split(' '):
operations.get(chunk, lambda: stack.append(int(chunk)))()
print('Python list: %f' % (time.time() - t))Время выполнения — 0,56 секунды, то есть на ПХП быстрее. Зато, если запустить этот код через PyPy (это интерпретатор с JIT), то результат куда более впечатляет — 0,10 секунды.
Стоимость вызова функции в ПХП
В комментариях к предыдущей заметке мне напомнили о немаловажной подробности, которую я упустил из вида в прошлый раз — в ПХП вызов функции дорогое удовольствие. Как пишут на демотиваторах «по возможности избегайте этого».
Например, если в прошлом примере с массивами array_push заменить на добавление элемента в массив через „[]“, то производительность сразу возрастёт на 0,04 секунды.
В самом деле, есть масса ситуаций, когда вызов функции можно заменить конструкцией или получением данных из константы, так же существуют частные случаи, когда такая замена возможна:
# занесение элемента в массив:
array_push($stack, $element);
$stack[] = $element;
# получение версии ПХП, есть ещё
# PHP_MAJOR_VERSION, PHP_MINOR_VERSION, PHP_RELEASE_VERSION, PHP_VERSION_ID и PHP_EXTRA_VERSION
if (phpversion() === "5.0.0") {}
if (PHP_VERSION === "5.0.0") {}
# способ подключения ПХП
if (php_sapi_name() === 'cli') {}
if (PHP_SAPI === 'cli') {}
# проверка существования ключа, но, увы, это не одно и тоже:
# isset не покажет true, если ключ существует, но значение null
if (array_key_exists('key1', $arr) && array_key_exists('key2', $arr)) {}
if (isset($arr['key'], $arr['key2'])) {}
# для массивов, ключи которых не перекрываются (операция «+» добавит только те ключи,
# которые отсутствуют в первом массиве)
$arr = array_merge($arr1, $arr2);
$arr = $arr1 + $arr2;
# операционная система
if (php_uname('s') === 'Darwin') {}
if (PHP_OS === 'Darwin') {}
# получение переменной окружения. Есть отличие: массив $_ENV может быть перезаписан другим кодом,
# при этом реальное значение переменной окружения не изменится, кроме того,
# getevn не сгенерирует предупреждение, если значения с таким ключом нет
if (getenv('VARNAME') === 'value') {}
if ($_ENV['VARNAME'] === 'value') {}Наверняка есть и ещё случаи, которые я не смог сходу вспомнить, буду благодарен, если
«Граул» и протокол ГНТП
У меня тут «Граул» обновился на «Маке» и я краем глаза увидел, что появилась поддержка
«Граул», для тех кто не в курсе, программулина, которая позволяет различным сторонним программам формировать всплывающие уведомления в едином унифицированном виде. Кстати, существует и версия для «Виндоуз».
Включается поддержка ГНТП специальной галочкой в настройках, после чего можно отсылать свои уведомления. Там же можно задать и пароль, чтобы ни одна сволочь снаружи не смогла

Протокол несложный и поддерживает три команды: можно зарегистрировать своё приложения и его типы сообщений, сформировать сообщение и подписаться на события. Для параноиков поддерживается ещё и шифрование (AES, DES или 3DES на выбор).
Прежде чем ваше приложение отошлёт сообщение, оно должно «зарегистрироваться» в «Грауле» — представиться и рассказать что за сообщения оно будет слать и как их оформлять. Ниже на скриншоте показан список зарегистрированных приложений, включая мой скрипт.

Я тут попробовал поработать с ГНТП из bash-скрипта, получилось удобоваримо, заодно вспомнил как работать с утилитой expect (можно было бы использовать netcat, но telnet плюс expect — интереснее и более гибко).
Увы, у expect под «Маком»
Внутри файла, в конце есть пример, который показывает как отослать сообщение и, в случае неудачи, попробовать сначала зарегистрировать своё приложение и потом отправить своё сообщение ещё раз:
# Пробуем отослать сообщение
cmd='GrowlSendNotify "" "" "Hello all!"'
eval $cmd || (
GrowlSendRegister && eval $cmd
)Внутри моего скрипта есть ещё функция получения IP локальной машины, на самом деле она там лишняя — «Граул» слушает на всех адресах, но мне было интересно написать такую функцию.
Экологически чистый
Понятие «экологически чистый» превращается из осмысленного словосочетания в бессмысленное. Это выражение сейчас является синонимом «полезного для здоровья» и «натурального», в противопоставление «химии». Кроме того, смешиваются два понятия — «безвредное для экологии» и «произведённое природой».
На мой взгляд, «экологически чистый» — это именно «безвредный для экологии», с некоторыми оговорками. Если на целину навезти десятки тонн натуральный глины, ничего хорошего для экологии не будет, хотя, на мой взгляд, она вполне экологична. Я
И вот ещё: некоторая продукция считающаяся экологически чистой
С «натуральностью» и «химией» мне вообще ничего не ясно, этого нельзя понять, можно только запомнить, правил нет. Морёное дерево считается «натуральным», «экологичным» продуктом, хотя и пропитано ядовитой морилкой (именно поэтому его и не едят жучки,
Пищевая сода считается «натуральной», хотя её производит химическая промышленность (например, способ Сольве — обычная химическая реакция) , а усилители вкуса — «химия», несмотря на то, что, например, глицин и глютамат синтезируются организмом самостоятельно. Глютамата, например, полно в молочных продуктах, мясе, рыбе.
С полезностью то же. Кварцевый песок — натуральный, произведённый природой, экологически чистый, но ни разу не полезный для здоровья.
Всё пришло к тому, что «экологически чистый» стало чисто маркетинговым слоганом, вроде его антипода «ГМО». Некоторые ребята уже даже не понимают почему я смеюсь над «поваренной солью без ГМО» и не паникую перед «модифицированным крахмалом» (в последнем случае, кстати, вообще смешно — крахмал это химическое вещество, (C6H10O5)n, он генов не содержит, его модификация к ГМО отношения не имеет, там даже слова «ген» нет, а люди всё равно пугаются).
Ne smeshite moi tapochki
Ребята, прекратите мне уже писать, что от написания «Микрософт», «Мак ОС» и «Айпад» у вас глаза выпадают.
И не надо говорить мне, что слову «Бруклин» сто лет в обед, а «Айпад» появился два года назад. Ну и что?
Когда я еду в гости к родителям, я проезжаю через сёла Шуран и Чирпы. Готов поспорить, что подавляющее число читателей видят эти названия в первый раз и никто сейчас не сломал глаза. В 1999 все наши СМИ писали о Киану Ривзе, многие увидели это имя впервые в том же году и ничего, никаких растерянных коментариев по этому поводу.
Аргумент про «неестественность» я тоже не принимаю. Нет ничего естественного для русского языка в имени Дженифер Лопес, а карта Татарстана, где я живу, содержит кучу татарских названий. Например, я одно время работал в рабочем посёлке Карабаш («кара» — «чёрный», «баш» — «голова», два татарских слова).
Неестественность, кстати, тоже понятие относительное. Например, «хак», «фря», «расшаривать», «таск», «лаг», «бот», «ник» и ещё масса слов — вполне себе русские, я пять лет назад писал об этом. Понятно, что значение у них было другое, но с точки зрения звучания они вполне естественны для нашего языка.
Не говоря уже о целой куче заимствований из французского, греческого, латыни и так далее. Чем именно английский такой особенный?
Второй агрумент, обычно — про поисковики. Но,
Электромобили
Пока мы тут удивляемся гибридным моделям, мир потихоньку переходит на электромобили. В позапрошлые выходные мы побывали в Риме, Ватикане и Стамбуле, убедились, что «там» это уже не редкость.
Вот электромобиль в Ватикане, заряжается от специальной розетки:

Вот на таких электрических мотоциклах (самокатах? на нём стоят) производства Т3 моушн, катается полиция около мечети Султанхмет в Стамбуле.

Драгоценное время
По результатам нашего обсуждения темы «Эксплорера» в твитере у Александра Шабуневича родилась статья «Internet Explorer: хороший, плохой, злой». Я её комментрировать не буду, по крайней мере пока, у меня давно была идея написать статью показывающую заслугу Микрософта в становлении веба,
Я хотел подробнее остановиться на цитате из твитера, которую Александр неверно понял:

Я так и подумал, что будет
Если я убеждён в собственной правоте, мне есть что сказать и мне интересен собеседник, я трачу много времени на то, чтобы обдумать свою позицию, вовлекаюсь полностью в предмет спора. Даже если это формат твитера, «неонка внутре» у меня светит с той же силой. И когда собеседник обрывает меня фразой «останемся при своих», у меня и возникает чувство, что весь этот внутренний жар «ушёл в свисток».
Вот это я и пытался выразить той фразой, к сожалению, твитер со своим ограничением в 140 символов не позволяет выразиться точнее.
Персик — это фрукт!
Я заметил, что многие девушки считают, что мужчины плохо различают оттенки, тогда как, якобы, девушки в них прекрасно разбираются. Мне это иногда преподносят как непреложную истину и очень удивляются, когда я спорю.
Мне показалось, что дело в следующем. Мужчины всё упрощают — большинство оттенки различает, но не делает попыток запомнить как оттенок называется, поэтому цвет называется по преобладающему. Так салатовый или фисташковый становится «зелёным», а лавандовый — «синим».
Хорошо, если мужчина помнит
Женщин помнить оттенки обязывает социум. Считается, что одежда — это вообще больше про девочек, разговоры «про тряпки» — женская тема, а в этих разговорах никуда без знания названий оттенков.
У женщин другая проблема. Взгляды на то, что такое «бирюзовый», «розовый» или «персиковый» могут различаться. Потому что на самом деле, у 16,7 миллионов цветов, доступных глазу, лишь малая часть имеет названия, так что «бирюзовый» — это диапазон, причём не формализированный. У одних границы этого диапазона одни, у других — другие.
Старый новый
Меня удивляет, что некоторые люди не знают что такое «Старый Новый год». Нет, я не про существование самого праздника, а про то как он появился. Я об этом узнал ещё в школе, на уроках истории, и хотя историю я не любил, тем не менее, этот факт запомнил, правда тогда мне рассказали о нём в весьма упрощённой трактовке.
Все знают, что год у нас равен 365 и 366 дням, в зависимости от високосности. В високосный год в феврале есть
Ещё есть високосная секунда, о чём знают горазно меньше людей, но обязаны знать программисты, так как время от времени в минуте бывает 61 секунда. Например, через четыре дня, 30 июня, на часах, которые смогут это показать, будет 23:59:60.
В общем, календарь, где год равнялся 365,25 дням. Т. е. каждые четыре года вводился дополнительный день, но оказалось, что этой поправки недостаточно и за сотни лет накопилась солидная ошибка.
Поэтому ему на смену пришёл более точный григорианский календарь, где год составляет 365,2425 суток, а накопившуюся ошибку просто добавили к текущей дате в момент перехода. Даты после принятия григорианского календаря называют «по новому стилю», до — «по старому стилю».
Каждые 128 лет в прежнем календаре накапливалась ошибка в один день. В России переход состоялся в 1918 году и накопившаяся ошибка составила 13 дней, после 31 января в этом году шло сразу 14 февраля, в этот момент и родился «Старый Новый год», который отмечается до сих пор, тем более, что РПЦ новый календарь не приняла и продолжает встречать все праздники по старому календарю.
Для меня в этой истории важно следующее.
Когда я занялся историей своей семьи, быстро столкнулся с датами «по старому стилю». Например, мой прадед Феодор Николаевич Старостин родился 9 августа по старому стилю, что соответствует 22 числу по новому. А вот что было для меня новостью (и что мне не рассказали в школе), что разница между старым и новым стилем не постоянна.
Вообще, это логично, конечно, если об этом задуматься — ведь ошибка копилась со временем. Например, даты от 29 февраля 1900 года до 1 марта 1800 года сдвигаются уже на 12 дней (в Википедии есть табличка). То есть даты рождения моего прапрадеда, Николая Феодоровича Старостина (1870 год) или его супруги, Анастасии (Юстины) Евдокимовны Меркуловой (1873) нужно сдвинуть на 12 дней.
Сканирование наличия метрических книг
Написал небольшой скрипт на ПХП для сканирования наличия метрических книг в Национальном Архиве Республики Татарстан. У них на сайте приходится по одному году выуживать, что страшно долго.
Так как некоторые архивы горели, в них могут отсутствовать записи
Мой сканер задаёт те же вопросы, что и сайт Национального Архива (губернию, уезд и прочее), а на последнем шаге спрашивает диапазон лет для сканирования. В конце работы печатает результат.
Как же мне это всё напоминает программирование двадцать лет назад! «Введите число и нажмите „Ввод“», правда тогда я всё больше на языках ассемблеров писал. Текст скрипта.
<?
$URL = 'http://www.archive.gov.tatarstan.ru/_go/anonymous/metbooks/';
$COOKIE = '';
// парсим страницу, вынимаем оттуда все теги SELECT
function U_getselects($url, $content = false)
{
if ($content === false) {
global $COOKIE;
$opts = array(
'http' => array(
'method' => 'GET',
'header' => 'Cookie: ' . $COOKIE,
),
);
$content = file_get_contents($url, false, stream_context_create($opts));
foreach ($http_response_header as $header) {
if (preg_match('/^set-cookie:.*?(PHPSESSID=[^; ]+)/i', $header, $m)) {
$COOKIE = $m[1];
break;
}
}
}
$out = array();
$content = iconv('cp1251', 'utf8', $content);
if (preg_match('@<span class="bt4r">([^<>]+)</span>@si', $content, $m)) {
echo 'Ошибка: ', $m[1], "\n";
exit;
}
$mask = '@<span class="bt4b">([^<>]+)(?:<[^>]+>\s*)*?<select\s+.*?name="([^"]+)"[^>]*>(.*?)</select>@si';
if (preg_match_all($mask, $content, $matches, PREG_SET_ORDER)) {
foreach ($matches as $select) {
$options = preg_match_all('/"([^"]+)"/s', $select[3], $m) ? $m[1] : array();
$out[] = array(
'title' => $select[1],
'name' => $select[2],
'options' => $options,
);
}
}
return $out;
}
// Даём пользователю выбрать какой-то пункт из найденного SELECTа
function U_reactselect($select)
{
for (;;) {
echo $select['title'], "\n";
foreach ($select['options'] as $key => $val) {
if (strpos($val, '/') !== false) list(,$val) = explode('/', $val, 2);
printf("% 2d. %s\n", $key + 1, $val);
}
echo "\nПожалуйста, введите номер пункта и нажмите Enter: ";
$value = (int) fgets(STDIN);
if (in_array($value - 1, array_keys($select['options']))) {
echo "\n";
return $select['options'][$value - 1];
}
echo "\n\nТакого пункта нет в списке. Попытайтесь ещё раз, пожалуйста.\n\n";
}
}
// Отправляем запрос
function U_postselect($url, $fields)
{
global $COOKIE;
$fields = array_map(function($item) {
return iconv('utf8', 'cp1251', $item);
}, $fields);
$opts = array(
'http' => array(
'method' => 'POST',
'header' => 'Cookie: ' . $COOKIE . "\r\n".
'Content-type: application/x-www-form-urlencoded',
'content' => http_build_query($fields),
),
);
return file_get_contents($url, false, stream_context_create($opts));
}
// Просим ввести диапазон
function U_getyear($message)
{
echo $message;
$val = (int) fgets(STDIN);
return min(1917, max($val, 1724));
}
$postcontent = false;
for ($step = 1; $step < 3; $step++) {
$choices = array();
foreach (U_getselects($URL, $postcontent) as $select) {
$choices[$select['name']] = U_reactselect($select);
}
$choices['action'] = 'step' . $step;
$choices['to_step' . ($step + 1)] = 'Далее >';
$postcontent = U_postselect($URL, $choices);
}
$choices = array(
'to_step4' => 'Найти',
'action' => 'step3',
);
foreach (U_getselects($URL, $postcontent) as $select) {
$choices[$select['name']] = U_reactselect($select);
}
$from = U_getyear('Введите начальный год: ');
$to = U_getyear('И конечный: ');
if ($from > $to) {
list($from, $to) = array($to, $from);
}
$years = array();
echo "\n";
for ($year = $from; $year <= $to; $year++) {
$choices['year'] = $year;
$postcontent = U_postselect($URL, $choices);
$found =
strpos($postcontent, "\xed\xe5\x20\xed\xe0\xe9\xe4\xe5\xed\xfb") === false &&
strpos($postcontent, "\xed\xe0\xe9\xe4\xe5\xed\xfb") !== false;
if ($found) {
$years[] = $year;
echo '+';
} else {
echo '-';
}
}
if ($years) {
$years[] = INF;
echo "\nАрхив найден за следующие годы: ";
for ($i = 0, $l = sizeof($years); $i<$l-1; $i++) {
if ($i) echo ', ';
echo $years[$i];
for($c = 0, $i++; $i<$l; $i++, $c++) {
if ($years[$i] - $years[$i-1] > 1) {
$i--;
if ($c) {
echo '-', $years[$i];
}
break;
}
}
}
echo "\n";
} else {
echo "\nНичего не найдено.\n";
}
С вас пять кредитных карт!

Как люди умудряются такое писать? Они потом не читают что получилось что ли?
Opera 12 CSS hack
Вышла «Опера» 12, многое поменялось, на некоторых моих сайтах едут стили. В частности, на «Маке» «Опера» поменяла поведение стиля
Пришлось придумывать
Хак получился вот такой:
@media (min-resolution: .001dpcm) {
_:-o-prefocus, body { /* стиль только для Opera 12.00+ */
background: red;
};
}Соответственно, на место «body» надо поставить требуемый тег или селектор.
Как определить модель iPad через JavaScript?
На «Хабре» наткнулся на любопытный код на JS, который определяет с каким Айпадом мы имеем дело — первым, вторым или третьим. Третий ото всех остальных отличить просто — у него в свойстве «devicePixelRatio» значение „2“ записано. А первый от второго как?
Оказывается способ есть — надо в событии «devicemotion» проверить есть ли у устройства акселерометр. Не знаю для чего это всё может пригодиться (разве что отключать
Я немного переписал код, сделал из него функцию, чуть упростил и навёл порядок. Получился вот такой код:
// функция для определения модели Айпада
function detectIPadVersion(callback, undefined) {
if ('ondevicemotion' in window) {
window.addEventListener('devicemotion', function self(event) {
if (~navigator.platform.indexOf('iPad')) {
var version = event.acceleration ? (window.devicePixelRatio === 2) + 2 : 1;
}
window.removeEventListener('devicemotion', self);
callback(version);
}, false);
} else {
callback(undefined);
}
};
// пример вызова, в callback будет передан номер модели (1,2 или 3) или undefined, в случае, если это не iPad
detectIPadVersion(alert);