google web font

понедельник, 14 марта 2016 г.

How to expand an iterator into a list in Python3

One of the most noticeable changes from Python 2 to Python 3 is that map, filter, zip and range builtins now return iterators instead of lists. This is usually a good feature to have, because, well, nobody uses range outside of a for statement. But there may be rare cases when resulting list might take less memory then the iterator itself, especially when you nesting them like this:
def increase(self, *increments):
    self.values = map(sum, zip(self.values, increments))
This is going to eat all the memory and crash with a several gigabyte core dump. So the question is: how does one expand an iterator into a sequence in Python 3? Well, I don't want to hurt the Zen of Python, but there are more than one way to do so.

The most obvious one is this:
def increase(self, *increments):
    self.values = tuple(map(sum, zip(self.values, increments)))
It's too obvious to write the whole post about it. It is as obvious as to get rid of the iterator in favor of the list comprehension:
def increase(self, *increments):
    self.values = [sum(x) for x in zip(self.values, increments)]
(Don't forget to use square brackets, or else you will get a generator, which is practically the same as iterator in this case).

I mean, there are some more exotic ways to do it.

Сколькими способами можно развернуть генератор в список в Python3

Одно из заметных нововведений в Python3 по сравнению с Python2 это то, что встроенные функции filter, map, range и zip теперь возвращают итераторы. В некоторых случаях этот итератор может занимать больше памяти, чем тот список, который от него хотят. А если их ещё и засовывать один в другой, вроде чего-то такого:
def increase(self, *increments):
    self.values = map(sum, zip(self.values, increments))
так вообще никакой памяти не хватит. Отсюда, конечно вопрос: как развернуть этот итератор в нормальную последовательность? Как бы сильно это ни противоречило Дзену Пайтона, способов много.
Самый очевидный вариант:
def increase(self, *increments):
    self.values = tuple(map(sum, zip(self.values, increments)))
Слишком просто, чтобы писать об этом блог-пост. С таким же успехом можно было вообще избавиться от map, использовав list-comprehension:
def increase(self, *increments):
    self.values = [sum(x) for x in zip(self.values, increments)]
(обязательно квадратные скобки, а то генератор никуда не денется :-)
В общем, есть более экзотические варианты.

пятница, 26 февраля 2016 г.

Javascript plugins for Blogspot

I've just finished with some interface tuning here. I generally like when some piece of work looks nice at the end of the day. Blogspot have some problems here, though. First, it doesn't offer nice fonts (well, it have a few, but with no support for cyrillic). Second, adding a source code syntax highlighter requires manually editing the source code of the template, which is not so fun and have a sad consequence that changes get lost every time I switch the template.

Luckily, there is a clean and portable way to solve my problems without the need to edit the template at all. Here is the recipe:
  • Open blog setting and go to the "Design" tab.
  • Choose a block to add new gadget to. In some cases a block from the top of the page is preferable and in some cases it is better to choose one from the bottom, but in most cases it den's matter so much.
  • Click the "add gadget" link.
  • Choose "HTML/Javascript" in the pop-up
  • Enter any XHTML code, containing CSS and Javascript (enclosed into style and script tags) and hit the "save" button.

Javascript-плагины для blogspot

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

К счастью, на самом деле есть одно решение для обеих этих проблем: это возможность создания собственных "гаджетов".
  • В настройках блога выбираем "Дизайн"
  • Выбираем блок, в который не жалко добавить невидимый гаджет. В зависимости от цели можно предпочесть блок из верхней части страницы или из нижней.
  • Нажимаем "Добавить гаджет"
  • В появившемся окне выбираем "HTML/JavaScript"
  • В окне настроек пишем XHTML-код того, что нам нужно добавить, и сохраняем.

среда, 10 февраля 2016 г.

A word for recursion

Personally, I think that parents must teach recursion to their children as early as they give them counting rods for the first time. The first lesson about counting must be that every number is the previous number plus one
int getNthNumber(int n) {
    int nthNumber = getNthNumber(n-1) + 1;
    return nthNumber;
}
Of course, they need to define that the first number is zero
int getNthNumber(int n) {
    if (n == 1) // first number is zero by definition
        return 0;
    int nthNumber = getNthNumber(n-1) + 1;
    return nthNumber;
}
And there is a second lesson about recursion, which is that the first number have to have the index of zero, too
int getNthNumber(int n) {
    if (n == 0) // first number is zero by definition
        return 0;
    int nthNumber = getNthNumber(n-1) + 1;
    return nthNumber;
}

понедельник, 8 февраля 2016 г.

Немного про познание рекурсии

Для того, чтобы познать рекурсию, надо познать рекурсию.
http://bash.im/quote/11128

Познавать рекурсию нужно с детства, я так считаю. Когда родители вручают ребёнку счётные палочки, речь должна идти только о том, что каждое следующее число есть предыдущее число, увеличенное на единицу.
int getNthNumber(int n) {
    int nthNumber = getNthNumber(n-1) + 1;
    return nthNumber;
}
Ну, конечно, обязательно нужно оговориться, что первое число равно нулю
int getNthNumber(int n) {
    if (n == 1) // первое число равно нулю по определению
        return 0;
    int nthNumber = getNthNumber(n-1) + 1;
    return nthNumber;
}
Хотя, в примере выше есть ошибка, в нём нулю равно второе число. Потому что если первое число равно нулю, то первый номер первого числа тоже равен нулю, а не единице (вот это утверждение уже имеет отчётливый привкус рекурсии)
int getNthNumber(int n) {
    if (n == 0) // первое число равно нулю по определению
        return 0;
    int nthNumber = getNthNumber(n-1) + 1;
    return nthNumber;
}

вторник, 29 сентября 2015 г.

Мегафон, опция "Вокруг Света"

А вот вам дельный совет: если вы абонент Мегафона, улетая за границу, включайте опцию "Вокруг Света" в аэропорту вылета, а не прилёта. Потому что она действует по московскому времени.


Что примечательно, в описании опции про это даже действительно написано. Простой пример: если в Сан-Франциско вы вдруг вспомните, что забыли подключить эту опцию, то действовать она начнёт через примерно 10 часов после подключения. Если её включить в московском аэропорту, то в Сан-Франциско она тоже начнёт действовать только через десять часов, но поскольку перелёт длится ещё больше, никто этого не заметит.

среда, 26 августа 2015 г.

Shell executable jar


So, Java is rich on surpises, one can find some funny features in some pretty boring places. For instance, as boring as jar files.

Let's say, I 've got a jar which I run as usual:
java -jar my-fancy-app.jar
For this to work I need to add MainClass into manifest file, there is nothing to see there, except that jar files like this are called "executable" for some strange reason.

Then, if my program does something useful than it probably make use of some third-party libraries. And since I don't feel happy about annoying my users, I'd like to ship that libraries together with my application. Most common aproach is to use so-called "uber-jar" which contains third-party jars compiled into it. There is a maven plugin that can do so (sure, there is!), it installs it's own MainClass that installs it's own classloader and than yields for my MainClass. That classloader can load classes from jars inside the jar and is pretty much like one can find in the java tutorial from oracle.com.

While uber-jar is very convinient way for deploying an application, there are useful and important proprietary third-party libraries which have licences that don't allow me to bundle them inside my jar. And since one does not simply run java with both -jar and -cp options, I need a better solution. And there it is. I'd even say, sure there they are.

вторник, 25 августа 2015 г.

Как сделать jar, который может сам себя выполнить


Java богата сюрпризами, некоторые моменты откровенно радуют, некоторые забавляют. В целом, осваиваюсь, начинает нравиться. Обнаружил интересное, например, в том, как работает запускалка jar-файлов.

Типичное использование:
$ java -jar my-fancy-app.jar
Для того, чтобы это работало, нужно при сборке jar-файла указать исполняемый класс (MainClass), это всем известно, абитуриентов не принимают на первый курс, если они этого не знают.

Все программы, которые умеют делать что-то полезное, используют какие-то библиотеки, написанные другими людьми и заранее упакованные в другие -jar-файлы. Чтобы моё приложение могло их подцепить, мне нужно добавить их в classpath. Но когда я запускаю -jar, я не могу указать дополнительно другой classpath. Я не склонен винить кого-либо в этом ограничении, вопрос "почему" не настолько сильно меня беспокоит. Больше интересно, что делать.

Популярное решение: "uber-jar". Говорят, раньше у maven был плагин, который так назывался (сейчас для этого используется плагин shade). Он архивирует jar'ы зависимостей внутрь jar'а моего приложения и прописывает свой MainClass, который устанавливает свой classloader, а потом возвращает управление моей программе. Classloader загружает библиотеки из вложенных jar-файлов и не сильно отличается от того, который описан в одном из первых уроков по java на сайте оракла. Раньше, говорят, был плагин, который вообще jar'ы зависимостей распаковывал прямо в мой jar, ему даже classloader подменять не надо было.

Это решение может не работать в ситуации, когда одна из зависимостей имеет злобную лицензию, не позволяющую паковать её в свой jar. Поскольку указать дополнительный classpath при использовании ключа -jar нельзя, остаётся два варианта: поставить эту библиотеку в систему (типа $JAVA_HOME/lib/) либо не использовать ключ -jar. Как это не использовать?

понедельник, 10 августа 2015 г.

Чем старше становишься, тем сложнее становятся простые вещи

Удивительно, насколько прост и прекрасен мир, который видят дети. И ведь я тоже таким был. С каждым днём любое дело обрастает грузом опыта, который вроде бы и должен помогать в решении простых проблем, на деле обычно отбивает желание вообще чем-либо заниматься. Простой пример: попросите программиста со стажем написать простой список или алгоритм сортировки — он скорее всего откажется, хотя продолжит утверждать, что это слишком просто, чтобы тратить на это время. А уж начать какое-то действительно новое дело ещё сложнее, потому что ты уже знаешь, как много надоедливых граблей услужливо разложено вокруг.

Я старательно пытаюсь вернуть то мироощущение, когда я не знал про эти грабли. Это очень круто: знать, как решать проблемы, с которыми ты уже сталкивался, знать, сколько проблем тебя ждёт, но продолжать, как в детстве, верить, что любое дело — простое, надо только за него взяться. Если посмотреть вокруг, то люди с таким отношением к делам есть, и у них неплохо получается. Вот буду брать с них пример.

воскресенье, 2 августа 2015 г.

Возвращение

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

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

А эта заметка сделана просто для того, чтобы зафиксировать намерение писать по одному блогпосту в неделю. Я прекрасно понимаю, что стоит одну неделю пропустить — и привычка пропадёт, поэтому нужно будет сильно постараться. Это как бросать курить, только наоборот :-)

В общем, всем привет.

вторник, 6 августа 2013 г.

Гейзенбаг и Шрёдинбаг

Вот они и встретились.

У нас в проекте есть модуль А и модуль В. Они разрешаются лицензионными ключами. Каждый модуль может работать независимо от наличия другого модуля, но нужно, чтобы был активен хотя бы один, иначе программе можно вообще не запускаться. Всю жизнь у всех пользователей использовались оба модуля, а тут вдруг (практически, ВНЕЗАПНО), тестировщику понадобился только один из двух модулей. И ему, кстати, повезло ещё и с тем, что понадобился именно второй модуль. Повезло — потому что если убрать ключ на модуль А, то модуль В не включается, и потому что тестировщикам такие случайности очень нравятся. Оказалось, что модули инициализировались тупо по порядку:

понедельник, 19 марта 2012 г.

Кстати, про коммунальные услуги

Тут один популярный блогер раскритиковал моего любимого Собянина за то, что в Москве грязно. Высказывался в резких выражениях, можно было даже предположить, что это единственная вообще проблема, которая его волнует. Но мы-то знаем, что это не так: не решена проблема с парковками, с пробками, с турникетами в общественном транспорте (когда уже?!) — это только то, что касается пешего и езжего транспорта, и то не всё. Но как минимум за уборку территорий я вступлюсь: на выборах 4 марта всем москвичам давали ещё второй бюллетень, так вот, возле кого галочки поставили — к тем и идите жаловаться. Уборка территории принципиально относится к самым местным руководителям, которые только возможны в федеративном устройстве нашего государства. Жаловаться на лужи тому, кто решает совершенно другого уровня задачи — всё равно, что жаловаться президенту на то, что до́ма окна прохудились. Привыкли, что в Питере сосульки Матвиенко лично лазерами пуляла, панимаишь.

воскресенье, 18 марта 2012 г.

Про важность статического анализа

Есть ряд багов, которые нельзя поймать ни тестами, ни тестировщиками. Потому что формально установить наличие ошибки по выхлопу нельзя. Собственно, настоящие, красивые, баги появляются именно так, а не так, как мы уже привыкли: те "баги", которые мы видим каждый день — это либо дефекты выбранного алгоритма, либо его "забытые" тёмные закоулки (необработанные ошибки, нереализованные ветвления, неосвобождённая память и т.п.). А эти ошибки можно найти только анализируя код. И даже если это будет не тот "настоящий, красивый баг", которым можно восхищаться годами, постоянно переоткрывая его в багзилле, но тоже может быть интересно.

Вот простой пример:
sub very_bin_integer($) {
    my $length = int(shift) or die "Illegal length";
    my $ret = '';
    for ( 1 .. $length )
    {
        my $n = 0;
        while ( not $n ) {   
            $n = int(rand(9));
        };
        $ret .= $n;
    }
    return $ret;
}
Даже обработка некорректного ввода есть. Кто напишет корректный юнит-тест на эту ошибку — может рассчитывать на пирожок.

среда, 14 марта 2012 г.

Стратегия

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

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

вторник, 13 марта 2012 г.

Уберите вора и удивитесь

Не могу не радоваться локальным московским новостям с тех пор, как этого воришку Лужкова выжили с насиженного места. Как только его уволили (хотя могли бы и посадить, но так тоже неплохо) — сразу нашлись деньги и на плитку, и на метро, и на дороги, и на парковки, и вообще.

Очень хорошая и показательная ситуация, надо заметить. Лужков ведь не всегда был воришкой и когда-то Москва настолько хорошо чувствовала себя под его руководством, что москвичи реально сами выбирали его мэром. С тех пор много воды утекло, мэр Москвы стал назначаемым, а не изибраемым, и провёл на этой должности почти двадцать лет, что превратило его из хорошего руководителя в зажравшегося престарелого жулика.

Если Собянин просидит на этом посту двадцать лет, то, можно не сомневаться, скатится туда же. И тут важно даже не вовремя поймать тот момент, когда он покатится. Просто именно по этой причине весь цивилизованный мир осознал необходимость регулярной смены власти. Чтоб не засиживались и не скатывались.

Вы уже поняли, на кого я намекаю, ведь так? Единственное, чего я не понимаю, так это как можно с этим спорить. Всё же перед глазами, даже гуглить ничего не надо.

суббота, 3 марта 2012 г.

Ненавижу наклейки

Возвращаться к ведению блога — это всё равно, что начинать с нуля. Попробую начать с чего-нибудь несложного. Ненавидеть — просто. Ненавижу чёртовы наклейки.

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

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

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

Высказался — и полегчало.

пятница, 3 февраля 2012 г.

Однопользовательская система

Вот зачем ему несколько учётных записей?
Я много думал над этим и пришёл к выводу, что многопользовательские системы не нужны. Этот подход должен умереть. Линукс должен эволюционировать до однопользовательской системы, как и Windows, и хз как там у MacOS.

Любой "компьютер" сейчас используется одним человеком. Этот человек настраивает его под себя как хочет и даже отключает запрос пароля при логине в систему, потому что нафиг его каждый раз набирать, если устройством больше никто не пользуется? Я не ввожу пароль на телефоне, когда мне нужно позвонить. И на телевизоре тоже. И даже если мне захочется сделать запрос пароля, мне совершенно не нужно иметь многопользовательскую систему для этого.

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

воскресенье, 18 декабря 2011 г.

Наличие жизни за МКАДом

Это тот самый уровень, который "жизни нет". Я действительно был удивлён, хотя чему тут удивляться.

Есть у меня мама, живёт она очень глубоко за МКАДом. И есть у мамы с недавних пор ноутбук. К ноутбуку нужен интернет, поэтому я незадолго до появления устройства позвонил в местный интернет с просьбой подключить маму. Состоявшийся телефонный диалог ввёл меня в состояние кататонической фалломорфии на несколько дней. Суть была такова:

пятница, 9 декабря 2011 г.

Негодовайчик

Маленькая заметка об осторожности.

Команда cp в консоли копирует файлы из пункта А в пункт Бэ. Если пункт Бэ является каталогом, то из пункта А можно скопировать несколько файлов, если нет, то нет ©. Поэтому когда я экспериментирую на кошках, я нередко делаю так:
$ mkdir ./{storage,sandbox}
$ mv ./important_files_* ./storage/
$ cd ./sandbox/
$ cp ../storage/important_files_* ./
И вот тут может подкрасться пушистый лисёнок. Одна из моих люимых опечаток — промахнуться мимо двух находящихся рядом клавиш ./ и попасть куда попало, например, на Alt и Shift. В консоль при этом ничего не напечатается. Если в каталоге storage много файлов, то всё ок: я получу сообщение об ошибке:
$ cp ../storage/important_file_*
important_file_100500 не является каталогом
А вот если файлов всего два, то будет больно:
$ md5sum ../storage/important_file_*
3b80e8178985f9954e3ce0e9df962914  ../storage/important_file_1
d1af2e429dbd91857cc23fcb747f8bdb  ../storage/important_file_2
$ cp ../storage/important_file_*
$ md5sum ../storage/important_file_*
3b80e8178985f9954e3ce0e9df962914  ../storage/important_file_1
3b80e8178985f9954e3ce0e9df962914  ../storage/important_file_2
Не могу не заметить, что против этого "лома" нет приёма, не использовать же MidnightCommander из-за такой ерунды. Так что просто будьте аккуратнее, да.