программирование
Пару слов о Джаве
У ДиБРа увидел прекрасное. Как вы думаете, что выведет следующий код:
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». Насколько я понял по комментариям, это происходит
Чем плох ПХП
На «Хабре» появился перевод статьи «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 (чтобы потом её переименовать), а если она уже
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. Исправлять не буду до первого реального случая, когда
Криптография для чайников
Очень хорошее видео (но на английском языке) о том как работает обмен ключами в том же самом HTTPS.
Работа с камерой и распознавание чисел в «Опере»

Я вчера заморочился на отличненько. Мне показалось скучным и грустным вводить цифры счёта за квартиру в окошко «Госуслуг» и решил сделать автоматическую распознавалку чисел, попутно изучив работу с камерой из браузера.
Доступ к камере — эксперментальный стандарт, поэтому мало кто из браузеров может им похвастаться, я использовал специальный билд «
АПИ оказалось несложным. Всё, что нужно сделать — соединить специальным образом тег VIDEO с источником стримового видео; потом я 10 раз в секунд забираю кадр с видео и кладу в CANVAS (на скриншоте он цветной), оттуда вырезаю небольшую область, перевожу в градации серого, беру за порог 75% от усреднённого цвета и перевожу всё в ч/б.
Больше всего из трёх часов, которые у меня ушли на это, я делал распознование цифр. Алгоритмы, которые я нашёл в интернете, были очень монструозными, да и переписывать готовое было скучно, поэтом я перепробовал несколько вариантов, которые пришли мне в голову.
В итоге, лучше всех распознаёт следующий алгоритм.
Сначала я очевидным образом разбиваю изображение на цифры, потом условно разделяю каждую цифру вертикальной линией по середине. Слева и справа от линий считаю количество переходов между чёрным и белым, двигаясь сверху вниз. Получаются комбинации из пар чисел. Я их прореживаю — одинаковые последовательно идущие заменяю на одно значение.
Получаются цепочки, которые уже достаточно хорошо характеризуют цифру, правда некоторые цифры этот паттерн не в состоянии распознать. Поэтому я считаю количетсво ч/б переходов ещё и по моей умозрительной вертикальной линии.
На скриншоте в большом текстовом поле записаны получившиеся комбинации. Первое — номер по порядку, далее (через двоеточие) — количество переходов по вертикали и потом описанная последовательность. Например, «ноль» записывается как «2:11» (два перехода по вертикали, потом одинаковые переходы по разу слева и справа разделительной линии).
Алгоритм «шумит»,
Переход на «Гоу 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.
Для тех, кто не понимает английский — набор утилит «Гоу» находится в стадии разработки и ещё может измениться. Это плохо очень. Я не хотел бы с выходом каждой новой версии смотреть не сломалось ли у меня
Гоу вышел
Today marks a major milestone in the development of the Go programming language. We’re announcing Go version 1, or Go 1 for short, which defines a language and a set of core libraries to provide a stable foundation for creating reliable products, projects, and publications.
Появился релиз языка «Гоу». Это означает, что язык стабилизировался и обратную совместимость ломать больше не будут.
Шутки про технологии
abeshkov: Знаю отличную шутку про UDP, но не факт что она до вас дойдет. :) n1313: про технологии шутим, да? Ну вот я знаю того, кто знает отличную шутку про DNS. bolk: n1313, но ты не уверен, правильно ли помнишь? n1313: чем дальше, тем сильнее, да. Но если что, я переспрошу.
PHP 5.4
Поставил себе на ноут ПХП 5.4, смотрю как работает. Трейты, конечно, приятная штука, но гораздо важнее, что синтаксис в порядок стали приводить. К сожалению, с первой попытке порядок навести не удалось, но стало гораздо логичнее.
class B {
function arr() {
return [
'i' => 0b101,
'f' => function () {
return ['i' => 1];
}
];
}
}
var_dump((new b)->arr()['i']); // works!
var_dump(call_user_func((new b)->arr()['f'])['i']); // still works…
var_dump((new b)->arr()['f']()); // don't :(В примере дан класс «B», метод «arr» которого возвращает массив из двух элементов. По индексу «i» там число, по «f» — анонимная функция, которая так же возвращает массив. В новом (5.4) ПХП есть возможность получить элемент массива, возвращаемый функцией, не присваивая его переменной (и, кстати, вызвать метод объекта сразу после его создания).
Но увы, пока нельзя так же вольно обращаться с функциями, приходится их оборачивать в «call_user_func». Но я рад, что ПХП постепенно избавляется от своих болезней.
Обратите внимание на более короткий синтаксис массивов. Это начинает походить на своеобразный стандарт уже.
libjpeg-turbo
Сегодня от нашего системного администратора узнал о библиотеке
Авторами утверждается, что библиотека превосходит оригинальную по скорости в несколько раз.
Самое интересное, что библиотека бинарно соместима с оригиналом, то есть простой заменой одной на другую в системе можно добиться прироста производительности всех утилит, которые её используют.
Я погонял тесты у себя на ноутбуке с «МакОС», результаты получились следующие:
bolk@Bolk ~ $ otool -L `which jpegtran` | fgrep libjpeg
/usr/local/Cellar/jpeg/8d/lib/libjpeg.8.dylib (compatibility version 13.0.0, current version 13.0.0)
bolk@Bolk ~ $ time for _ in {1..100}; do jpegtran -optimize -crop 4000x3000+2+2 ex.jpg > /dev/null; done
real 1m28.244s
user 1m20.063s
sys 0m7.705
bolk@Bolk ~ $ otool -L /opt/libjpeg-turbo/bin/jpegtran | fgrep libjpeg
/opt/libjpeg-turbo/bin/jpegtran:
/opt/libjpeg-turbo/lib/libjpeg.62.dylib (compatibility version 63.0.0, current version 63.0.0)
bolk@Bolk ~ $ time for _ in {1..100}; do /opt/libjpeg-turbo/bin/jpegtran -optimize -crop 4000x3000+2+2 ex.jpg > /dev/null; done
real 0m59.433s
user 0m50.509s
sys 0m7.728sВ моём случае прирост порядка 30%. Для теста я взял случайную картинку из фотоальбомов с разрешением 5184×3456 и при помощи утилиты jpegtran вырезал оттуда кусок изображения. Каждый тест повторялся сто раз.
Перевод картинки в серый средствами CSS

Экспериментировал в рамках прототипа для рабочего проекта с преобразованием изображения в серую гамму. Вообще, конечно, есть тег CANVAS, там это запросто, но интересно посмотреть появилось ли
.gray {
filter: gray; /* IE 5+ */
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(grayscale=1)"; /* new IE */
}Я всё ждал когда же W3C «переизобретёт» микрософтские фильтры. Свершилось. Недавно появилась спецификация Filter Effects, которая, конечно, гораздо шире того, что
«Хром» включил в готовящуяся
.gray {
-webkit-filter: grayscale(1); /* Chrome 18+ */
}В «Опере» и «Файрфоксе» поддержки этих фильтров пока нет, но есть поддержка других — фильтров SVG. Можно, например, засунуть растровое изображение внутрь SVG и применить к нему нужный фильтр:
<svg style="width: 0; height: 0">
<filter id="gray">
<feColorMatrix type="saturate" values="0"/>
</filter>
</svg>
<!-- тут какой-то HTML код и вдруг понадобилась серая картика -->
<svg style="width:400px; height: 431px"><image xlink:href="/imgs/2008.11.27.jpg" width="100%" height="100%" filter="gray" /></svg>Хорошие новости — SVG можно мешать с HTML. С версии 3.5 в «Файерфоксе» есть способ лучше — можно применять фильры SVG прямо к тегам HTML (и делать всякие другие чудесные штуки), правда все описания в документации
<style>
.gray {
filter: url(#gray); /* Firefox 4+ */
}
</style>
<svg style="width: 0; height: 0">
<filter id="gray">
<feColorMatrix type="saturate" values="0"/>
</filter>
</svg>
<body><img src="/imgs/2008.11.27.jpg" class="gray" /></body>Добавлено позднее: в ходе дальнейших экспериментов оказалось, что в более ранних «Хромах» (нижнюю границу я пока не выяснил, но в моём
<style>
.gray {
-webkit-filter: url(#gray); /* Chrome ?? */
-webkit-filter: grayscale(1); /* Chrome 18+
}
</style>
<svg style="width: 0; height: 0">
<filter id="gray">
<feColorMatrix type="saturate" values="0"/>
</filter>
</svg>
<!-- тут HTML и внезапно понадобилась серая картинка -->
<svg style="width:400px; height: 431px"><image xlink:href="/imgs/2008.11.27.jpg" width="400" height="431" class="gray" /></svg>При этом «Хром» требует, чтобы ширина и высота картинки были заданы в абсолютных единицах (остальные браузеры прекрасно понимают проценты).
Если собрать всё вместе, получается нижеприведённый код. Я поставил рядом два изображения: слева обычный элемент HTML img, справа — растр в SVG, по ссылке можно протестировать что поддерживает ваш браузер. Мне негде потестировать IE и тем более десятую версию, но я Посмотреть код.
<html>
<meta http-equiv="X-UA-Compatible" content="IE=9" />
<style>
.gray {
cursor: pointer;
filter: url(#gray); /* Firefox 4+ */
filter: gray; /* IE 5+ */
-webkit-filter: url(#gray); /* Chrome ?? */
-webkit-filter: grayscale(1); /* Chrome 18+ */
-ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(grayscale=1)"; /* new IE */
}
.gray:hover {
filter: none;
-webkit-filter: none;
-ms-filter: none;
}
</style>
<svg style="width: 0; height: 0">
<filter id="gray">
<feColorMatrix type="saturate" values="0"/>
</filter>
</svg>
<body>
<img src="/imgs/2008.11.27.jpg" class="gray" />
<svg style="width:400px; height: 431px"><image xlink:href="/imgs/2008.11.27.jpg" width="400" height="431" class="gray" /></svg>
</body>
</html>
Магические методы
Что мне никогда не нравилось в Пайтоне, так это «магические» методы и свойства. Сейчас их существует за сотню:
bolk@Bolk ~ $ wget -O- http://docs.python.org/reference/datamodel.html 2>&- | egrep -o '__(\w+)__' | sort -u | wc -l
108Я, даже если очень постараюсь, вряд ли вспомню хотя бы половину. Всё «магическое» в Пайтоне начинается и заканчивается двумя подчёркиваниями, например, если сменить знак у объекта (сделать
Запомнить все эти методы, наверное, реально при помощи тщательной зубрёжки, но сделать это естетственно, во время изучения языка, нереально, по моему мнению. Причина — неинтуитивность. Я давно высказывался на тему, почему хотя бы не расширить синтаксис и некоторые методы не разрешить называть как операции, то есть «/», «+», «[]» и так далее, смутно вспоминая, что в Си++, кажется, так и сделано.
Оказывается, так в точности сделано в языке «Скала»:
trait Ord{
def < (that:Any):Boolean
def<=(that:Any):Boolean = (this < that) || (this == that)
def> (that:Any):Boolean = !(this <= that)
def>=(that:Any):Boolean = !(this < that)
}Это гораздо проще выучить, изучая язык, чем «__lt__», «__le__», «__gt__», «__ge__» (впрочем, когда перечисляешь в ряд несколько конструкций, кажется что ничего страшного в этом нет, но надо держать в голове, что их больше сотни).
У некоторых методов название упрощать не нужно, например «__unicode__» (преобразование к юникодной строке) всё равно дёргается стоит вызвать unicode(something) или «__del__» (деструктор) вызывается, в частности, если сделать «del something» (если ссылок больше нет). Они уже содержат название операции, просто оно буквенное. Есть методы, которые вряд ли вообще можно
Наверняка есть часть, которую понятнее не назовёшь. На ум сразу приходит метод «__hash__», думаю есть и ещё.
Но, бо́льшую часть, мне бы хотелось именовать
Апач vs. Энжиникс
Меня
Я поставил и настроил ngnix для отдачи статического контента. Это снизило нагрузку в 2 раза…
Речь идёт о сайте president2012.ru. Версия Апача —
Как работает свойство vertical-align в ЦСС
На сайте
Каррирование и частичное применение
Я, оказывается, путал раньше каррирование и частичное применение. Даже не то чтобы путал, просто не пытался разобраться в чём разница между терминами, применяя то и другое по мере надобности. Недавно на «Хабре» в комментариях мне на моё незнание указали и я уяснил, наконец, что конкретно стоит за каждым термином.
Каррирование — преобразование функции от двух аргументов в функцию от первого аргумента, возвращающую функцию, результат вызова которой со вторым агрументом эквивалентен вызову первоначальной функции с упомянутыми аргументами. Немного запутанно, с примерами станет всё яснее. Я буду объяснять на примере Джаваскрипта, его больше народу знает, а на ПХП очень уж многословно получается. Кстати, в соответствующую статью в «Википедии» я добавил пример на «Гугл Гоу».
// функция, суммирующая два числа
function sum(x, y) {
return x+y;
}
alert(sum(2, 8)); // вернёт 10
function sum(x) {
return function (y) {
return x+y;
}
}
alert(sum(2)(8)); // тоже вернёт 10При вызове второй функции sum создаётся функция, в которую
Частичное применение функции (Partial function) — создание некой функции на базе указанной, где некоторые агрументы заменены конкретными значениями. Например:
function partial_one_arg(f, a) {
return function(b) {
return f(a, b);
}
}
min0 = partial_one_arg(Math.min, 0);
min1 = partial_one_arg(Math.min, 1);
alert([min0(-5), min0(5)]); // вернёт [-5, 0]
alert([min1(-5), min1(5)]); // вернёт [-5, 1]В примере я заменил один из агрументов фунции нахождения минимального значения на конкретное значение, теперь при вызове функции «min0» сравнение будет идти с нулём, при вызове «min1» — с единицей.
Очень простые штуки, часто встречающиеся в функциональном программировании.
Что нового в ПХП 5.4
Илья Альшанетский (это один из разработчиков ПХП) подготовил презентацию в формате ПДФ о том о самых важных нововведениях ПХП 5.4.
Bolt — автоматическое обновление конфигурации «Апача» на «Маке»
Добавил новую программу в свои «Игры с шелом», назвал «Болт», она следит за изменением папки, куда у вас на «Маке»
Запускать нужно так (из командной строки):
sudo тутполныйпуть/bolt.sh &Потом ввести пароль администратора. Если затем в папке с сайтами создать, например «site1», то в браузере сразу можно набирать «http://site1», он уже будет открываться. Программа умеет убирать за собой (после перезагрузки компьютера, например).
Скачать можно с «Гитхаба».
MakeCorner, новый процесс инсталяции
У меня есть проект MakeCorner — бесчеловечная (потому что запускается из командной строки) программа для скругления уголков. Я несколько раз писал про неё, поэтому буду предполагать, что все заинтересованные лица в курсе что это такое и зачем.
Я переделал установку, теперь она стала намного проще (по крайней мере под «МакОс»).
Банкоматы «Ак Барс Банка»
У меня зарплатная карточка «Ак Барс Банка», он вряд ли известен за пределами нашей республики, но в Татарстане широко распространён. Этот банк входит в организацию «Объединённая расчётная система», в которую входят ещё несколько банков, в банкоматах которых карты «Ак Барса» обслуживаются на льготных условиях.
Список
# coding: utf-8
import urllib
import re
import sys
import codecs
from itertools import ifilter
# Чтобы при перенаправлении в файл была кодировка UTF-8
sys.stdin = codecs.getreader('utf-8')(sys.stdin)
sys.stdout = codecs.getwriter('utf-8')(sys.stdout)
# Конфигурация
ORS_URL = 'http://ors.ru/cashpoints/print.asp'
ORS_CITY = u'Казань'
ORS_REGION = u'Республика Татарстан'
# Данные для оправления через POST
postdata = urllib.urlencode({
'CITY': ORS_CITY.encode('cp1251'),
'REGION': ORS_REGION.encode('cp1251'),
'CURRENCY': 'RUR',
'OPERATION': 'cash-out',
})
content = urllib.urlopen(ORS_URL, postdata).read().decode('cp1251')
# Ищем все ячейки таблицы и выбираем каждую вторую из шести
tds = re.finditer('<td[^>]*>(.+?)</td>', content, re.S | re.I)
tds = ifilter(lambda x: x[0] % 6 == 1, enumerate(tds))
# Берём только уникальные значения и рубим лишние символы
for x in set(x[1].group(1) for x in tds):
print(x.replace(' ', ' '))Выводится список банков (регион и город задаётся в коде в очевидном месте), например, на настоящий момент список выглядит вот так:
ОАО Банк ЗЕНИТ
ОАО "РГС Банк"
АКБ "Абсолют Банк" (ЗАО)
Быстробанк ОАО
ОАО "АК БАРС" БАНК
АКБ "РОСБАНК" (ОАО)
НОМОС-БАНК (ОАО)
АКБ МБРР (ОАО)
ЗАО АИБ "Ипотека-Инвест"
ОАО "АИКБ "Татфондбанк"
АКБ "БТА-Казань" (ОАО)
КБ "Юниаструм Банк" (ООО)
ОАО АКБ «Авангард»
ОАО КБ "Восточный"Бинарные данные в XML
На «Хабре» статья вышла, в ней есть интересный и обоснованный вывод:
Этот пример имеет практическое значение, т. к. в случае, если используются
XML-файлы, которые содержат бинарные вставки и затем упаковываются (GZIP, DEFLATE и т. п.) для экономии трафика, то на самом деле выгоднее эти вставки делатьне в Base64-кодировке, а в HEX, что может противоречить интуиции.
Кроме того, в ней проливается свет на сжатие
HTTPS может использоваться не только для защиты, но и для сжатия данных. Протоколы SSLv3 и TLS дают возможность договорится сторонам об использовании сжатия при установке соединения. Такой способ выглядит привлекательней метода
с «Content-Encoding:gzip/deflate». Во первых, сжимаются все данные (включая заголовки), идущие в обе стороны. Во вторых, при сжатии может учитываться история запросов/ответов, что повышает эффективность сжатия.
Рекомендую статью к прочтению полность, тем более она небольшая.