Евгений Степанищев

Я — эксперт в области разработки веб-приложений и безопасности в интернете. Каждый месяц мой блог посещают около 90 тысяч человек. Работаю техническим директором в «Системах документооборота», занимаюсь электронным правительством.

Повторенье — мать ученья

Простите, наболело. Многие товарищи как-то вольно трактуют поговорку «повторенье — мать ученья». Как будто любое повторение чему-то учит. Ну вот вам повторение:
while True: pass
Чему учит нас этот бесконечный цикл на «Пайтоне», кроме того, что бесконечность — это очень долго? Не надо забывать, что повторенье только мать ученья. А чтобы ученье зачалось нужен ещё и папа, а чтобы родилось, хорошо бы и акушера под рукой держать.
27 комментариев
16 апреля 2009 16:12

Девид Блейн, раскукож мой Samsung

Samsung выпустили забавный рекламный ролик обращающий внимание на HD-камеру, встроенную в новый телефон этой фирмы (модель HD i8910).

Его сюжет — мужик ходит по комнате, снимая всё, что там попадается, включая свою подружку и восхищаясь HD-камерой телефона, он подходит к зеркалу, проводит рукой и… камера исчезает, но съёмка продолжается. В аннотации к ролику говорится, что весь ролик снят одним дублем, без монтажа и спецэффектов.

На «Хабре» довольно быстро заподозрили, зеркала никакого нет и в нём стоит просто брат-близнец. Именно поэтому столько слов «HD-camera» и разговоров про детали в ролике — предлагается обращать внимание на мелочи, различающиеся в «зеркале» и в комнате. Я, например, заметил, что зонтик за «зеркалом» не так стоит.

Но помимо мелочей, Samsung прокололась в главном: отражение в чайнике (или что это такое) не совпадает с отражением в «зеркале». И никакие мелочи изучать не надо. Но это только поможет этой рекламе побыстрее забраться нам в головы.

Фокус с телефоном Samsung (43.98КБ)

Дополнение от 16 апреля 2009 13:22: мне в комментариях подсказывают, что необходимости в брате-близнице нет, достаточно одеть второго человека в ту же одежду. Действительно — когда снимающий отражается в чайнике, он старательно прикрывает лицо камерой.
2 комментария
16 апреля 2009 10:28

Знаете ли вы JavaScript

У Дмитрия Барановского (это автор Raphaël — JavaScript-библиотеки для построения диаграмм) в бложике нашёл чудесный тест на знание JavaScript, привожу его здесь полностью. Попробуйте, я прошёл его довольно посредственно.

Итак, что выведет каждый кусок кода?
if (!("a" in window)) {
    var a = 1;
}
alert(a);
var b = function a(x) {
    x && a(--x);
};
alert(a);
function a(x) {
    return x * 2;
}
var a;
alert(a);
function b(x, y, a) {
    arguments[2] = 10;
    alert(a);
}
b(1, 2, 3);
function a() {
    alert(this);
}
a.call(null);
38 комментариев
15 апреля 2009 21:07

I � Unicode

Давайте я вам про Unicode ещё раз расскажу?

Как известно, в памяти компьютера числа представлены битами, которые группируются в байты. Один байт может хранить одно из 256 значений (поскольку состоит из восьми бит, каждый из которых может хранить одно из двух). Следовательно, числа, значения которых > 255 хранятся в больше, чем одном байте.

Например, числа до 65535 можно уместить уже в двух байтах: в так называемом старшем записывается сколько раз полных 256 содержится в числе, а в младшем — остаток: старший × 256 + младший.

В зависимости от типа процессора, порядок, в котором записаны в памяти старшие и младшие байты, различается. Собственно, мне хорошо известны только две системы: младший записывается первым (как в процессорах Intel) и старший записывается первым (в процессорах ARM, которые стоят в смартфонах). Есть ещё смешанная, но с ней я не сталкивался. Системы эти носят имена: little-endian и big-endian (системы со смешанным порядком называются middle-endian и термин не указывает на то как именно «мешается» этот порядок). Краткая запись названий — LE и BE.

Есть ещё системы, которые умеют переключать порядок (те же ARM) и называются bi-endian.

Термины little-endian и big-endian пришли к нам из «Приключений Гулливера» и на русский переводятся как «тупоконечный» и «остроконечный». Те, кто читали, те помнят (война по поводу того с какой стороны разбивать яйца). Информатика тут какбэ намекает. Хотя у каждой системы есть свои достоинства и (не удержался) мне ближе LE.

Сюрприз для непрограммистов: буквы в памяти компьютера тоже представлены числом. Это просто номер по порядку в компьютерном алфавите. Так девочки в нашем классе «кодировали» записки: вместо букв ставили номер позиции в алфавите. В чём-то они были правы, но только не в том, что это шифр.

Когда-то компьютеры победивших сейчас систем использовали всего 256 символов и всем было хорошо — туда умещались все символы, которые присутствовали в том мире, где эти компьютеры создавались. Экспансия привела к тому, что 256 значений для символов перестало хватать.

Было принято очевидное решение — выделять на символ не один байт, а несколько. Так появился стандарт Unicode, где огромному количеству символов дано своё число и закреплены начертания, стандарт дополняется и новые версии выходят почти каждый год.

Система кодирования Unicode, где выделяются два байта, называется UTF-16 (16 бит на символ), там где четыре байта — UTF-32 (32 бита). Название UCS-4 (четыре байта) является синонимом UTF-32, а UCS-2 (два байта) подмножеством UTF-16. UCS-2 отличается от UTF-16 отсутствием так называемых «суррогатных пар» (которые появились только в Unicode 2.0, вы не хотите знать что это) и является устаревшим стандартом, можете про него забыть.

Так как способов хранения чисел, не умещающихся в памяти у нас несколько, то системы подразделяются на UTF-16BE, UTF-16LE, UTF-32BE и UTF-32LE. Отсюда видно, что UCS-4LE это тоже, что и UTF-32LE. Если порядок байт не указан, то принято считать, что используется big-endian.

Первого апреля 2005-го года были предложены шуточные «стандарты» UTF-9 и UTF-18, отношения к рассматриваемой проблеме они имеют. Для телеграфа и прочего слоновьего гуано, разрабатывались UTF-5 и UTF-6, но о их судьбе мне ничего не известно. Так же есть UTF-7, который в стандарт не вошёл, но реально применяется (в модифицированном виде) внутри почтового протокола IMAP4, про него я рассказывать не буду, мне он стал известен из-за оригинального способа его использования для XSS-атак в IE (в частности, решением этой проблемы я занимался в PEAR PHP классе HTML_Safe). Можно упомянуть ещё UTF-1, но с ней я не сталкивался в работе.

BOM. BOM расшифровывается как «byte order mark» (признак порядка байт) и ставится внутри файлов упомянутых двух- и четырёхбайтных кодировок. Если BOM внутри файла не встретился, принимается порядок big-endian. У BOM есть значание. В UCS-2 это 65279 (для программистов — FEFF), для UCS-4/UTF-32 — это 4278124544 (FEFF0000). Число выбрано так, чтобы старшие и младшие байты у них не совпадали и по их порядку можно было бы определить какой порядок байт используется. К сожалению, BOM не даёт возможности определить использутеся двух- или четырёхбайтная кодировка.

Теперь непрограммистам будет трудно.

Пока всё было достаточно просто, но человечество придумало ещё одну кодировку — UTF-8, с плавающим размером. Хорошие новости заключаются в том, что порядок следования байт тут определён и никаких LE и BE рядом с UTF-8 не ставится. Соотвественно и BOM тут не нужен. Он может использоваться только для того, чтобы указать программе, что это именно UTF-8 и имеет номер 15711167 (EF BB BF). Откуда можно сделать вывод (дорогие писатели редакторов), что использование в UTF-8 BOM от UTF-16 — ошибка.

Трудность в том, что UTF-8, по сути это ещё один способ записи многобайтовых чисел (а каждая буква в стандарте Unicode — многобайтовое число). У системы есть целых два плюса (ирония!): старая однобайтовая кодировка совместима с UTF-8, а значит буржуинам не нужно переделывать свои программы, если они не используют в них буквы и других языков (например, на любом старом англоязычном сайте как бы уже используется кодировка UTF-8), второй плюс — латиница записывается компактнее (в один символ). Минусы — чисто программисткие: работа с кодировкой требует больше ресурсов из-за плавающего размера.

Итак. Каждый символ в кодировке занимает от 1 до 4-х байт. Вообще, формат устроен так, что можно было бы взять и более длинные цепочки, но в Unicode нет столько символов, чтобы записывать их более длинными последовательностями.

Тут надо вспомнить что такое биты. Бит — единица информации, мельче не бывает, у него всего два значения — 0 или 1. Байт состоит из 8 битов, биты очень удобно записывать в позиционной двоичной системе: 00001011. «Позиционная» тут означает, что значение числа зависит от его позиции. Кстати, это привычная нам система. В числе «22» две двойки, но у первой значение в десять раз больше, чем у второй. Это десятичная позиционная система. В двоичной, каждая более левая однёрка будет больше в два раза своей соседки.

Таким образом число 1011 расшифровывается из двоичной как 1 × 23 + 0 × 22 + 1 × 21 + 1 × 20 = 1 × 8 + 1 × 2 + 1 × 1 = 8 + 2 + 1 = 11 в десятичной системе.

UTF-8 устроен следующим образом. Пусть, мы двигаемся по строке, содержащей два байта: 208 и 159. В битах это 11010000 и 10011111. (Немного осталось, потерпите).

В первом символе нужно посчитать количество бит со значением «1» до первого нуля. Это общее количество байт, которым записан данный символ. Если количество байт — один (это вроде как специальный признак), то вы нашли не первый байт символа.

У нас в примере количество бит до первого нуля — два. Значит, буква записана двумя символами — первый это тот, на которым мы находимся и второй — который следует за ним. Каждый байт в UTF-8 разбит на две части — до первого нулевого бита. Первая часть — общая длина байт последовательности, а оставшаяся — значение. Биты из значения записывают последовательно (у нас это 10000 011111) и смотрят какое число получилось (у нас это — 1055, это номер буквы «П» в Unicode).

Могу рассказать про UTF-7 и UTF-1, если интересно. Или про суррогатные пары.
38 комментариев
15 апреля 2009 12:26

Уточка №4

Уточка — грузинский космонавт (25.23КБ)

Не могу не попе*арить прекрасный блог, который радует меня по утрам: «уточка №4». Особенно хороши картинки-загадки, типа этой, которую я утащил в свой блог.
9 комментариев
15 апреля 2009 10:02

Определение UTF-8 на чистом Perl

У нас сейчас смена админов: отдел переходит из ведомства одних админов к другим. Соотвественно, все задачи выполняются сильно медленее. Задача по установке модуля к Perl висит уже несколько дней. Вот и пришлось мне написать на чистом Perl функцию, определяющую UTF-8 это или нет.

На Perl'e не писал уже очень давно, так что было интересно что я помню. Функцию, в итоге, сохраню здесь, мало ли — понадобится кому.
sub detect_utf8($) {
    my $str = shift;
    my %exclude = map { $_ => undef } (0..191, 194..244);  # RFC 3629

    for (my $i = 0, $l, $len = length $str; $i < $len; $i++) {
        $code = ord substr($str, $i, 1);

        return 0 unless exists $exclude{$code};

        for ($l = 0; $code & 128; $l++, $code = 0xFF & ($code << 1)) {}

        $i += $l - 1 if $l;

        return 0 if $i > $len or $l > 4; # broken
    }

    1;
}
Что можно улучшить: проверять, чтобы дополнительные байты имели старшие биты «10».
5 комментариев
14 апреля 2009 17:20

Интранет-вики

Мнение о том, что использование вики-разметки вызывает в людях жестокость и неконтролируемую агрессию, легко опровергается одним ударом лопаты по голове.
12 комментариев
14 апреля 2009 11:39

Альтернативные люди


Ребята, ну это просто пиз^Wнеправильно. Ненависть.
18 комментариев
13 апреля 2009 19:16

Доступ по паролю

Большое заблуждение, считать, что http://user:password@example.org/ и http://example.org/user/password/ сильно различаются. Ничего подобного. Единственное различие между ними, что если набрать второй адрес руками, то он останется в истории браузера. Для AJAX'а более пригоден второй путь — «logout» делать сильно проще.

Необходимое замечание: речь, конечно же, идёт о basic-авторизации. Digest мало кто пробует (а три года назад оно сильно ещё глючило, наверное, сейчас получше должно быть), NTLM по-чёрному глючит в «Опере» (в чём я убедился, работая в «Яндексе»).

Итак http://example.org/jfdhfjhrtjktjkfhdjht/ это вполне себе парольный доступ.
20 комментариев
13 апреля 2009 15:08

Госпожа Бовари смотрела много голливудских фильмов

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

Я тут на днях начал читать великолепную (по моим ощущениям) «Госпожу Бовари» Гюстава Флобера, там Бовари чувствует себя потерянной в жизни из-за того, что жизнь не оправдала её ожиданий. Своё ощущение того «как должно быть» она почерпнула из романов:

Там было все про любовь, там были одни только любовники, любовницы, преследуемые дамы, падающие без чувств в уединенных беседках, кучера, которых убивают на каждой станции, кони, которых загоняют на каждой странице, дремучие леса, сердечные тревоги, клятвы, рыдания, слезы и поцелуи, челны, озаренные лунным светом, соловьиное пение в рощах, герои, храбрые, как львы, кроткие, как агнцы, добродетельные донельзя, всегда безукоризненно одетые, слезоточивые, как урны.
Так вот: не Голливуд виноват. Это всегда было. И Донцову не надо обвинять. В конце концов, не она же эти книги пишет, да и покупает у себя их не она.
8 комментариев
13 апреля 2009 12:57

Opera и document.all

«Опера» в одно время пыталась притворяться Internet Explorer'ом — копировала его user-agent, эмулировала его свойства и так далее. В частности, в «Опере» есть document.all, как часть поддержки так называемых «коллекций», которые были разработаны и использовались в стародавние времена. Один из популярнейших методов определить «а не IE ли это» заключался в проверке существования document.all, иногда — исключения «Оперы»:
var isIE = document.all && self.opera
Впрочем, на Западе «Опера» не популярна, поэтому «Оперу» не исключают и считают её разновидностью IE.

Так вот, в последние годы «Опера» пытается открестится от своего «иешного» прошлого, например, где-то по дороге с 8-й версии в 9-ю user-agent перестал притворяться Internet Explorer'ом. А вот в 9-й версии (в 10-ке это тоже так) изменения начались, на мой взгляд, какие-то довольно печальные: ломают логику языка JavaScript.

В новых «Операх» конструкция alert(document.all ? 1 : 0) выдаст «0», тогда как alert(document.all) — «[object HTMLCollection]». Сделано понятно для чего: обратная совместимость не ломается, но проверка «не IE ли» теперь уже выдаёт false.
11 комментариев
10 апреля 2009 15:48

libmapi: насколько всё запущено

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

Однако к MAPI это отношения не имеет
Цитата из книги «Основы MAPI» Ирвинг де ла Круз, Лес Талер, вырванная из контекста.
5 комментариев
9 апреля 2009 19:44

Python 2.4 не освобождает память

Как я уже не раз говорил, libmapi нещадно течёт. Я сейчас работаю с версией из транка, 921-й комит, это довольно старая версия (текущий коммит — 1303), но утечки находят до сих пор и впереди их немало. Память течёт быстро и при получении больших объёмов данных утекает раньше, чем данные удаётся получить.

Поэтому я изолирую libmapi в отдельном процессе, получаю данные, пока могу и отдаю их «наверх» — родителю, потом делаю новый процесс и получаю следующую пачку. Для того, чтобы отдать данные родителю я использую os.pipe, а данные туда можно передавать только строкой. Так как данные у меня сложные, я их сериализую при помощи cPickle, а для сериализации нужна память.

Где взять память, если всё, что было доступно процессу, съела libmapi? Я пытался выделать память при помощи list(range(20 * 1024 * 1024)), а перед сериализацией удалять, но это не работало. Сегодня я узнал почему. Оказывается Python до версии 2.5 никогда не освобождает память. У меня как раз Python 2.4, приехали.

P.S. Чтобы предотвратить вопросы для чего я делаю list(range(…)), расскажу сразу: для совместимости с Python 3.0, на который мы все когда-нибудь перейдём. Там range возвращает итератор.

Добавлено позднее.

Я сейчас немного поисследовал, сделал замеры и выяснил, что если обращаться к аллокатору памяти Python напрямую (например, через ctypes), то память возвращается:
from ctypes import *

mem = pythonapi.PyMem_Malloc(c_size_t(100*1024*1024))

pythonapi.PyMem_Free(mem)
Комментировать
9 апреля 2009 14:02

В домашнем интранете кто-то неправ!

Моя жена обживает интернет просто семимильными шагами. Не в том смысле, что она его раньше не видела, а в том смысле, что в понимании сетевой культуры, которая её раньше не интересовала, она сильно продвинулась и уже начала переносить её понимание в реальную жизнь. В доказательство, диалог, который произошёл только что:

— Марин, я уже кушать хочу!
— Солнце,… я кушать хочу больше тебя, (с угрозой) ты хочешь со мной об этом поспорить?
26 комментариев
8 апреля 2009 21:39

Часть правды о бытовой химии

Цитирую целиком, ибо мне это кажется достаточно важным:

1. Шампунь по составу мало чем отличается от геля для душа, поэтому они легко заменимы.

2. Страна производитель – важный показатель качества. Fructis российского производства и французского – разные шампуни. Для развивающихся стран используются более дешевые ингредиенты в меньших количествах (все остальное – вода), производства EU находится под более строгим контролем (меньше риск, что в бадью с вашей любимой помадой упадет бидон с казеиновым клеем, что случается), в Европе строже стандарты качества. Другими словами, для EU делают более дорогой и густой шампунь, чем для российского рынка. Поэтому покупайте то, что сделано в Европе для европейской компании.

3. Читайте этикетки. Состав продукта перечисляется по убыванию массы ингредиентов. Например, если написано: «Состав: вода, сода, соль… какие-то непонятные слова….масло виноградных косточек точка», это значит, что на 99% ваш шампунь состоит из воды. Масло виноградных косточек туда тоже попало, но в виде трех капель на мегатонную бочку. Если описание состава вашего любимого крема для рук начинается со слов «вазелин, парафин», то выбросьте его в форточку и купите банку вазелина. Скорее всего, кроме этих двух ингредиентов и пары отдушек, закодированных в латинские названия, там ничего нет. Да, кстати, как это ни прискорбно, бомбочки для ванн LUSH на 99,9% состоят из соды, поэтому их себестоимость – порядка 30 центов (при цене 300 рублей). Там есть еще пару капель эфирных масел и отдушки, но проще сделать такие бомбочки самим.

4. Уважаемые родители, стиральные порошки «Аистенок» и «Ушастый нянь» сделаны в России (читайте второй пункт). «Ушастый нянь» сделан на фабрике «Невская косметика», что, вообще-то, уже лет 30 как не внушает доверия, «Аист» сделан на неизвестном российском производстве. По составу эти порошки ничем не отличаются от «взрослых порошков» - это все простой маркетинг. Покупайте для своих детей жидкие концентраты, сделанные в Европе.

5. Любой стиральный порошок на 80% состоит из балласта, чтобы радовать покупателя большой коробкой. И, кстати, вот эти синенькие и красненькие точечки в стиральном порошке – тоже балласт, а вовсе не какие-то мифические активные вещества. Покупайте жидкие концентраты – это экономичнее, они не так вредны для природы как порошки, которые попадают в водоемы и рушат экосистему.

6. Ополаскиватели для цветного и белого белья по химическому составу идентичны. Различаются только этикетками.

7. Самый большой обман в том, что стиральные машинки ломаются от накипи и поэтому надо покупать Calgon. Не верьте! Машинки от этого не ломаются, а стиральный порошок Calgon ничем не отличается от других.

8. Грустная новость для российских защитников животных: если на товаре написано, что он не тестировался на животных, это не значит, что в России не пострадал ни один кролик. Дело в том, что для выхода на российский рынок любой косметический продукт должен пройти миллионы СанПинов, которые были придуманы в 70-80х гг. в СССР, в том числе, пробы на животных. Их никто не отменял даже для Green Mama и Body Shop. Другое дело, что компания может не проводить эти тесты самостоятельно, а отдать свою тушь российскому подрядчику, который и будет закапывать эту тушь в глаза кролику, пока его сетчатка не покраснеет.
Девушка, парень которой долгое время работал на косметические компании и компании, выпускающие бытовую химию, делится откровениями. Про «Калгон», кстати, подтверждаю, я сам как-то проводил нехеровое исследование на эту тему.
36 комментариев
8 апреля 2009 18:49