0,(9) апреля
Каждый год, первого апреля, увеличивается количество мусора. Потом десятилетиями в интернете болтаются статьи, выпущенные в этот день, но читатели уже не обращают внимание на дату. Так становится больше слухов, искажений, непроверенных фактов и просто вранья, которое рождалось как шутка.
Особенно грустно, когда этим занимаются новостные издания, которым остальные 360 с гаком дней в году читатель привыкает верить.
Просто замечательно, когда авторы проекта продумывают шутку так, чтобы встретив её в любой другой день в году, посетитель догадаться бы, что это шутка, например, «Яндекс.Карты» сделали панораму Марианской впадины, это здорово (в специальном посте на «Хабре» собираются шутки со всего интернета).
Но моё сердце отдано картам «Гугла», эти ребята сделали карты в стиле старых «восьмибитных» игр, волшебно.

Ну а я первого апреля традиционно серьёзен, как стадо бизонов.
ДОСбокс и «Гопник»
Вспомнил, что есть такая штука как DOSBox («ДОСбокс»), позволяет запускать

Чтобы её поставить под «Мак», сначала надо установить «хоумбрю» (если у вас его ещё нет), потом в консоли последовательно набрать:
brew tap homebrew/games
brew install dosbox
# долго скачиваются разные штуки, ставятся библиотеки
sed -ie 's/keyboardlayout=auto/keyboardlayout=RU/' "$(dosbox -printconf)"
# заменяем кодировку на русскую, иначе будут проблемы со шрифтами
dosbox
# запускаем ДОСБокс, там пишем:
mount c /каталог на диске где у вас игры
# переходим на диск C:
C:
# запускаем игру
gopnik.exeГотово, теперь у вас в окне искомая игра.
strrev для UTF-8
В ходе обсуждения одной книге на «Хабре» придумал как развернуть строку
Вот что я придумал: перевожу в двухбайтную кодировку
$test = 'А роза упала на лапу Азора ウィキ';
$test = iconv('utf-8', 'utf-16le', $test);
$test = strrev($test);
// キィウ арозА упал ан алапу азор А
echo iconv('utf-16be', 'utf-8', $test);Казань ✈ Москва ✈ Бангкок → Паттайя → Бангкок ✈ Москва ✈ Казань
Ура, удалось вырваться в короткий отпуск (загруженность высокая, поэтому и пишу «вырваться»). С 7 по 15 мая будем в Паттайе (Таиланд) в отеле «Шератон» 5★. Это относительно новый отель с собственными пляжем, номер будет с видом на море.

Снимок взят с сайта отеля.
Переход на «Гоу 1»
С выходом первой версии языка программирования «Гоу» посмотрел как компилируются мои программы. Не компилируются никак. Весь набор утилит поменяли, теперь всё делается через утилиту «go». С одной стороны хорошо — раньше, чтобы просто запутсить код нужно было много танцев проделать, а сейчас «go run code.go», и всё, он работает.
С другой стороны, мне все make-файлы придётся переписать, надо ещё разобраться как всё теперь работает, но самое плохое вот что:
Finally, the Go tool chain (compilers, linkers, build tools, and so on) are under active development and may change behavior. This means, for instance, that scripts that depend on the location and properties of the tools may be broken by a point release.
Для тех, кто не понимает английский — набор утилит «Гоу» находится в стадии разработки и ещё может измениться. Это плохо очень. Я не хотел бы с выходом каждой новой версии смотреть не сломалось ли у меня
Работа с камерой и распознавание чисел в «Опере»

Я вчера заморочился на отличненько. Мне показалось скучным и грустным вводить цифры счёта за квартиру в окошко «Госуслуг» и решил сделать автоматическую распознавалку чисел, попутно изучив работу с камерой из браузера.
Доступ к камере — эксперментальный стандарт, поэтому мало кто из браузеров может им похвастаться, я использовал специальный билд «
АПИ оказалось несложным. Всё, что нужно сделать — соединить специальным образом тег VIDEO с источником стримового видео; потом я 10 раз в секунд забираю кадр с видео и кладу в CANVAS (на скриншоте он цветной), оттуда вырезаю небольшую область, перевожу в градации серого, беру за порог 75% от усреднённого цвета и перевожу всё в ч/б.
Больше всего из трёх часов, которые у меня ушли на это, я делал распознование цифр. Алгоритмы, которые я нашёл в интернете, были очень монструозными, да и переписывать готовое было скучно, поэтом я перепробовал несколько вариантов, которые пришли мне в голову.
В итоге, лучше всех распознаёт следующий алгоритм.
Сначала я очевидным образом разбиваю изображение на цифры, потом условно разделяю каждую цифру вертикальной линией по середине. Слева и справа от линий считаю количество переходов между чёрным и белым, двигаясь сверху вниз. Получаются комбинации из пар чисел. Я их прореживаю — одинаковые последовательно идущие заменяю на одно значение.
Получаются цепочки, которые уже достаточно хорошо характеризуют цифру, правда некоторые цифры этот паттерн не в состоянии распознать. Поэтому я считаю количетсво ч/б переходов ещё и по моей умозрительной вертикальной линии.
На скриншоте в большом текстовом поле записаны получившиеся комбинации. Первое — номер по порядку, далее (через двоеточие) — количество переходов по вертикали и потом описанная последовательность. Например, «ноль» записывается как «2:11» (два перехода по вертикали, потом одинаковые переходы по разу слева и справа разделительной линии).
Алгоритм «шумит»,
Казань → Лениногорск → Казань
С 29 апреля по первое мая будем с женой в Лениногорске, в гостях у моих родителей.
Криптография для чайников
Очень хорошее видео (но на английском языке) о том как работает обмен ключами в том же самом HTTPS.
ФлешБэк
Все уже знают о существовании ботнета из полумиллиона «Маков»?
Проверить не заражён ли ваш «Мак» можно на специальном сайте. Я написал небольшой скрипт, который надо запускать из консоли, если лень шариться по менюшкам в поисках UUID вашей машины:
#!/bin/bash
UUID=$(/usr/sbin/system_profiler SPHardwareDataType | /usr/bin/awk '/UUID/ {print $3}')
result=$(/usr/bin/curl "http://flashbackcheck.com/check/?uuid=$UUID" 2>&-)
echo -n "Your system status is "
case "$result" in
"") echo NA.;;
clean) echo -e "\033[1;32mclean.\033[0m";;
*) echo -e "\033[1;31minfected.\033[0m";;
esacЛибо можно сразу скачать его на запуск с «Гитхаба»:
curl -s https://raw.github.com/bolknote/shellgames/master/checkflashback.sh | /bin/bashУ меня компьютер чистый.
Угадай закон
Минздравсоцразвития собирается внести законопроект о защите здоровья населения от табачного дыма, сообщается на Вести.ru… С 2014 года предлагается ввести запрет курения на рабочих местах в помещении, в общественном транспорте.
Пишет портал «ПроГород» и куча других изданий. Ммм? Что? Ещё 10 июля 2001 года был принят «Об ограничении курения табака»
Запрещается курение табака на рабочих местах, в городском и пригородном транспорте… за исключением курения табака в специально отведенных местах для курения табака
Из той же статьи:
— Мы надеемся, что Минздрав запретит еще и курение в подъездах, — сказал Дмитрий Янин, председатель правления Международной конфедерации обществ потребителей. — Пока закон не защищает нас от курящих соседей,
из-за которых всем остальным приходится дышать дымом.
Как же не защищает? Курение в подъезде является нарушением п. 9.1 СанПин
Nuzhno vvesti bukvy

Регистрация на сайте
UserJS для воспроизведения H.264 в «Опере»
Существует плагин «DivX web player», который отлично подменяет тег «VIDEO», в случае, если должен быть использован кодек H.264, но браузер его не поддерживает.
К сожалению, в «Опере» он
Самая засада — это тег «VIDEO» без размеров. Мне для поддержки этого приходтся запускать проигрывание и когда становятся доступны медиаданные, останавливать воспроизведение и переписывать размеры видео.
// ==UserScript==
// @name XVid patch
// @author Evgeny Stepanischev aka Bolk
// @version 1.00
// @namespace /files/opera-xvid-patch.js
// @modified 2012-04-14
// @include http://*
// ==/UserScript==
!function () {
var htmlif = function (attr, attrname) {
return attr ? attrname + '="' + attr + '" ' : '';
}
var patchtag = function (o, src) {
var html = '<embed type="video/divx" '+
'custommode="none" ';
if (o.preload == 'auto') html += 'bufferingMode="full" '; else
if (o.preload == 'none') html += 'bufferingMode="null" ';
html += htmlif(o.poster, 'previewImage')+
htmlif(o.id, 'id')+
htmlif(o.name, 'name')+
htmlif(src || o.src, 'src')+
htmlif(o.controls ? 'full' : 'null', 'mode')+
htmlif(o.width, 'width')+
htmlif(o.height, 'height');
if (!o.height || !o.width) {
html += 'onloadedmetadata="this.width=this.videoWidth;this.height=this.videoHeight" ';
html += htmlif(!o.autoplay && 'if (!this._sized) {this.pause(); this.currentTime=0; this._sized=1}', 'onplay');
html += 'autoPlay=true ';
} else {
html += htmlif(o.autoplay ? 'true' : 'false', 'autoPlay');
}
html += 'pluginspage="http://go.divx.com/plugin/download/"></embed>';
o.outerHTML = html;
};
var patch = function () {
window.opera.addEventListener('BeforeScript', function() {
with (window.HTMLVideoElement)
if (prototype._canPlayType === undefined) {
prototype._canPlayType = prototype.canPlayType;
prototype.canPlayType = function (type) {
if (type.substr(0, 9) == 'video/mp4') {
return 'probably';
}
return this._canPlayType(type);
}
}
!function() {
var videos = document.getElementsByTagName('VIDEO');
for (var i = 0, vl = videos.length; i<vl; i++) {
if (!videos[i]) continue;
if (videos[i].type && videos[i].type.substr(0, 9) == 'video/mp4') {
} else {
var sources = videos[i].getElementsByTagName('source');
var foundSupported = false, foundMP4 = false;
for (var j = 0, sl = sources.length; j < sl; j++) {
if (videos[i]._canPlayType(sources[j].type) !== '') {
foundSupported = true;
break;
}
if (sources[j].type.substr(0, 9) == 'video/mp4') {
foundMP4 = sources[j].src;
}
}
if (!foundSupported && foundMP4) {
patchtag(videos[i], foundMP4);
}
}
}
}();
});
};
for (var i = 0, l = navigator.plugins.length; i < l; i++) {
if (navigator.plugins[i].filename == 'DivXBrowserPlugin.plugin') {
return patch();
}
}
}();Добавлено: в комментариях справдливо указали на недостаток — перехватывать надо не только BeforeScript. Исправлять не буду до первого реального случая, когда
Чем плох ПХП
На «Хабре» появился перевод статьи «PHP: фрактал плохого дизайна». Отличная статья, расставляющая все точки над «ё» в этом вопросе. Кстати, вот штука, которую я не знал:
bolk@Bolk ~ $ php <<PHP
> <?
> function __lambda_func() {
> };
>
> create_function('', 'return;');
> PHP
Fatal error: Cannot redeclare __lambda_func() (previously declared in -:3) in -(5) : runtime-created function on line 1ПХП, при использовании функции create_function сначала создаёт функцию __lambda_func (чтобы потом её переименовать), а если она уже
Стоит ли покупать третий «Айпад»
Я покупать не буду, не вижу никакой причины для этого, но если вы раздумываете надо или нет, то принять решение поможет очень хорошая статья на «Айфонс»: «Три недели с третьим iPad. Впечатления от использования», это лучший обзор чего угодно, который я вообще
Пару слов о Джаве
У ДиБРа увидел прекрасное. Как вы думаете, что выведет следующий код:
public class Main {
public static void main(String[] args) {
Integer a = 10, b = 10;
Integer c = 150, d = 150;
System.out.println(a == b);
System.out.println(c == d);
}
}Как ни странно, но «true» и «false». Насколько я понял по комментариям, это происходит
Вот что я люблю¹

Мне кажется это очень плохой слоган, раз он требует пояснения. Мне кажется это очень плохое пояснение, потому что оно ничего не поясняет. «Хочется съесть самому» это и есть «жалко».
Национальный музей РТ

Невидимый поросёнок Пётр, хипстерская «Лейка»,
Остальные фото (без аннотаций правда) на «Яндекс.Фотках».
Ещё недостаток «Гоу»
В отличие от многих языков, в «Гоу» символ решётки не позволяет комментировать строку. В упомянутых языках это сделано не зря. В различных
Сам же язык, встретив первой строкой
В «Гоу» такого нет. Несмотря, что в первой версии появилась команда «go run», позволяющая запускать программы из командной строки, не компилируя их (на самом деле компилируя, но результат не сохраняется), я не могу указать в первой строке «#!/usr/local/bin/go run», «Гоу» меня отругает:
bolk@dhcp-174 ~ $ ./main.go
package :
main.go:1:1: illegal character U+0023 '#'Прискорбно.
葉片風扇沒有

Помните в интернете все с ума сходили по безлопастному вентилятору VES VD 501? Китайцы не дремлют!
610 рублей всего. Вот напись с ценника:
Фантастическая технология и дизайн, не имеющая аналогов! Вентилятор не покрывается пылью! Воздух подаётся охлаждённым! Устройство нетравматично! Вентилятор можно установить напротив себя, при этом будем видно собеседника! Сборка занимает всего полминуты!
Опечатки с ценника я заботливо перенёс. Я себе живо представляю двух китайцев, разговаривающих сквозь этот небольшой (он с ладонь размером) вентилятор и изумляющихся: «посмотри Ляо Дзянь, я тебя вижу, не то что через этот старый лопастной вентилятор!».
Декларация-вызов в JS
Сегодня на первой части семинара Ильи Кантора по JS присутствовал (к сожалению, на второй части не получится, буду в Москве это время). Немного поговорили о частом паттерне «объявили функцию и тут же вызвали». Используется этот приём (если кто не знаком с ДжаваСкриптом) для изоляции — в этом языке функции единственное, что может создавать зоны видимости.
Я вскользь затронул свой любимый способ — описание функции и вызов через восклицательный знак или тильду, вместо оборачивания скобками. Вообще, в JS непосредственный вызов функции сразу по месту определения возможен, только если декларация находится в контексте выражения. Для этого и нужны традиционные скобки:
(function () {
// скобки вокруг функции говорят интерпретатору, что это выражение
})();Вообще говоря, можно использовать любые средства, чтобы декларация стала частью выражения. Например, можно
Использование тильды или восклицательного знака гораздо лучше скобок по трём причинам:
!function () {
//
}();И,
var a = 5
(function() {})()Причём ошибку, которую найти иногда довольно трудно, да и сообщение о ней не самое дружественное: «TypeError: 5 is not a function». На самом деле, тут пропущена точка с запятой. Интерпретатор считает, что ему встретились две части выражения, между которыми пропущен
Обычно для этого добавляют точку с запятой сразу перед такими блоками.
Но если использовать унарный оператор, то этой проблемы просто нет (поэтому, на самом деле, мы экономим два байта, ещё и точка с запятой не обязательна):
var a = 5
!function () {}()Тут интерпретатор, встретив унарный оператор, понимает, что предыдущее выражение закончилось и началась новая конструкция.
Логичность шаблона «объявили и вызвали» в JS
Вчера в комменариях возникло обсуждение семантики синтаксиса «!function () {}()». Мне так кажется, что семантика здесь побоку, использовать функцию для создания зоны видимости — уже костыль (в JS 1.7 есть конструкция «let» для этого), но мне тут подумалось, что ведь можно сделать эту конструкцию семантичной, если использовать забытую конструкцию «with»:
with (function () {
// тело функции
}) call();На мой взгляд, весьма и весьма семантично. Что скажете?
Как в JS узнать что объект — массив?
Узнал на семинаре Кантора такую штуку. Как узнать, что объект, который пришёл на вход — массив? Конечно, лучше использовать утиную типизацию, но если нам нужен именно массив, со всей полнотой методов, не проверять же каждый?
Кстати, если
Я до недавнего времени думал, что правильный способ такой:
console.log([] instanceof Array); // trueА редко его используют, потому что конструкция «instanceof» не везде реализована. Я заблуждался. Вот правильный способ:
console.log(Object.prototype.toString.call([]) == '[object Array]'); // trueИ вот почему. Оказывается, у каждого фрейма своя иерархия типов, если один фрейм передаёт во второй
<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>