программирование

Пару слов о Джаве

У ДиБРа увидел прекрасное. Как вы думаете, что выведет следующий код:

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». Насколько я понял по комментариям, это происходит из-за того, в Джаве экземпляры Integer (видимо для скорости) в диапазоне [-128; 127] предопределены. Поэтому объекты «a» и «b» равны (ссылаются на один объект), а «c» и «d» нет. А на равенство значений надо проверять вызовом метода «equals».

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

Чем плох ПХП

На «Хабре» появился перевод статьи «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 (чтобы потом её переименовать), а если она уже где-то была создана, падает.

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

UserJS для воспроизведения H.264 в «Опере»

Существует плагин «DivX web player», который отлично подменяет тег «VIDEO», в случае, если должен быть использован кодек H.264, но браузер его не поддерживает.

К сожалению, в «Опере» он почему-то не работает. Я сделал UserJS, который, пользуясь этим плагином, подменяет видеотег, если у него указан тип «video/mp4». Все атрибуты он не переносит (я просто пока не столкнулся с тем, что это нужно), буду добавлять, если столкнусь. Кроме того, я подменяю метод «canPlayType», чтобы показать, что браузер 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. Исправлять не буду до первого реального случая, когда где-то этого события не будет достаточно.

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

Работа с камерой и распознавание чисел в «Опере»

Распозновалка (43.68КиБ)

Я вчера заморочился на отличненько. Мне показалось скучным и грустным вводить цифры счёта за квартиру в окошко «Госуслуг» и решил сделать автоматическую распознавалку чисел, попутно изучив работу с камерой из браузера.

Доступ к камере — эксперментальный стандарт, поэтому мало кто из браузеров может им похвастаться, я использовал специальный билд «Opera-Labs-Camera», который можно взять с сайта снапшотов «Оперы». Работать мой пример, соответственно, будет только там.

АПИ оказалось несложным. Всё, что нужно сделать — соединить специальным образом тег VIDEO с источником стримового видео; потом я 10 раз в секунд забираю кадр с видео и кладу в CANVAS (на скриншоте он цветной), оттуда вырезаю небольшую область, перевожу в градации серого, беру за порог 75% от усреднённого цвета и перевожу всё в ч/б.

Больше всего из трёх часов, которые у меня ушли на это, я делал распознование цифр. Алгоритмы, которые я нашёл в интернете, были очень монструозными, да и переписывать готовое было скучно, поэтом я перепробовал несколько вариантов, которые пришли мне в голову.

В итоге, лучше всех распознаёт следующий алгоритм.

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

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

На скриншоте в большом текстовом поле записаны получившиеся комбинации. Первое — номер по порядку, далее (через двоеточие) — количество переходов по вертикали и потом описанная последовательность. Например, «ноль» записывается как «2:11» (два перехода по вертикали, потом одинаковые переходы по разу слева и справа разделительной линии).

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

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

Переход на «Гоу 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.

Для тех, кто не понимает английский — набор утилит «Гоу» находится в стадии разработки и ещё может измениться. Это плохо очень. Я не хотел бы с выходом каждой новой версии смотреть не сломалось ли у меня что-то.

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

Гоу вышел

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: чем дальше, тем сильнее, да. Но если что, я переспрошу.

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

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». Но я рад, что ПХП постепенно избавляется от своих болезней.

Обратите внимание на более короткий синтаксис массивов. Это начинает походить на своеобразный стандарт уже.

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

libjpeg-turbo

Сегодня от нашего системного администратора узнал о библиотеке libjpeg-turbo. Это оптимизированная под SIMD-инструкции (MMX, SSE и NEON) библиотека libjpeg.

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

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

Я погонял тесты у себя на ноутбуке с «МакОС», результаты получились следующие:

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 вырезал оттуда кусок изображения. Каждый тест повторялся сто раз.

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

Перевод картинки в серый средствами CSS

Серое в CSS (92.76КиБ)

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

.gray {
        filter: gray; /* IE 5+ */
        -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(grayscale=1)"; /* new IE */
}

Я всё ждал когда же W3C «переизобретёт» микрософтские фильтры. Свершилось. Недавно появилась спецификация Filter Effects, которая, конечно, гораздо шире того, что когда-то предложили в «Микрософте», но основной смысл тот же, и даже некоторые фильтры похожи.

«Хром» включил в готовящуяся 18-ю версию эксперементальную поддержку этих фильтров:

.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 (и делать всякие другие чудесные штуки), правда все описания в документации почему-то относятся к XHTML или внешним ресурсам, но я обнаружил, что уже с четвёртой версии этот же трюк работает и с обычным 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>

Добавлено позднее: в ходе дальнейших экспериментов оказалось, что в более ранних «Хромах» (нижнюю границу я пока не выяснил, но в моём 17-м работает), можно через CSS задавать фильтры для SVG, вот таким образом:

<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, по ссылке можно протестировать что поддерживает ваш браузер.

Посмотреть код.

<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>

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

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

Магические методы

Что мне никогда не нравилось в Пайтоне, так это «магические» методы и свойства. Сейчас их существует за сотню:

bolk@Bolk ~  $ wget -O- http://docs.python.org/reference/datamodel.html 2>&- | egrep -o '__(\w+)__' | sort -u | wc -l
     108

Я, даже если очень постараюсь, вряд ли вспомню хотя бы половину. Всё «магическое» в Пайтоне начинается и заканчивается двумя подчёркиваниями, например, если сменить знак у объекта (сделать „-something“), то Пайтон попытается вызвать магический метод «__neg__». В более распространнённом ПХП всё примерно так же, но «магических» методов сильно меньше, их я уже помню на память все, но и возможности гораздо уже.

Запомнить все эти методы, наверное, реально при помощи тщательной зубрёжки, но сделать это естетственно, во время изучения языка, нереально, по моему мнению. Причина — неинтуитивность. Я давно высказывался на тему, почему хотя бы не расширить синтаксис и некоторые методы не разрешить называть как операции, то есть «/», «+», «[]» и так далее, смутно вспоминая, что в Си++, кажется, так и сделано.

Оказывается, так в точности сделано в языке «Скала»:

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» (если ссылок больше нет). Они уже содержат название операции, просто оно буквенное. Есть методы, которые вряд ли вообще можно как-то проще назвать, например «__new__» и «__init__» — названия конструкторов для «новых» и «старых» объектов Пайтона.

Наверняка есть часть, которую понятнее не назовёшь. На ум сразу приходит метод «__hash__», думаю есть и ещё.

Но, бо́льшую часть, мне бы хотелось именовать как-то понятнее. Причём, вполне можно предложить синтаксис для левостоящих и правостоящих объектов, что-то вроде «def self+» и «def +self».

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

Апач vs. Энжиникс

Меня кто-то убеждал буквально недавно, что Апач уже давно отдаёт статику столь же эффективно, как и nginx. На реальном весьма нагруженном проекте опыт смены одного на другое такой:

Я поставил и настроил ngnix для отдачи статического контента. Это снизило нагрузку в 2 раза…

Речь идёт о сайте president2012.ru. Версия Апача — 2-2.2.16-6+squeeze4, nginx — 0.7.67-3.

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

Каррирование и частичное применение

Я, оказывается, путал раньше каррирование и частичное применение. Даже не то чтобы путал, просто не пытался разобраться в чём разница между терминами, применяя то и другое по мере надобности. Недавно на «Хабре» в комментариях мне на моё незнание указали и я уяснил, наконец, что конкретно стоит за каждым термином.

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

// функция, суммирующая два числа
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 создаётся функция, в которую из-за замыкания, «железно» попадает аргумент «x» со значением «2». Поэтому возвращаемая функция будет всегда суммировать с двойкой. С этим фактом тесно связано частичное применение, потому что оно только что, фактически, состоялось.

Частичное применение функции (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» — с единицей.

Очень простые штуки, часто встречающиеся в функциональном программировании.

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

Bolt — автоматическое обновление конфигурации «Апача» на «Маке»

Добавил новую программу в свои «Игры с шелом», назвал «Болт», она следит за изменением папки, куда у вас на «Маке» по-умолчанию смотрит веб-сервер «Апач» (это ~/Sites/), если в ней что-то произошло, то добавляет все папки оттуда как доменные имена в конфигурацию «Апача» и в файл hosts.

Запускать нужно так (из командной строки):

sudo тутполныйпуть/bolt.sh &

Потом ввести пароль администратора. Если затем в папке с сайтами создать, например «site1», то в браузере сразу можно набирать «http://site1», он уже будет открываться. Программа умеет убирать за собой (после перезагрузки компьютера, например).

Скачать можно с «Гитхаба».

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

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('&nbsp;', ' '))

Выводится список банков (регион и город задаётся в коде в очевидном месте), например, на настоящий момент список выглядит вот так:

ОАО Банк ЗЕНИТ 
ОАО "РГС Банк" 
АКБ "Абсолют Банк" (ЗАО) 
Быстробанк ОАО 
ОАО "АК БАРС" БАНК 
АКБ "РОСБАНК" (ОАО) 
НОМОС-БАНК (ОАО) 
АКБ МБРР (ОАО) 
ЗАО АИБ "Ипотека-Инвест" 
ОАО "АИКБ "Татфондбанк" 
АКБ "БТА-Казань" (ОАО) 
КБ "Юниаструм Банк" (ООО) 
ОАО АКБ «Авангард» 
ОАО КБ "Восточный"

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

Бинарные данные в XML

На «Хабре» статья вышла, в ней есть интересный и обоснованный вывод:

Этот пример имеет практическое значение, т. к. в случае, если используются XML-файлы, которые содержат бинарные вставки и затем упаковываются (GZIP, DEFLATE и т. п.) для экономии трафика, то на самом деле выгоднее эти вставки делать не в Base64-кодировке, а в HEX, что может противоречить интуиции.

Кроме того, в ней проливается свет на сжатие в HTTPS-протоколе, я об этом, признаться, вообще не задумывался, так как HTTPS знаю плохо:

HTTPS может использоваться не только для защиты, но и для сжатия данных. Протоколы SSLv3 и TLS дают возможность договорится сторонам об использовании сжатия при установке соединения. Такой способ выглядит привлекательней метода с «Content-Encoding:gzip/deflate». Во первых, сжимаются все данные (включая заголовки), идущие в обе стороны. Во вторых, при сжатии может учитываться история запросов/ответов, что повышает эффективность сжатия.

Рекомендую статью к прочтению полность, тем более она небольшая.

1 комментарий

← 1 35 36 37 38 39 67 →