По родным

пробабушка Вера (39.20КиБ)

В Сергиевск (село в Самарской области) я приехал, чтобы распросить своих родных, которых не видел много лет, о родственниках по отцовской линии. Теперь у меня уже записано 382 человека родственников и ещё есть куда работать. Тётя Валя, сестра моей бабушки со стороны папы, рассказала ещё и своём детстве. Трудно жили.

Больше всего меня поразило, что́ сельский фельдшер «прописал» её сестре, Вере в качестве лечения от кори. Его «рецепт» заключался в том, чтобы занавесить окна красным. Девочка умерла, в восемь лет, шёл 1946 год.

На фотографии — монашка Вера Гусева (справа), это уже другая Вера, двоюродная сестра Пелагеи Евдокимовой, мамы мужа уже упомянутой моей двоюродной бабушки Вали.

Оставить комментарий

☁☁ ✈ ☁☁ ☀

Мы тут с женой в отпуск собрались, не теряйте! Как получится писать не знаю. Повторяю маршрут, если что. Сегодня в 22:40 вылетаем.

Москва → Нижнекамск → Лениногорск → Сергеевск → Казань → Москва → Санкт-Петербург → Хельсинки → Таллин → Рига → Варшава → Москва

26 комментариев

Спяааат устааалые игрушки, книжки спяааат…

Сегодня скрипач в метро, в переходе с Театральной на Охотный ряд играл «Спят усталые игрушки…». А у меня рефлекс ещё с советских лет, я же в детстве смотрел «Спокойной ночи, малыши!», там если играла эта музыка, то всё, Хрюша и Степашка прощаются с вами, пора спать. Весь рабочий настрой с утра сбил! Нельзя так, товарищ!

12 комментариев

JPEG vs. DjVu

Мне кажется, формат DjVu получает незаслужено мало внимания. Те, кому надо хранить документы, делают это, чаще всего, в JPEG или TIFF (а то и в PNG), а об DjVu вообще мало кто слышал. Я взял первый попавшийся в поиске документ, чтобы проиллюстрировать всю мощь формата.

JPEG vs. DjVu (69.42КиБ)

Картинку я уменьшил (до 636 по ширине) и сконвертировал в два формата. Слева на картинке JPEG, справа DjVu. Картинка в JPEG занимает 85КБ (качество — 85%, сжато jpegtran), в DjVu — 13КБ (качество — «normal», сжималось any2djvu). Выигрыш в 6,5 раз при сходном качестве.

За счёт чего достигается такой результат?

Дело в том, что JPEG — формат общего назначения, он ничего не знает о том какое изображение хранит, DjVu придумывался специально под текстовые документы и знает — внутри него, в основном, чёрно-белый текст (возможно с фоном) и вкрапления иллюстраций.

Поэтому обрабатываемое изображение разделяется на три слоя: фон, передний план и маску. По сути, изображение разделяется на две части: то, что будет сохранено с низкой детализацией (иллюстрации и фон) и то, что с высокой детализацией (текст). Маска нужна, чтобы при просмотре наложить одно на другое. Обе части сжимаются вейвлет-преобразованием, но с разным качеством, а маска (она однобитная) сжимается алгоритмом JB2.

Эффективность сжатия DjVu сильно зависит от того есть ли на картинке задний фон, если его нет и изображение только чёрно-белое, то размер отсканированной страницы в разрешении 600dpi (говорит нам Википедия) — всего 15КБ!

27 комментариев

Проверка типа соединения в «Андроидах»

Оказывается в «Андроидах», начиная с версии 2.2 есть специальное свойство у navigator.connection, которое позволяет узнать тип соединения: «navigator.connection.type». Объект «navigator.connection» содержит так же несколько констант, с самодокументируемыми названиями, которые содержат все возможные значения типа соединения: UNKNOWN, ETHERNET, WIFI, CELL_2G, CELL_3G.

with (navigator.connection)
if (type == CELL_2G || type == CELL_3G) {
    // медленное и/или платное
}

На последней, на данный момент прошивке iOS на iPhone 4, увы, это свойство не поддерживается.

15 комментариев

Кодировка rot13 в Пайтоне

В стандартном интерпретаторе Пайтона есть много такого, что иначе как «пасхальным яйцом» не назовёшь. Например, можно попробовать импортировать модули «__hello__», «this» или сделать «from __future__ import braces» (попробуйте), но следующее просто гениально, хотя, видимо, получилось случайно.

В файле программы на Пайтоне в специальном коментарии принято указывать кодировку файла. В случае с латиницей работает и без этого, если применяется UTF-8, то это делать обязательно. Интерпретатор поддерживает множество кодировок (честно сказать, я не знаю сколько именно) и одна из них — rot13. Используются те же самые кодировки, что и в методах encode и decode у строки. Я думаю после считывания файла программы именно они и вызываются.

Вот вполне валидная программа, которая выполняется и делает нечто осмысленное:

# coding: rot13

vzcbeg __uryyb__
cevag "Zl anzr vf Ritral Fgrcnavfpuri nxn Obyx!".rapbqr("rot13")

Кодируется только текст программы, поэтому-то мне и пришлось «rot13» написать как есть.

8 комментариев

У клиента дохлый канал?

В 1997 году, когда я впервые увидел веб через графический браузер (до этого у меня был опыт выхода в интернет через терминал на базе i80286 через текстовый браузер Lynx), у меня была выделенка, дело было в Казанском Государственном Университете и ещё очень долго я не знал что такое диалап и оплата за трафик.

Сейчас выделенки у большинства, но нередко встречается и такое, что клиент приходит на сайт через «дохлый канал» или с оплатой по трафику (например, через сотовый телефон).

Хорошо было бы об этом как-то узнать и не грузить клиенту лишние подробности в этом случае. Браузеры такое API не предоставляют (ещё бы, они и сами ничего не знают про канал), такую обобщённую информацию получить неоткуда. Но можно попытаться об этом догадаться. Эта запись — сборник моих сырых мыслей на эту тему.

Я вижу несколько путей.

  • можно замерить время за которое страницу удалось отдать клиенту целиком. У меня пока нет оформившихся мыслей о том как это делать и есть недостаток — когда мы узнали о том, что у клиента плохой канал, содержимое уже выдали, ничего поменять нельзя. Можно выдавать chunked-контент, как предлагал Сергей Чикуёнок, но первый кусок должен быть значительным
  • после загрузки страницы «пропинговать» хост. То есть обратиться через XHR на свой же сайт и замерить время ответа. Опять же, что делать с этими данными? Есть возможность в следующий раз показать более бедное содержимое, но следующий запрос может идти через другой канал. Возможное решение — сохранять IP-адрес запроса
  • смотреть с какого браузера клиент приходит, если это «Опера Мини», вероятнее всего, канал плохой или с оплатой
  • опять же «Опера», если включена функция «Опера Турбо» (определяется по IP-адресу клиента), клиент экономит трафик, значит канал с оплатой
  • проверить грузятся ли картинки, способов много, но данные получаем постфактум, после загрузки страницы. Логика та же — выключил картинки, экономит. Загрузку Flash контролировать смысла не имеет — многие выключают, чтобы не видеть рекламы
  • проверять не пришёл ли человек через канал сотового оператора (по IP-адресу). Безлимиток, которые бы не деградировали по скорости после какого-то лимита пока исчезающе мало, так что имеет смысл отдавать в этом случае «обеднённый» контент. Мобильные браузеры определять смысла не имеет — клиент может прийти через WiFi
  • в комментариях подсказали, что в «Андроидах» 2.2 и выше есть специальное
    API, чтобы определять способ подключения
  • ещё вариант из комментариев — определять модель телефона/планшета и по базе смотреть есть ли у него GSM/3G или WiFi
    Кто-нибудь ещё какие-то пути видит?

37 комментариев

Макакин копирайт

Макака-кривляка (105.63КиБ)

Фотографии макаки, которая якобы сфотографировала себя на фотоаппарат, случайно оставленный каким-то фотографом, видели многие. Если не видели, то выше одна из них, остальные можно посмотреть, на сайте «Daily Mail», например.

У меня большие сомнения, что макака могла найти нужную кнопку и понять закономерность, ну да бог с ними, нас убеждают, что фото сделала макака, давайте поверим.

Итак, фото сделано макакой. Внимание вопрос: кому принадлежат копирайты на данные фотографии?

Вроде бы очевидно, что это теперь общественное достояние, так как фотограф (по первой озвученной версии) случайно оставил фотоаппарат и на кнопку нажимало (являлось автором творчества) живое разумное существо (пусть и с низким IQ), права которого не регулируются законами о копирайте.

Тем не менее, фотограф, которому принадлежит фотоаппарат и агенство, которому были (я так думаю) проданы снимки не согласны. Интересно будет посмотреть за развитием событий.

15 комментариев

Как вам, жаворонкам, живётся?

Решил провести эксперимент — вставать до конца недели на два часа раньше, в восемь утра. Не экстремально рано, конечно, но для меня, совы, всё же довольно рано. Сегодня встал в первый раз. Пока всё нормально.

28 комментариев

Сравнение объектов встроенных типов в Пайтоне

Некоторым ребятам показалось, что в заметке про «goatse operator» в Перле я поругал этот язык. Это не так, можно прочитать заметку от и до, чтобы в этом убедиться. Мне очень нравится Перл, но это язык не для современного продакшна. Давайте я что-нибудь забавное расскажу и о языке, на котором больше всего сейчас программирую — про Пайтон.

В Пайтоне всё что только можно — объект и нет примитивных типов. С объектами можно делать всё что хочется — сравнивать, умножать, производить битовые операции. Чтобы программист мог указать как объекту следует себя вести рядом с каким-то оператором, следует определить некоторые «магические» методы, например, «__cmp__», «__mul__» и какой-нибудь «__xor__».

Где-то внутри какие-то «магические» методы определены и для встроенных типов (которые тоже являются объектами, напоминаю), ведь надо же как-то сравнивать две строки или строку и число:

In [26]: "Это строка".__eq__
Out[26]: <method-wrapper '__eq__' of str object at 0x10136f770>

In [27]: "Это строка".__ne__
Out[27]: <method-wrapper '__ne__' of str object at 0x10139cf70>

Сравнивать между собой можно большинство встроенных типов — список с со словарём, строку с кортежем и так далее. Есть исключения (например, set нельзя сравнить ни с чем, кроме set и frozenset), но их мало. Какой же будет результат сравнения? Давайте попробуем:

In [44]: "">()
Out[44]: False

In [45]: ""<()
Out[45]: True

In [46]: []>()
Out[46]: False

In [47]: []<()
Out[47]: True

In [48]: []<{}
Out[48]: False

In [49]: []>{}
Out[49]: True

Даже пустые объекты разных типов не равны между собой, но какое-то правило определённо есть, не случайным же образом создатели языка выбирали что больше чего. Добавление значений в объекты ситуацию не меняет, не играет роли их число и значение. Я намеренно оставляю в стороне числа (типы int, float и complex) и лишь походя затрагиваю строки (str и unicode), там как там правила немного другие, но это неважно.

In [52]: [1,2,3,4,5,6]<(0,)>[100000]
Out[52]: True

Не знаю где это написано в документации, не искал, но я совершенно случайно, из какой-то книги знаю, что на самом деле сравниваются первые буквы типов. Зная эта правило, легко сформировать длинное сравнение, которое будет истиной:

True < {} < [] < object() < "" < () < u""
# b < d < l < o < s < t < u

Решение мне кажется, мягко говоря, неудачным, но уж какое выбрали. Я не вижу ничего страшного в том, чтобы сравнение встроенных типов всегда выдавало False (попробуйте сравнить между собой два None) или выдавать исключение при попытке их сравнения (кажется в 3-й версии Пайтона так и сделали).

2 комментария

Плагины по запросу в «Опере»

Плагины по запросу (27.46КиБ)

Хочу похвалить «Оперу» за галочку в настройках, которая недавно появилась. С ней стало удобнее. Теперь можно выключить плагины (Flash, Java, Silverlight и остальное, в куче) для всех сайтов разом, а потом включить их для определённых сайтов (YouTube, RuTube, video.yandex.ru и так далее) в отдельных «Настройках для сайта» (открывается по клику правой на странице).

На местах, где должны показываться плагины, если установлена галочка «включать плагины только по запросу», показывается большая серая треугольная кнопка проигрывания, которая запускает Flash-ролик (или другое подобное содержимое), если на неё нажать.

Очень удобно. Спасибо, ребята!

16 комментариев

Не хочу я выключать ноут в самолёте-2

Помните мы обсуждали нужно ли выключать технику в самолёте?

Я сегодня летел бизнес-классом S7 (завтра проверю ещё в бизнес-классе «Аэрофлота»), там техникой можно хоть обложиться. Рядом со мной, на столике стоял мой включенный ноутбук и я читал с телефона. Ни одна стюардесса ни разу не сделала мне замечание. Хотя о том, что технику надо выключать объявили на весь салон.

Через проход сидел дядька, смотрел с «айПада» какой-то фильм, за ним сидела женщина, у неё тоже какая-то электроника светилась.

В двух сидениях позади меня техникой пользоваться уже нельзя (я не раз летал рейсами S7), хотя я ближе к кабине (собственно, на рейсовых самолётах я в первый раз в жизни летел в первом ряду).

Дополнено позднее: обратно летел совместным рейсом «Аэрофлота» и «Дон-Авии». Самолёт принадлежит «Дон-Авии», при взлёте и посадке техникой пользоваться запретили.

23 комментария

location.reload() ≠ location.href=location.href

Увидел у Никиты Васильева во внутренних бложиках, что вызов «location.reload()» не эквивалентен присваиванию location.href в себя же. Оказывается, последний перезагружает страницу из кеша во всех браузерах, кроме «Оперы».

6 комментариев

Макбук под рентгеном

Макбук и фотоаппарат (37.16КиБ)

Смотрите-ка, полиция после взрывов начала делать что-то более существенное, чем установка рамок, на писк которых никто внимание не обращает — установили у некоторых входов в метро сканеры для багажа, похожие на большие духовые шкафы.

Меня вчера на Охотном ряду остановили в метро, попросили рюкзак положить в эту «микроволновку» и даже совершенно не препятствовали тому, чтобы я это всё сфотографировал (правда на телефон, фотоаппарат в рюкзаке остался). Итого на фото видно мой Макбук (в алюминиевом корпусе) и фотоаппарат (продолговатое тёмное на фоне ноута).

7 комментариев

Оператор goatse в Перле

Внезапно вспомним Перл. Когда-то я на нём много и в удовольствием программировал, причём этот навык не утерян мною до сих пор. Хотя попрограммировать на этом девиантном языке мне удаётся редко, я по-прежнему им восхищён. Немного жаль, что он умирает, но право же, чаще программы на нём можно слать в передачу «А вам слабо?», чем в продакшн.

Есть такая шутка, что Перл единственный язык, программа на котором до и после RSA-шифрования выглядит одинаково. Честно сказать, я не уверен, что это шутка, так как вот это, например, вполне разумная программа на Перле:

not exp log srand xor s qq qx xor
s x x length uc ord and print chr
ord for qw q join use sub tied qx
xor eval xor print qq q q xor int
eval lc q m cos and print chr ord
for qw y abs ne open tied hex exp
ref y m xor scalar srand print qq
q q xor int eval lc qq y sqrt cos
and print chr ord for qw x printf
each return local x y or print qq
s s and eval q s undef or oct xor
time xor ref print chr int ord lc
foreach qw y hex alarm chdir kill
exec return y s gt sin sort split

Если не верите, попробуйте запустить, ничего страшного не произойдёт. Очень много шуток есть по поводу того, каким ненатуралом надо быть, чтобы программировать на этом языке и в этом тоже есть доля правды.

Я постараюсь пропустить неаппетитные подробности, но есть такой мем «goatse» — это картинки мужичка, в деталях показывающего свою тёмную неизвестность, а так же пародии на неё. Не гуглите пожалуйста это, прошу, нет, даже умоляю, не надо. Та картинка, как любой шок-контент, используется в троллинге.

Для нас важно, что после того как картинка стала мемом, появился смайлик „=()=“, довольно точно отражающий её суть. Я знаю эту преамбулу, потому что однажды какой-то экспериментатор нашёл в Перле то, что назвали goatse operator — тот самый „=()=“, который, что интересно, позволяет делать довольно разумную вещь.

Например, вам нужно подсчитать сколько цифр содержится в строке. На помощь вам придёт goatse operator!

my $s = "Hello, world! This is a Perl! 123456";
my $c =()= $s =~ /\d/g;
print $c;

В результате будет напечатано число шесть.

Как это работает и почему нельзя как-то иначе?

Сначала отвечу на первую часть.

Самое правое выражение в рассматриваемой строчке — регулярное выражение, которое ищет одну цифру, оператором «=~» мы применяем его к конкретной переменной, а ключ «g» в конце регулярки говорит, что искать надо все вхождения.

В Перле есть понятие скалярного и списочного контекста. Результат может сильно отличаться в зависимости от того ожидается ли в каком-то месте кода скаляр или список (массив). Программист даже может проверить в каком контексте вызвана его функция при помощи специальной функции «wantarray».

Например, если я попробую напрямую присвоить результат выполнения регулярного выражения на переменной „s“ в скалярную переменную (начинается с доллара), то я получу флаг, показывающий встретились ли вообще цифры в рассматриваемой переменной. Если же присвоить тот же результат массиву (имя переменной начинается с «@»), то я получу массив совпадений.

С goatse operator происходит следующее.

На деле «() = что-то ещё» — это обычное присваивание массиву чего-то ещё. Пустые скобки — пустой анонимный массив, ему тоже можно что-то присвоить, синтаксис это позволяет. Таким образом контекст не скалярный и мы всего-то присваиваем одному массиву другой. Дальше чуть интереснее. По правилам Перла присваивание первого массива второму в скалярном контексте возвращает количество элементов первого.

Получается «SCALAR = LIST0 = LISTREGEXP», что возвращает нам количество элементов массива LISTREGEXP при любом не константном LIST0. Двумя присваиваниями, идущими подряд, вряд ли кого-то удивишь, цепочки присваиваний можно использовать в Си, JavaScript, PHP и куче других языков.

Теперь ответ на второй вопрос. Нельзя ли как-то иначе. Можно. Если религия вам не позволяет использовать «оператор» с такими сомнительными ассоциациями, то можно, например, присвоить результат работы регулярного выражения переменной-массиву, а потом взять его в скалярном контексте. Как-то так:

my $s = "Hello, world! This is a Perl! 123456";
my @c =$s =~ /\d/g;
print scalar @c; # массив в скалярном контексте вернёт количество элементов

Но это скучно.

25 комментариев

33000 и анимированный GIF

Черная цифра 1 на белом фоне

По всей видимости, «Опера» немного неправильно обрабатывает анимированные «гифы».

Анимированный GIF устроен очень просто — поверх первого кадра через заданное время лепится следующий. Задержка задаётся в сотых долях секунды и, согласно спецификации, поля для её хранения имеет размер беззнаковое слово (2 байт), то есть максимальное значение — 655,35 секунд или почти 11 минут.

Распространённая ошибка в Си и похожих языках — использовать вместо беззнакового число со знаком. Тогда максимальное значение по модулю сокращается в два раза.

Вот я и проверил — не содержат ли кодеки популярных браузеров эту ошибку. На картике — число «1», если оно через пять-шесть минут сменится на «2», значит ошибки нет. Я выставил задержку между кадрами в 33000 (330 секунд или 5,5 минут). Кодек с ошибкой будет трактовать это число как -233 (отрицательное), поэтому кадр не сменится.

У меня на ноуте на FF 5, Safari 5.0.5, Chrome 12.0.742.122 цифра меняется, а на «Опере» 11.50 — нет. Сейчас попробую найти ноут с Windows 7 и попробую там. Попробуйте тоже на своих браузерах.

Добавлено: меняются ещё цифры на Андроиде 2.3.4, на FF 4.0.1 (Windows), а так же под Internet Explorer 9.0 и 10PP2 (Windows 7).

Добавлено ещё позднее: всё в порядке у «Оперы», разъяснил один из читателей — «Опера» начинает анимацию заново, если GIF не было видно. Дожидаясь, я переключал табы, поэтому анимация стартовала всегда сначала и «2» не появлялась. Так что ложная тревога, но любопытный факт.

14 комментариев

Москва ✈ Казань ✈ Москва

В пятницу вечером срочно вылетаю в Казань, пробуду по вечера субботы. Ничего особенного, рабочие вопросы.

2 комментария

Последний газовый фонарь Москвы

Женщина в синем платье с голубым зонтом проходит мимо книжного магазина «Медицинская книга» с арочным окном и вывеской над входом.
Последний газовый фонарь Москвы

Сегодня выполнил квест — искал последний газовый фонарь Москвы. По крайней мере утверждается, что он газовый. Понятное дело никто точно не знает последний ли он, вот я не обратил бы внимания на такую деталь арки, так что может и ещё где-то есть такие же. Более того, точно неизвестно газовый ли он, так как заляпан основательно (на фото — сразу над надписью, как элемент арки).

Такие фонари в Москве были окончательно заменены электрическими в 1932 году, значит этому фонарю должно быть около 80 лет.

Надо будет сообщить музею «Огни Москвы» о его существовании, может посмотрят что это на самом деле и отреставрируют, если он какую-то ценность представляет.

Добавлено позднее: получил ответ от музея:

Спасибо, Евгений! Про этот фонарь мы уже знаем. Не уверена, что он газовый. Нужно проверять. Есть еще несколько газовых фонарей в нашем городе. Сейчас мы собираем информацию и в скором времени будем пытаться сделать так, чтобы их все взяли под контроль. По крайней мере всем директорам предприятий обслуживающих наружное освещение уже дано указание перед демонтажем фонарей старше 70-х годов ХХ века обращаться к сотрудникам музея. Спасибо за Вашу заботу. Будем рады, если отыщете еще что-нибудь интересное. С уважением, Наталья.

3 комментария