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

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

Далеко, далеко, на лугу пасутся ве…

Сегодня на рейсе из Бангкока, слушая истеричную стюардессу, которая объясняла, что не может сказать в какой касалетке какое мясо, посольку она мяса не ест и в нём не разбирается, я всё думал, что из всех клубов по интересам, вегетарианство один из самых странных…

В этой связи у меня вопрос, может кто знает ответ. Предположим, случилось странное — все люди на Земле вдруг стали вегетарианцами. Что вегетарианцы предлагают сделать с коровами, козами и т.п.? Убить сразу? Выпустить «на волю» (т.е. убить позднее)? Создать, ну не знаю, какие-то заповедники? Кастрировать и дать дожить до старости? Или что?
9 комментариев
14 мая 2012 20:47

Нас обманули, расходимся

Как и следовало ожидать, Майя не предсказывали никакой конец света в этом году:
Календарь находился на северной стене, рядом с изображением монарха. Из этого календаря можно было узнать о лунных затмениях, а также соединениях Луны, Марса и Венеры, которые произойдут в ближайшие несколько тысяч лет. Вычисления продолжалась и на восточной стене дома. Там изображены четыре колонки цифр — это расчеты фаз Луны и солнечный календарь. «Когда мы с моими студентами изучили эти колонки, мы обнаружили, что это календарь на два с половиной миллиона дней — то есть на семь тысячелетий вперед!» — говорит Уильям Сатурно.

Стоит отметить, что никакого упоминания 23 декабря 2012 года — даты, когда произойдет завершение одного из больших циклов календаря майя и которую многие ошибочно принимают за предсказание конца света, — в таблицах нет.
4 комментария
12 мая 2012 17:08

Привет из Таиланда!

WTF (66.54КБ) Я пропал и не пишу в блог, потому что отдыхаю с женой в Таиланде, в Паттайе. Бесплатный интернет есть только в лобби отеля, а в номерах час стоит почти 200 рублей. Меня жаба душит.

На снимке — такая реклама висит сейчас в Паттайе. Рекламируется какой-то сайт, кажется.

Всё просто замечательно, природа (у нас отель в зелени утопает, рядом море), еда, куча фруктов (мы ездим в магазин время от времени, закупаем их кучей, стоит всё копейки, например, рамбутан стоит 19 (!) рублей за килограмм!). Кстати, теперь-то мы видели пять морей! Получается: Чёрное, Красное, Средиземное, Балтийское и, вот, Южно-Китайское.

Кстати, недавно видел в отеле актёра, который играл Хиро Накамура из сериала «Герои».
15 комментариев
8 мая 2012 07:41

Размер имеет значение

Такая ещё вещь в ПХП вызывает мою искреннюю печаль. В руководстве написано, что при приведении переменной к булевскому типу, строка «"0"» трактуется как false:
var_dump( (bool) "0"); // false
var_dump( (bool) "00"); // true
Сделано это по определённым причинам. ПХП, исторически, был языком не просто для чайников, а для фанерных чайников, когда снаружи приходят параметры в GET или POST запросе, ПХП их раскладывает в специальные переменные, но все данные имеют тип «строка» (иногда — массив строк).

Дальше, и тут есть своя логика, если снаружи приходит ноль, ПХП решает (типизации-то данных запросов нет), что программист в своей ХТМЛ-форме имел ввиду число ноль и ведёт себя соответствующе. Благодаря этому «if ($variable_from_get) {}» ведёт себя «правильнее».

Поэтому я называю ПХП языком не с «динамическим приведением типов», а с «нестабильным приведением типов». Потому что его правила приведения содержат исключения.

Такой «строковый ноль» может привести к сюрпризам:
var_dump(array_filter( [ 0, null, false, "00", "0" ])); // останется один элемент — "00"
var_dump(in_array("0", [ false ])); // true
Или вот, например, поведение конструкции «empty» с той же строкой (именно из документации по этой конструкции я узнал о существовании такого нуля, ещё в ПХП3):
$z = "0"; $zz = "00";
var_dump(empty($z)); // true
var_dump(empty($zz)); // false
При этом, один пробел и всё, ноль перестаёт быть «магическим»:
var_dump(in_array(" 0", [ false ])); // false
6 комментариев
6 мая 2012 09:01

☁ == ☀

Как знают программисты на ПХП, у этого языка есть одна неприятная особенность: при сравнении с приведением типов („==“) ПХП всё, что по его мнению похоже на число, преобразует в число:
If you compare a number with a string or the comparison involves numerical strings, then each string is converted to a number and the comparison performed numerically.
Причём, «похоже на число» — это не обязательно нечто десятичное:
var_dump("0x01" == "1"); // true
// но при этом
var_dump("0b01" == "1"); // false
var_dump("014" == "12") // false
Эта проблема косвенно проявляется при поиске в массиве. Казалось бы, строкового значения «1.5» в массиве нет:
var_dump(in_array("1.5", ["01.5000"])); // true
// правда есть специальный флаг для строгого стравнения, о котором почему-то мало кто знает:
var_dump(in_array("1.5", ["01.5000"], true)); // false
Но настоящая проблема вот в чём. ПХП, конечно, смотрит, похожа ли строка на то, что он считает числом, но никак не проверяет сможет ли он «съесть то, что укусил»:
var_dump("10000000000000000000000000000000" == "10000000000000000099999999999999"); // true
Сюрприз?

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

В итоге при конвертации происходит потеря точности, левая и правая часть конвертируются в 1e31 (единица с с 31 нулём), которые равны между собой. Это может произойти, например, тогда, когда мы сравниваем «двумя равно» пару хешей, которые содержат только цифры.

Вывод: используете всегда только строгое равенство („===“) и вызовы функций сравнения с флагами, отключающими приведение типов, если только вы чётко не понимаете когда это правило можно нарушить. Но.

Есть конструкция, которой мы управлять не можем:
switch ("1.5") {
    case "0001.500": echo "пичалька"; // ещё какая!
}
Конструкция «switch» всегда использует нестрогое сравнение, об этом нужно помнить.
3 комментария
5 мая 2012 21:58

Гугл Нексус Уан в поле не уоин

Google Nexus Many (35.56KB)Google Nexus Many (48.50KB)Google Nexus Many (45.72KB)
Моему смартфону почти 2,5 года. Внезапно начал дохнуть аккумулятор. Вообще, время работы смартфонов на «Андроиде» — беда, тщательно высмеиваемая владельцами «Айфонов» и «Винмобайлов». А теперь штатный аккумулятор и вовсе держит заряд всего полдня.

Многие ломаются и покупают «Айфон», слабаааки!

Штатный аккумулятор первого «Нексуса» обладает ёмкостью 1400 мА·ч. Я купил (спасибо, Китай!) аккумулятор на 3000 мА·ч. Уже половину дня пытаюсь его разрядить, гоняя «Амели» на полной подстветке, со включенным вай-фаем, 3Г и блюзом. Хоть бы хны!

Смартфон стал вдвое толще и вчетверо — уродливее, но я трудностей не боюсь!
9 комментариев
4 мая 2012 20:52

Супербасков

Басков (137.63КБ) Николай Басков в комиксе. На обложке — Халк, Железный человек, другие супергерои, внутри — Басков.
2 комментария
3 мая 2012 16:49

Спасибо социальным сетям!

Спасибо социальным сетям за то, что они так популярны, ну нет правда.

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

Пока это самое эффективное, даже Национальный Архив РТ сказал, что метрических книг по деревне Новое Исаково, откуда часть моих родственников, у них нет.

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

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

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

В архивах двоюродной бабушки, у которой я был в гостях на праздниках, нашлась фотография — две девочки в школьной форме, на обороте надпись (sic) «на память тёти Маши от Лиди и Тани первый раз в первый клас 1 сентября 1974 года Литвиновы сёстры близнецы». «Тётя Маша», Мария Степановна, упомянутая моя бабушка, помнила степень родства, но не знала адреса или других контактов.

Эти две девочки присутствовали и на другой фотографии, семейной, которая, судя по надписи на обороте, сделана была в Горьком (сейчас — Нижний Новгород).

У меня были: город, два имени, девичья фамилия и год поступления в школу (1974), последнее даёт год рождения — примерно 1966. У одной из девочек были очень необычные глаза, я решил её и поискать, предполагая, что узнаю эти глаза на любых фото.

Во «Вконтакте» я вбил в поиск эти данные и получил несколько претенденток, но только у одной было написано, что она поступила в школу в 1974. Вместо фотографии была абстрактная картинка, зато были проставлены дата рождения и фамилия по мужу. Поиск в «Одноклассниках» по уточнённым данным дал ту же анкету, в которой было уже два фото — уже знакомая мне абстрактная картинка и современная фотография, где в этой женщине уже сложно было бы узнать ту девочку с фото, если бы не глаза…

Написал ей сообщение в обе анкеты, сегодня получил от неё ответ. Я не ошибся, это моя родственница.

Это уже третий случай удачного поиска через социальные сети. В первые разы находились родственницы из Майкопа (республика Адыгея) и из Самары. К первым я уже съездил, летом собираюсь ко вторым.
8 комментариев
2 мая 2012 21:56

Стрелкова Евдокия Никаноровна

Прабабушка с бабушками (83.15КБ) Сегодня утром вернулись из Лениногорска, были с женой и младшим братом в гостях у родителей, навестили ещё и двоюродную бабушку, сестру моей бабушки со стороны мамы.

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

Я осторожно удалил канцелярским ножом хлебный клейстер с обратной стороны (тогда фотографии в альбом часто им приклеивали) и разобрал часть текста. На снимке она с двумя дочерями — средней дочерью Александрой (на снимке ей 15) и младшей Марией (на снимке ей 8 лет, как раз у неё в гостях я и побывал), а прабабушке на нём 40 лет.

Я её помню совсем старенькой, когда я родился ей уже было 74 года. Она родилась ещё при царе, в 1903 году, так и осталась неграмотной, но обладала потрясающей памятью и хорошим зрением, всё время была в движении, наверное благодаря этому дожила почти до 97 лет (без четырёх месяцев).

Помню меня всё удивляло, что у неё не было ни одного зуба, ещё что она совсем не помнит как жили при царе, а сейчас, после 13 прошедших с её смерти лет, у меня самого воспоминания уже не такие яркие, приходится напрягаться, чтобы вспоминать некоторые вещи.
Комментировать
1 мая 2012 23:55

Как в JS узнать что объект — массив?

Узнал на семинаре Кантора такую штуку. Как узнать, что объект, который пришёл на вход — массив? Конечно, лучше использовать утиную типизацию, но если нам нужен именно массив, со всей полнотой методов, не проверять же каждый?

Кстати, если кто-то думает, что ответ «typeof», то он просто не знает JS. Эта конструкция вернёт «object».

Я до недавнего времени думал, что правильный способ такой:
console.log([] instanceof Array); // true
А редко его используют, потому что конструкция «instanceof» не везде реализована. Я заблуждался. Вот правильный способ:
console.log(Object.prototype.toString.call([]) == '[object Array]'); // true
И вот почему. Оказывается, у каждого фрейма своя иерархия типов, если один фрейм передаёт во второй какой-то объект, то «instanceof» даст «false», так как сравнивает c «Array», локальным для этого фрейма. Проблему иллюстрирует следующий пример:
<script>
function Up(arr, iframeWindow) {
    alert(arr instanceof Array); // false
    alert(arr instanceof iframeWindow.Array); // true

    alert(Object.prototype.toString.call([]) == '[object Array]'); // true
}
</script>
<iframe src="data:text/html, <script>parent.Up([], window)</script>"></iframe>
12 комментариев
28 апреля 2012 19:14

Логичность шаблона «объявили и вызвали» в JS

Вчера в комменариях возникло обсуждение семантики синтаксиса «!function () {}()». Мне так кажется, что семантика здесь побоку, использовать функцию для создания зоны видимости — уже костыль (в JS 1.7 есть конструкция «let» для этого), но мне тут подумалось, что ведь можно сделать эту конструкцию семантичной, если использовать забытую конструкцию «with»:
with (function () {
    // тело функции
}) call();
На мой взгляд, весьма и весьма семантично. Что скажете?
5 комментариев
26 апреля 2012 09:19

Декларация-вызов в JS

Сегодня на первой части семинара Ильи Кантора по JS присутствовал (к сожалению, на второй части не получится, буду в Москве это время). Немного поговорили о частом паттерне «объявили функцию и тут же вызвали». Используется этот приём (если кто не знаком с ДжаваСкриптом) для изоляции — в этом языке функции единственное, что может создавать зоны видимости.

Я вскользь затронул свой любимый способ — описание функции и вызов через восклицательный знак или тильду, вместо оборачивания скобками. Вообще, в JS непосредственный вызов функции сразу по месту определения возможен, только если декларация находится в контексте выражения. Для этого и нужны традиционные скобки:
(function () {
    // скобки вокруг функции говорят интерпретатору, что это выражение
})();
Вообще говоря, можно использовать любые средства, чтобы декларация стала частью выражения. Например, можно что-то прибавить к декларации. Или использовать любую унарную операцию.

Использование тильды или восклицательного знака гораздо лучше скобок по трём причинам:
!function () {
    // 
}();
Во-первых, на один байт меньше. Если таких функций много, экономия существенная. Во-вторых, скобки надо балансировать, а унарный оператор — нет.

И, в-третьих, самая главная причина. Вот такой код вызовет ошибку:
var a = 5
(function() {})()
Причём ошибку, которую найти иногда довольно трудно, да и сообщение о ней не самое дружественное: «TypeError: 5 is not a function». На самом деле, тут пропущена точка с запятой. Интерпретатор считает, что ему встретились две части выражения, между которыми пропущен какой-то знак. Эта ситуация часто встречается при автоматическом объединении двух скриптов в один.

Обычно для этого добавляют точку с запятой сразу перед такими блоками.

Но если использовать унарный оператор, то этой проблемы просто нет (поэтому, на самом деле, мы экономим два байта, ещё и точка с запятой не обязательна):
var a = 5
!function () {}()
Тут интерпретатор, встретив унарный оператор, понимает, что предыдущее выражение закончилось и началась новая конструкция.
33 комментария
23 апреля 2012 22:16

葉片風扇沒有

Вентилятор (32.72КБ) Помните в интернете все с ума сходили по безлопастному вентилятору VES VD 501? Китайцы не дремлют!

610 рублей всего. Вот напись с ценника:
Фантастическая технология и дизайн, не имеющая аналогов! Вентилятор не покрывается пылью! Воздух подаётся охлаждённым! Устройство нетравматично! Вентилятор можно установить напротив себя, при этом будем видно собеседника! Сборка занимает всего полминуты!
Опечатки с ценника я заботливо перенёс. Я себе живо представляю двух китайцев, разговаривающих сквозь этот небольшой (он с ладонь размером) вентилятор и изумляющихся: «посмотри Ляо Дзянь, я тебя вижу, не то что через этот старый лопастной вентилятор!».
2 комментария
23 апреля 2012 22:03

Ещё недостаток «Гоу»

В отличие от многих языков, в «Гоу» символ решётки не позволяет комментировать строку. В упомянутых языках это сделано не зря. В различных ЮНИКС-подобных системах, если запускаемый файл начинается с последовательности «#!», то считается, что дальше идёт путь до интерпретатора, который умеет обрабатывать запускаемый файл. Таким образом работают, например, все шелл-скрипты.

Сам же язык, встретив первой строкой «#!/bin/какой-то путь» просто посчитает это комментарием. Так поступает Пайтон, ПХП, Перл и ещё целая куча языков. Это удобно.

В «Гоу» такого нет. Несмотря, что в первой версии появилась команда «go run», позволяющая запускать программы из командной строки, не компилируя их (на самом деле компилируя, но результат не сохраняется), я не могу указать в первой строке «#!/usr/local/bin/go run», «Гоу» меня отругает:
bolk@dhcp-174 ~ $ ./main.go 
package : 
main.go:1:1: illegal character U+0023 '#'
Прискорбно.
6 комментариев
23 апреля 2012 11:19

Национальный музей РТ

Нацмузей РТ (59.07КБ) Невидимый поросёнок Пётр, хипстерская «Лейка», Родина-әни и карманный фонограф как бы говорят вам, что мы с женой посетили Национальный музей Республики Татарстан и впредь собираемся ходить в музеи в Казани чаще, чем никогда.

Остальные фото (без аннотаций правда) на «Яндекс.Фотках».
Комментировать
22 апреля 2012 18:47