Brainfuck на AppleScript

Для развлечения написал интерпретатор языка Brainfuck на AppleScript.

Особенности: для ввода программы используется текстовое поле, которое выглядит как однострочное, но на деле понимает многострочный текст. Операция «,» у меня с буфером, это значит, что при запросе можно вводить сразу строку, при надобности интерпретатор сам будет брать оттуда значения. Если их не хватит, запросит ещё.

AppleScript медленный язык, следовательно и получившийся интерпретатор медленный (никаких оптимизаций я не делал), лучше всего на нём запускать небольшие программы. Например, «Hello, world»:

++++++++[>+++++++++<-]>.<+++++[>++++++<-]>-.+++++++..+++.< 
++++++++[>>++++<<-]>>.<<++++[>------<-]>.<++++[>++++++<-]> 
.+++.------.--------.>+.

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

Интерпретатор Brainfuck на AppleScript.

#!/usr/bin/osascript
-- AppleScript Brainfuck interpreter
-- Evgeny Stepanischev 1 Jul 2011 //bolknote.ru

set Cells to {}
repeat 30000 times
    set end of Cells to 0
end repeat

display dialog "Enter your BF program" default answer ""
set Bf to text items of text returned of result

set Pointer to 1
set CmdPointer to 1
set Output to ""
set Input to {}
set Stack to {}

repeat while CmdPointer ≤ (count of Bf)
    set Cmd to item (CmdPointer) of Bf
    
    if Cmd is equal to ">" then
        set Pointer to Pointer + 1
        if Pointer > 30000 then set Pointer to 1
        
    else if Cmd is equal to "<" then
        set Pointer to Pointer - 1
        if Pointer < 1 then set Pointer to 30000
        
    else if Cmd is equal to "+" then
        set Val to (item (Pointer) of Cells) + 1
        if Val is greater than 255 then set Val to 0
        copy Val to item (Pointer) of Cells
        
    else if Cmd is equal to "-" then
        set Val to (item (Pointer) of Cells) - 1
        if Val is less than 0 then set Val to 255
        copy Val to item (Pointer) of Cells
        
    else if Cmd is equal to "." then
        set Output to Output & (ASCII character item (Pointer) of Cells)
        
    else if Cmd is equal to "," then
        if Output ≠ "" then
            display alert Output
            set Output to ""
        end if
        
        if Input is {} then
            display dialog "Enter one or more characters" default answer ""
            set Res to text returned of result
            
            set item (Pointer) of Cells to ASCII number of character 1 of Res
            
            try
                set Input to rest of text items of Res
            end try
            
        else
            set item (Pointer) of Cells to ASCII number of item 1 of Input
            set Input to rest of Input
        end if
        
    else if Cmd is equal to "[" then
        if item (Pointer) of Cells = 0 then
            set CmdPointer to CmdPointer + 1
            set Deep to 1
            
            repeat while CmdPointer ≤ (count of Bf)
                set Cmd to item (CmdPointer) of Bf
                
                if Cmd is equal to "[" then
                    set Deep to Deep + 1
                else if Cmd is equal to "]" then
                    set Deep to Deep - 1
                    
                    if Deep is 0 then exit repeat
                end if
                
                set CmdPointer to CmdPointer + 1
                
            end repeat
        else
            set Stack to (CmdPointer - 1) & Stack
        end if
    else if Cmd is equal to "]" then
        if item (Pointer) of Cells ≠ 0 then
            copy item (1) of Stack to CmdPointer
        end if
        set Stack to rest of Stack
    end if
    
    set CmdPointer to CmdPointer + 1
end repeat

if Output ≠ "" then
    display alert Output
end if

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

Как мне AppleScript

Миша, мой коллега, под постом, где я написал про интерпретатор Brainfuck на AppleScript с беспокойством осведомился, не подсел ли я на AppleScript.

Краткий ответ: нет.

Длинный ответ таков.

Мне непонятно текущее состояние AppleScript. Очевидно, что концепция «пользователь пишет программы на английском» вполне себе ничего. Для непрограммистов это был бы выход. А для программистов такой язык жутко неудобен. По понятными причинам. Программисты привыкли писать много, а на велиречивом AppleScript писать не каждому понравится (не пишу «никому», потому что существует же Objective C). Все эти сокращения в языке — «собачки», доллары и разные скобочки, их нужно помнить, но они здорово экономят время при написании программы и при её чтении. Потому что они короткие и их больше помещается на экране.

Текущее состояние непонятно, потому что цели своей авторы языка не достигли. До сих пор нужно писать «set Var to Var + 1» и нельзя «set Var to Var plus one», какой же это английский? При этом язык уже полтора года не развивается.

То есть проблема «иногда быстро писать мелкие программы» явно пока не решена. Так как для этого «иногда» надо иметь память робота, чтобы вспомнить через несколько месяцев как в этом языке что-то проверить или присвоить. Сам язык ещё ничего, запоминающийся. Но если хочется чего-то чуть более серьёзного, то приходится обращаться к специальному API.

Например, чтобы вызвать текстовый редактор и написать там «Hello», нужно сделать следующее:

tell application "TextEdit"
    activate
    tell application "System Events" to keystroke "hello"
end tell

Я открываю приложение TextEdit (так встроенный в MacOS текстовый редактор называется) и прошу System Events понажимать в редактор несколько клавиш. Выделенное наклонным — это как раз пример такого API. Причём, если написать в кавычки «³˚¹⁄₃¹⁄₂», то программа либо не сделает ничего, либо напечатает в редактор ерунду. Всё устроено так, как будто System Events действительно жмёт клавиши на клавиатуре. А вот эти символы система не знает как ввести. То же будет с китайскими иероглифами, например.

Ещё, когда я только начал знакомиться с AppleScript, у меня было заблуждение, что AppleScript — язык общего назначения, вроде PowerShell или Bash. Ничего подобного, вместо bash в Mac OS есть bash. AppleScript толком не умеет даже получить данные от пользователя, скажем перехватить нажатие клавиши (и нет ничего встроенного, что может ему в этом помочь), а уж о том, как мало он умеет самостоятельно выводить и говорить нечего.

Так что симпатии к языку у меня не появится, думаю. Не для меня он. Но писать я на нём иногда буду, я и на CMD много странного писал в своё время.

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

«Гонка версий»

Смешно, ей-богу, читать, что «Микрософт» включилась в «гонку номеров версий» браузеров. Мол, вместо того, чтобы выпустить какой-нибудь Internet Explorer 9.1, они выпускают 10. Мне повезло, я был уже в сознании, когда интернет только начинался. Поэтому я помню, что гонку номеров версий «Микрософт» начала!

Пока фирма Netscape выпускала свои бесконечные 1.00, 1.1, 1.22, 2.0, 2.01, 2.02, 3.0, 3.01, 3.02, 3.03, 3.04, 4.0, 4.01, 4.01a, 4.02, 4.03, 4.04, 4.05, 4.06, 4.07, 4.08, 4.5, 4.51, 4.6, 4.61, 4,7, 4.72, 4.73, 4.74, 4.75, 4.76, 4.77, 4.78, 4.79 и 4.8, «Микрософт» выпускала и продолжает выпускать IE 1.0, 1.5, 2.0, 3.0, 4.0, 5.0, 5.5, 6, 7, 8, 9 и 10. Причём, последние версии ещё и ноль в конце потеряли.

Версия 1.5 была явным заблуждением, а 4.5 я в список не включил — это отдельная ветка, её для «Мака» делали, так же как и другие, ещё менее известные подверсии для других систем.

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

Автоэкзотика — 2011

Сходили сегодня на «Автоэкзотику» на Тушинском аэродроме города Москвы. Шоу «Автоэкзотика» — это выставки автомобилей, мотициклов, гонки и вообще всё, что связано с машинами. Шоу проходит с первого по десятое июля.

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

Серый ретроавтомобиль с хромированной решёткой радиатора, фигурой оленя на капоте и российским номером Е868НА 197 RUS на фоне травы и другой машины.
Бежевый ретро-пикап Volkswagen с красными акцентами и надписями «OLD CAR COMPANY» и «THE BALVENIE», припаркованный на траве у палатки.
Красно-бежевый внедорожник ГАЗ-21 «Волга» с увеличенным клиренсом и крупными шинами на травянистом поле под облачным небом.
Фронтальный вид синего ретроавтомобиля с круглыми фарами и радиаторной решёткой на травянистой площадке; на заднем плане — белый внедорожник, палатки и другие машины.
Светло-голубой ретроавтомобиль с хромированной решёткой радиатора на переднем плане, за ним — белый кабриолет и люди на выставке классических машин на открытом воздухе.
Жёлтый ретро-автомобиль Ford с чёрным тентом и деревянными колёсами на выставке классических машин на травянистом поле, за ним — другие винтажные авто и палатки.
Красный классический кабриолет Chevrolet Corvette с эмблемой и надписью на капоте, сдвоенными круглыми фарами и хромированными деталями на фоне зелёной лужайки и палаток.
Крупный план руля и бака ржавого красного мотоцикла B.S.A. с зелёным баком и белой надписью, стоящего на траве на открытом воздухе.
Интерьер классического кабриолета: светло-голубой руль с эмблемой, приборная панель с круглыми шкалами, белая обивка сидений и синие ковры.
Две девушки в чёрных купальниках и ботфортах с ремешками танцуют перед серебристым автомобилем с открытыми дверями на открытом воздухе, рядом стоят мужчины и другие машины.
Чёрный автомобиль ГАЗ-3110 с надписью «MC KAKOSS» на двери припаркован на травянистом поле; на заднем плане видны палатки, люди и другие машины.
Хромированный велосипед с большим передним колесом, черным меховым украшением и пиратским флагом стоит на траве на фоне выставленных автомобильных дисков и отдыхающих людей.
Без рубашки молодой человек стоит на сегвее на траве, разговаривая по телефону; за ним — чёрный электромобль и жёлтый фургон с росписью, на заднем плане — палатки и люди.
Две женщины в купальниках стоят на крыше белого внедорожника с рисунком медведя на фоне городских зданий и ясного неба.
Мужчина в камуфляже и с белой бородой сидит на красном мотоцикле Honda Shadow на открытом воздухе, рядом с прилавком с тканями и палаткой.
Голубой ЗАЗ-965 с аэрографией на капоте и номером У965ЕХ 177 RUS стоит на траве, рядом стоит без рубашки мужчина, на заднем плане — люди и городские здания.

Уже жалею, что у меня нет суперзума. Бо́льшую часть потрясающих трюков спортсменов я не смог снять из-за того, что было слишком далеко.

Мотоциклист в белом шлеме и защитном жилете выполняет трюк на оранжевом мотоцикле на заднем колесе на асфальте, на заднем плане баннер «RUSSIA 2011» и зрители.
Мотоциклист в синей футболке и шлеме выполняет трюк на заднем колесе на асфальтированной площадке, на заднем плане — баннеры с надписями «MOTO», «МОТОМАНИЯ» и фотограф.
Мотоциклист в шлеме и белой футболке выполняет трюк на заднем колесе на асфальтовой площадке, на заднем плане — баннеры «BATTLE RUSSIA 2011» и «MOTUL».
Мотоциклист в шлеме и защитной экипировке выполняет трюк на белом мотоцикле с надписью STUNTBIKE на асфальтированной площадке перед баннерами с логотипами.
Мотоциклист в защитной экипировке выполняет трюк на жёлтом мотоцикле во время чемпионата Восточной Европы по стантрайдингу Motul Mi-Stunt Battle Russia 2011.
Мотоциклист в зелёно-чёрной экипировке выполняет трюк на заднем колесе на асфальтированной площадке перед баннерами «MOTO», «STUNTER.RU» и «ЧЕРЕЗ МАСТЕРСТВО НА ТРАССЕ
Мотоциклист в зелёно-чёрной экипировке выполняет трюк на заднем колесе на асфальтовой площадке, на фоне баннеров STUNTRU и GS MOTO.
Мотоциклист в зелёной экипировке выполняет трюк на заднем колесе на асфальтовой площадке, на заднем плане видны баннеры с надписью «STUNTER.RU» и логотипами.

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

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

«Без булдырабыз»

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

В чём идиотизм-то, расскажите?

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

Галереи теперь в трансляциях

Сделал, как многие просили, фотогалереи в трансляциях RSS. Теперь всюду, куда транслируется мой блог («Ярушка», ЖЖ и т. д.), видно бо́льшую часть фотографий (не более десяти). Галереи там, конечно, условные — с миниатюры ссылка ведёт на полное фото.

Фотогалереи в RSS (54.14КиБ)

Вот, кстати, о чём совершенно забыли создатели современной версий HTML — это форматирование HTML там, где всё плохо с CSS. В читалках RSS (тут CSS режется из соображений безопасности) и почтовых клиентах (те же соображения, плюс примитивные движки в некоторых приложениях). Я, пока отлаживал трансляции, убедился, что единственный способ всё отформатировать как надо — использовать таблицы и винтажные 0.gif. Но чем дальше, тем меньше можно сделать атрибутами тегов, да ещё и в условиях, когда лента встроена в документ, где уже есть стили (например из-за сброса стилей, на «ярушке» не работают атрибуты hspace и vspace у картинок).

Конечно это правильно, разделение данных и представления, но HTML5 не предлагает взамен безопасного внедрения чужого контента в изолированном окружении, что полностью решило бы проблему. Есть специальный режим у IFRAME, но фреймы — это совсем не то, они не ведут себя как часть страницы, скорее как окошко в другой документ. Полосы прокрутки, развыв выделения текста и так далее. Всё не то.

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

Отпуск

С 22 июля по 7 августа мы с женой в отпуске. Маршрут выглядит следующим образом.

Москва ✈ Нижнекамск → Лениногорск → Сергиевск → Казань ✈ Москва ✈ Санкт-Петербург → Хельсинки → Таллин → Рига → Варшава → Москва.

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

Признаки того, что человек тонет

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

Рот утопающего периодически скрывается под поверхностью воды и появляется снова. Времени, которое рот находится над водой, недостаточно, чтобы выдохнуть, вдохнуть и позвать на помощь. Утопающий успевает только быстро выдохнуть и вдохнуть.

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

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

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

Из переводной статьи «Утопление не выглядит таковым». Статья стоит того, чтобы прочитать её полностью. Ещё полезно прочитать комментарии спасателей по ссылкам в конце статьи.

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

Лайфхак для стопщиков

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

Примерно то же самое происходит, когда вы едете в плацкарте, а уж тем более — когда лежите в больнице.

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

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

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

В IE10 не будет попадать под conditional comments

«Микрософт» решила, что conditional comments не должны обнаруживать IE10. То есть, по идее, условия «[if IE]», «[if IE 10]», «[if IE gt 5]» работать не должны, а «[if IE lte 9]» по-прежнему будет работать.

Поведение изменено из-за того, что этот функционал несовместим с HTML5. Ну да, в спецификации на парсер эта возможность не описана, но стоит ли её убирать? Вот уж вряд ли. Она много лет спасала верстальщиков от самоубийства.

Because some features in earlier versions of IE aren’t compatible with HTML5 parsing, we’ve removed them from IE10 mode. Sites that rely on these legacy features will still work when running in legacy modes. This way, sites that work today will continue to work with IE10 even if the developers of the site don’t have the time to update them.

Причём «Микрософт» тут же признаётся, что парсер ни при чём:

This means conditional comments can still be used, but will only target older versions of IE.

Если часть условия conditional comments всё-таки будут срабатывать, то причём тут парсер HTML5? Условия, которые оставили совместимы с HTML5, а те, которые убрали — нет?

Скорее «Микрософт» этим шагом заявляет, что «мы так всё идеально поддерживаем, что нет нужды отделять IE от других браузеров». Может быть это и так. Но я был бы рад, если бы conditional comments появились в других браузерах, а не исчезли был из IE.

Помимо этого из IE10 исчезнут Element Behaviors и XML Data Islands.

Добавлено позднее: мы тут поговорили с Вадимом Макеевым, кажется, я ошибаюсь. В режимах эмуляции старых браузеров (вероятно в этот момент работает отдельный движок), conditional comments работают, в режиме IE10 — нет.

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

Безопасная транзакция по банковской карте

Безопасная транзакция (43.42КиБ)

Какой там HTTPS, 3D Secure и прочее? Гостиница «Островок» в Санкт-Петербурге для оплаты номера банковской картой (ака «кредиткой») просит скачать с их сайта документ Word, вписать туда реквизиты вашей карты, включая код безопасности, и выслать всё это по электронной почте.

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

Немного статистики

Из 306 родственников, заведённых на сайте генелогического древа, больше всего Александров, Иванов, Валентин и Ольг.

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

Про вред пассивного курения

Наконец-то я обнаружил (случайно, правда) хоть какое-то обоснование, похожее на разумное, почему пассивное курение может быть опаснее активного:

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

Из статьи «Город некурящих», с сайта «Аргументов и Фактов».

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

Купил SD Card 64ГБ

Фото (39.28КиБ)

Готовлюсь к отпуску — купил карточку для фотоаппарата SD Card на 64ГБ. Я, конечно, сталкивался, с «коммерческим гигабайтом», но как-то обидно, что на карте на самом деле на 7,5 гигабайт меньше.

macos-x:~ bolk$ dd if=/dev/zero of=/Volumes/Photo/zero
Add: /Volumes/Photo/zero: No space left on device
118568449+0 records in
118568448+0 records out
60707045376 bytes transferred in 5609.439860 secs (10822301 bytes/sec)

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

Стань стальной крысой!

Отрывок из книги Гарри Гаррисона «Стань стальной крысой», где герой описывает, как его обманули банкиры, и он решает создать свою валюту — ДОСТ.
Стань стальной крысой!

Решил показать жене игру-книгу «Стань стальной крысой». Но оказалось, что читать и переходить по ссылкам в таком варианте неудобно.

Сделал конвертор на «Пайтоне», преобразующий книгу с «Либрусека» в HTML (может так же использовать любое «зеркало», например копию на «Флибусте».). Получается гиперигра (работает только в современных браузерах), плюс я запрограммировал простенький ДОСП (см. книгу) на JavaScript.

# coding: utf-8
import re, urllib

n, articles, skip = 0, {}, True

content = urllib.urlopen('http://lib.rus.ec/b/115854/read')

for line in content.readlines():
    line = re.sub(u'<[^>]+>', '', line.decode('utf-8'))
    
    if line.find(u'Добро пожаловать!') != -1:
        skip = False
    elif line.find(u'Оглавление') != -1:
        break
    
    if skip: continue
    
    try:
        n = int(line)
    except ValueError:
        
        line = re.sub(r'\[\s*(\d+)\s*\]', r'[<a href="#a\1">\1</a>]', line)
        
        try:
            articles[n] += line
        except KeyError:
            articles[n] = line

articles[0] = re.sub(r'\[([^\]]+)\]', r'[<a href="#a30">\1</a>]', articles[0])

t = u"""
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8" />
<title>Стань стальной крысой</title>
<style type="text/css">
html {
    background: white;
}

body {
    background: #eee; color: black;
    font: 14px/1.4em Helvetica, 'Trebuchet MS', Arial, sans-serif;
    padding: 20px;
    margin: 100px;
}

header {
    font-size: 25px;
    margin: 0 0 20px;
    padding: 0 0 5px;
    border-bottom: 2px solid #ccc;
    color: #ccc;
}

article {
    display: none;
    white-space: pre-wrap;
}

article:last-of-type {
    display: block;
}

article:target ~ article:last-of-type {
    display: none;
}

article:target {
    display: block;
}

footer {
    margin-top: 10px;
    color: #ccc;
    text-align: right;
    font-size: x-small;
}

i {
    cursor: pointer;
    background: url('data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAEBAQEBAQEBAQECAQECAgMCAgICAgQDAwIDBQQFBQUEB-
    QUFBggHBQYHBgUFBwkHBwgICQkJBQcKCgoICggJCQj/wgALCAAtACwBAREA/8QAGwAAAgMBAQEAAAAAAAAAAAAABgcEBQgCAwn/2gAIAQEAAAAB+zdD-
    Wxyy5FAAc4AtfBIfe0adbXjDJ+UuXGa9nRF1ti8ReInBsko//8QAHhAAAgMBAQADAQAAAAAAAAAABAUBAgMABhESExT/2gAIAQEAAQUC23rhXT9LxNx46Cv-
    ykUyhMdGn2s2IYV6qi9uJ0MBHqwNDJGIzLHpMQOyy23J5nWJFMr9aeTcUoBiw/lC1YyTAZND7mD5cbNddfEAVaLfTLZwpnlr8w0/DPW55FSxt22y1eMqA5340I-
    mWXp26ojyqc/wBNZSmXJBu//8QANRAAAgECAwQFCgcAAAAAAAAAAQIDAAQRITEFEhNBEBRRYaEiJDJSU3GBkbHhBkJDcsHC0f/aAAgBAQAGPwLFgWY5Ko1Y-
    1vXU5iX2cRw8dayt9/vbWsUZ4+4tvCsNJBqOiW7bPMpEOwff/KgjsVXiyEgyyejF8OdFrnat3PMeYmKD5LSx8TrGeAkbWo7tZmYqccCcjUNzFnG67wq0jGixL9K2-
    YqjzdZDLIfcMAPHw6Ix+YvRq4tZv0Z9we4qrf2q2jnUvcRebS9zrl4jA0E4W7HiDrnkcanS3Q70Z3W54HCg7XflgeguYrhKcF1Y9g5mr7ahUxxz3bsgPYFVfqpq/2r-
    aw8VpFTirjpun0vkT8qZYCt2VALKh8oD3ULYR8FPUAwxP81iIuqwevJ5K/eoPw/sKUvdSk9bm9ggOp9XuGpyq02bZpuW0KCNR0SX1lOdnXAXQDeTly5acjTWnX-
    7iXBeHiLhlGOWeHw8a6xcbae1XcCtw48ZGH7mJw05Cuq7Ot+ChO87E4tI3ax5no//8QAIxABAAEDBAICAwAAAAAAAAAAAREAITFBUWGBEHGRobHh8P/aAAgB-
    AQABPyEqxIGdgVfUsJ+Ru6gr73E/JlqZ5yH4hx1FNLcYbJueByIk0WF7E+qLSPukAzuOhxQ2XA7eIgpxNKh4mzFl5qU2VaGpHNMPBcE6UzklnNtQPJc6r2mfg/LyD0-
    H78Qb26cP5Kq0e745LoKYNx4vQZaYpG8I4IGJ9NXxDiMb26dNGYrOxr/B4cCmRDpTYK7Qdh4c0owRRcCOuIS+KSNRXOjKpqXev7Yaz9CWrIs9hBjaZWuCSLV6n-
    FkGfbmvunXUnUitIcWA4oVjEQY3zu1o9mPoOicwXIG9RPIIHstu274//2gAIAQEAAAAQ2dRilY//xAAhEAEBAAICAgMAAwAAAAAAAAABEQAhMUFRYRBxgZGhwf/-
    aAAgBAQABPxCWwNoyhKHSqoAKoFyNtZF/Ggp5TeHJYaOLr3/oYqGcsVdn0/b3llDWp5X2cUdi76XCLvgQuH7VnJHWMFrCpmiO1uCq5PGT7rUN6R+3ASpkpRBA-
    DZpsNi1wp72Lwl4AKM6c5+K8UCqnY0fY5YWk9kv6TGNaoB9kOE+G/lT8LF/k4NnJgUQ3s0thUGxBwMpLQDQaLlWnddQSJsOnKgTTCGICgXiXGrMihvNBj7PI4Kk-
    PKg1HoC/1zjTHn2P0ezQTkwAlegiHQE2iKtFDBaAq17SIHaW6x4rugOBoqKtKub+vSsjRplWzSnRjAnKRqMeUdR0AB+C0A61Tsq9riCIgEiJRMMifRjYvlnAnk5eelvIr-
    ZUqRz3rYO3LAmNdBkFRMXKK4ZalhVTlfj//Z');
    display: block;
    width: 44px; height: 45px;
    margin-top: 10px;
}

</style>
<script type="text/javascript">
function Coin(n) {
    location.hash = '#a' + n[Math.floor(Math.random() * n.length)];
}
</script>
</head>
<body>
<header>Стань стальной крысой. Гарри Гаррисон</header>
    
%(articles)s

<article id="a0">%(welcome)s</article>

<footer>Адаптировано Евгением Степанищевым. <a href="//bolknote.ru">bolknote.ru</a></footer>

</body>
</html>
"""

def dosp(v):
    v = v.strip()
    
    if re.search(u'ДОСП|(?i)случайных процессов', v, re.U):
        n = ','.join(re.findall(u'href="#a(\d+)"', v, re.U))
        
        return v + u'\n<i onclick="Coin([' + n + u'])" title="ДОСП"></i>'
    else:
        n = re.findall(u'\[[^]]+\]', v, re.U)
        
        return v + (u'\n\nИдём дальше? ' if len(n) == 1 else u'\n\nКуда дальше? ') + ', '.join(n) + '.'

welcome = articles[0]

articles = ''.join(
    '<article id="a' + unicode(k) + '">' + dosp(v) + '</article>'
        for k, v in articles.iteritems() if k
)

t = t.replace('-\n', '') % vars()
open('index.html', 'w').write(t.encode('utf-8'))

Конвертор создаёт на диске файл «index.html», который надо открыть браузером.

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

Ещё немного статистики

Почти половина (48,41%) поисковых переходов за прошедший месяц — это запросы

«петрушка наркотик»

и модификации.

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

Красавица → чудовище

Во время просмотра этого видео держите взгляд на перекрестии.

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

Исскуственное или настоящее?

Мы с женой сегодня в «Мосцветторг» ходили, покупать её коллеге букет на день рождения. Цены там действительно низкие, как и твердит реклама на каждой бумажке, валяющейся около метро. Но низкие цены — это не интересно. Интересно, что цветы, которые там продаются я перепутал с исскуственными. Пару минут я тыкал пальцами в каждый из них и спрашивал — «Этот настоящий? И этот?».

Вазочка с вязаными цветами розового и красного цвета, украшенная зелёными листьями, стоит на столе рядом с калькулятором и телефоном.
Букет из вязаных цветов в прозрачной коробке с розовой лентой и биркой «БУКЕТ», на фоне человека в красном фартуке.

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

Что мне даёт право предположить, что и всё остальное поливают какой-то специальной краской, чтобы цвета стали более насыщенными. Кто-нибудь что-нибудь знает на эту тему?

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

Третий мир

Страны третьего мира (24.63КиБ)

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

Третий мир — географический термин второй половины XX века, обозначавший страны, не участвующие прямо в холодной войне и сопутствующей ей гонке вооружений. В современном употреблении мало отличается от термина «развивающиеся страны»…

Изначально он относился к странам, которые во время холодной войны не относились ни к первому миру (НАТО), ни ко второму миру (Варшавский договор).

Отсюда, кстати, следует, что Россия (как наследница СССР) не относится к странам третьего мира, мы — второй мир, так как СССР одна из стран Варшавского договора. А картинке сверху выделены страны третьего мира.

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

Ура, спама нет!

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

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

В 2004 году появилась гугловская почта GMail, тогда ещё по инвайтам. Гугл сразу нацелилась на борьбу со спамом. Это была первейшая причина почему я захотел инвайт туда. Война со спамом велась с переменным успехом, а когда я обнаружил, что мусора стало приемлемое количество, я убрал свой замороченный JavaScript и написал email как есть.

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

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

Последний газовый фонарь Москвы

Женщина в синем платье с голубым зонтом проходит мимо книжного магазина «Медицинская книга» с арочным окном и вывеской над входом.
Последний газовый фонарь Москвы

Сегодня выполнил квест — искал последний газовый фонарь Москвы. По крайней мере утверждается, что он газовый. Понятное дело никто точно не знает последний ли он, вот я не обратил бы внимания на такую деталь арки, так что может и ещё где-то есть такие же. Более того, точно неизвестно газовый ли он, так как заляпан основательно (на фото — сразу над надписью, как элемент арки).

Такие фонари в Москве были окончательно заменены электрическими в 1932 году, значит этому фонарю должно быть около 80 лет.

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

Добавлено позднее: получил ответ от музея:

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

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

Москва ✈ Казань ✈ Москва

В пятницу вечером срочно вылетаю в Казань, пробуду по вечера субботы. Ничего особенного, рабочие вопросы.

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

33000 и анимированный GIF

Черная цифра 1 на белом фоне

По всей видимости, «Опера» немного неправильно обрабатывает анимированные «гифы».

Анимированный GIF устроен очень просто — поверх первого кадра через заданное время лепится следующий. Задержка задаётся в сотых долях секунды и, согласно спецификации, поля для её хранения имеет размер беззнаковое слово (2 байт), то есть максимальное значение — 655,35 секунд или почти 11 минут.

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

Вот я и проверил — не содержат ли кодеки популярных браузеров эту ошибку. На картике — число «1», если оно через пять-шесть минут сменится на «2», значит ошибки нет. Я выставил задержку между кадрами в 33000 (330 секунд или 5,5 минут). Кодек с ошибкой будет трактовать это число как -233 (отрицательное), поэтому кадр не сменится.

У меня на ноуте на FF 5, Safari 5.0.5, Chrome 12.0.742.122 цифра меняется, а на «Опере» 11.50 — нет. Сейчас попробую найти ноут с Windows 7 и попробую там. Попробуйте тоже на своих браузерах.

Добавлено: меняются ещё цифры на Андроиде 2.3.4, на FF 4.0.1 (Windows), а так же под Internet Explorer 9.0 и 10PP2 (Windows 7).

Добавлено ещё позднее: всё в порядке у «Оперы», разъяснил один из читателей — «Опера» начинает анимацию заново, если GIF не было видно. Дожидаясь, я переключал табы, поэтому анимация стартовала всегда сначала и «2» не появлялась. Так что ложная тревога, но любопытный факт.

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

Оператор goatse в Перле

Внезапно вспомним Перл. Когда-то я на нём много и в удовольствием программировал, причём этот навык не утерян мною до сих пор. Хотя попрограммировать на этом девиантном языке мне удаётся редко, я по-прежнему им восхищён. Немного жаль, что он умирает, но право же, чаще программы на нём можно слать в передачу «А вам слабо?», чем в продакшн.

Есть такая шутка, что Перл единственный язык, программа на котором до и после RSA-шифрования выглядит одинаково. Честно сказать, я не уверен, что это шутка, так как вот это, например, вполне разумная программа на Перле:

not exp log srand xor s qq qx xor
s x x length uc ord and print chr
ord for qw q join use sub tied qx
xor eval xor print qq q q xor int
eval lc q m cos and print chr ord
for qw y abs ne open tied hex exp
ref y m xor scalar srand print qq
q q xor int eval lc qq y sqrt cos
and print chr ord for qw x printf
each return local x y or print qq
s s and eval q s undef or oct xor
time xor ref print chr int ord lc
foreach qw y hex alarm chdir kill
exec return y s gt sin sort split

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

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

Для нас важно, что после того как картинка стала мемом, появился смайлик „=()=“, довольно точно отражающий её суть. Я знаю эту преамбулу, потому что однажды какой-то экспериментатор нашёл в Перле то, что назвали goatse operator — тот самый „=()=“, который, что интересно, позволяет делать довольно разумную вещь.

Например, вам нужно подсчитать сколько цифр содержится в строке. На помощь вам придёт goatse operator!

my $s = "Hello, world! This is a Perl! 123456";
my $c =()= $s =~ /\d/g;
print $c;

В результате будет напечатано число шесть.

Как это работает и почему нельзя как-то иначе?

Сначала отвечу на первую часть.

Самое правое выражение в рассматриваемой строчке — регулярное выражение, которое ищет одну цифру, оператором «=~» мы применяем его к конкретной переменной, а ключ «g» в конце регулярки говорит, что искать надо все вхождения.

В Перле есть понятие скалярного и списочного контекста. Результат может сильно отличаться в зависимости от того ожидается ли в каком-то месте кода скаляр или список (массив). Программист даже может проверить в каком контексте вызвана его функция при помощи специальной функции «wantarray».

Например, если я попробую напрямую присвоить результат выполнения регулярного выражения на переменной „s“ в скалярную переменную (начинается с доллара), то я получу флаг, показывающий встретились ли вообще цифры в рассматриваемой переменной. Если же присвоить тот же результат массиву (имя переменной начинается с «@»), то я получу массив совпадений.

С goatse operator происходит следующее.

На деле «() = что-то ещё» — это обычное присваивание массиву чего-то ещё. Пустые скобки — пустой анонимный массив, ему тоже можно что-то присвоить, синтаксис это позволяет. Таким образом контекст не скалярный и мы всего-то присваиваем одному массиву другой. Дальше чуть интереснее. По правилам Перла присваивание первого массива второму в скалярном контексте возвращает количество элементов первого.

Получается «SCALAR = LIST0 = LISTREGEXP», что возвращает нам количество элементов массива LISTREGEXP при любом не константном LIST0. Двумя присваиваниями, идущими подряд, вряд ли кого-то удивишь, цепочки присваиваний можно использовать в Си, JavaScript, PHP и куче других языков.

Теперь ответ на второй вопрос. Нельзя ли как-то иначе. Можно. Если религия вам не позволяет использовать «оператор» с такими сомнительными ассоциациями, то можно, например, присвоить результат работы регулярного выражения переменной-массиву, а потом взять его в скалярном контексте. Как-то так:

my $s = "Hello, world! This is a Perl! 123456";
my @c =$s =~ /\d/g;
print scalar @c; # массив в скалярном контексте вернёт количество элементов

Но это скучно.

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

Макбук под рентгеном

Макбук и фотоаппарат (37.16КиБ)

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

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

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

location.reload() ≠ location.href=location.href

Увидел у Никиты Васильева во внутренних бложиках, что вызов «location.reload()» не эквивалентен присваиванию location.href в себя же. Оказывается, последний перезагружает страницу из кеша во всех браузерах, кроме «Оперы».

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

Не хочу я выключать ноут в самолёте-2

Помните мы обсуждали нужно ли выключать технику в самолёте?

Я сегодня летел бизнес-классом S7 (завтра проверю ещё в бизнес-классе «Аэрофлота»), там техникой можно хоть обложиться. Рядом со мной, на столике стоял мой включенный ноутбук и я читал с телефона. Ни одна стюардесса ни разу не сделала мне замечание. Хотя о том, что технику надо выключать объявили на весь салон.

Через проход сидел дядька, смотрел с «айПада» какой-то фильм, за ним сидела женщина, у неё тоже какая-то электроника светилась.

В двух сидениях позади меня техникой пользоваться уже нельзя (я не раз летал рейсами S7), хотя я ближе к кабине (собственно, на рейсовых самолётах я в первый раз в жизни летел в первом ряду).

Дополнено позднее: обратно летел совместным рейсом «Аэрофлота» и «Дон-Авии». Самолёт принадлежит «Дон-Авии», при взлёте и посадке техникой пользоваться запретили.

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

Плагины по запросу в «Опере»

Плагины по запросу (27.46КиБ)

Хочу похвалить «Оперу» за галочку в настройках, которая недавно появилась. С ней стало удобнее. Теперь можно выключить плагины (Flash, Java, Silverlight и остальное, в куче) для всех сайтов разом, а потом включить их для определённых сайтов (YouTube, RuTube, video.yandex.ru и так далее) в отдельных «Настройках для сайта» (открывается по клику правой на странице).

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

Очень удобно. Спасибо, ребята!

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

Сравнение объектов встроенных типов в Пайтоне

Некоторым ребятам показалось, что в заметке про «goatse operator» в Перле я поругал этот язык. Это не так, можно прочитать заметку от и до, чтобы в этом убедиться. Мне очень нравится Перл, но это язык не для современного продакшна. Давайте я что-нибудь забавное расскажу и о языке, на котором больше всего сейчас программирую — про Пайтон.

В Пайтоне всё что только можно — объект и нет примитивных типов. С объектами можно делать всё что хочется — сравнивать, умножать, производить битовые операции. Чтобы программист мог указать как объекту следует себя вести рядом с каким-то оператором, следует определить некоторые «магические» методы, например, «__cmp__», «__mul__» и какой-нибудь «__xor__».

Где-то внутри какие-то «магические» методы определены и для встроенных типов (которые тоже являются объектами, напоминаю), ведь надо же как-то сравнивать две строки или строку и число:

In [26]: "Это строка".__eq__
Out[26]: <method-wrapper '__eq__' of str object at 0x10136f770>

In [27]: "Это строка".__ne__
Out[27]: <method-wrapper '__ne__' of str object at 0x10139cf70>

Сравнивать между собой можно большинство встроенных типов — список с со словарём, строку с кортежем и так далее. Есть исключения (например, set нельзя сравнить ни с чем, кроме set и frozenset), но их мало. Какой же будет результат сравнения? Давайте попробуем:

In [44]: "">()
Out[44]: False

In [45]: ""<()
Out[45]: True

In [46]: []>()
Out[46]: False

In [47]: []<()
Out[47]: True

In [48]: []<{}
Out[48]: False

In [49]: []>{}
Out[49]: True

Даже пустые объекты разных типов не равны между собой, но какое-то правило определённо есть, не случайным же образом создатели языка выбирали что больше чего. Добавление значений в объекты ситуацию не меняет, не играет роли их число и значение. Я намеренно оставляю в стороне числа (типы int, float и complex) и лишь походя затрагиваю строки (str и unicode), там как там правила немного другие, но это неважно.

In [52]: [1,2,3,4,5,6]<(0,)>[100000]
Out[52]: True

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

True < {} < [] < object() < "" < () < u""
# b < d < l < o < s < t < u

Решение мне кажется, мягко говоря, неудачным, но уж какое выбрали. Я не вижу ничего страшного в том, чтобы сравнение встроенных типов всегда выдавало False (попробуйте сравнить между собой два None) или выдавать исключение при попытке их сравнения (кажется в 3-й версии Пайтона так и сделали).

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

Как вам, жаворонкам, живётся?

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

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

Макакин копирайт

Макака-кривляка (105.63КиБ)

Фотографии макаки, которая якобы сфотографировала себя на фотоаппарат, случайно оставленный каким-то фотографом, видели многие. Если не видели, то выше одна из них, остальные можно посмотреть, на сайте «Daily Mail», например.

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

Итак, фото сделано макакой. Внимание вопрос: кому принадлежат копирайты на данные фотографии?

Вроде бы очевидно, что это теперь общественное достояние, так как фотограф (по первой озвученной версии) случайно оставил фотоаппарат и на кнопку нажимало (являлось автором творчества) живое разумное существо (пусть и с низким IQ), права которого не регулируются законами о копирайте.

Тем не менее, фотограф, которому принадлежит фотоаппарат и агенство, которому были (я так думаю) проданы снимки не согласны. Интересно будет посмотреть за развитием событий.

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

У клиента дохлый канал?

В 1997 году, когда я впервые увидел веб через графический браузер (до этого у меня был опыт выхода в интернет через терминал на базе i80286 через текстовый браузер Lynx), у меня была выделенка, дело было в Казанском Государственном Университете и ещё очень долго я не знал что такое диалап и оплата за трафик.

Сейчас выделенки у большинства, но нередко встречается и такое, что клиент приходит на сайт через «дохлый канал» или с оплатой по трафику (например, через сотовый телефон).

Хорошо было бы об этом как-то узнать и не грузить клиенту лишние подробности в этом случае. Браузеры такое API не предоставляют (ещё бы, они и сами ничего не знают про канал), такую обобщённую информацию получить неоткуда. Но можно попытаться об этом догадаться. Эта запись — сборник моих сырых мыслей на эту тему.

Я вижу несколько путей.

  • можно замерить время за которое страницу удалось отдать клиенту целиком. У меня пока нет оформившихся мыслей о том как это делать и есть недостаток — когда мы узнали о том, что у клиента плохой канал, содержимое уже выдали, ничего поменять нельзя. Можно выдавать chunked-контент, как предлагал Сергей Чикуёнок, но первый кусок должен быть значительным
  • после загрузки страницы «пропинговать» хост. То есть обратиться через XHR на свой же сайт и замерить время ответа. Опять же, что делать с этими данными? Есть возможность в следующий раз показать более бедное содержимое, но следующий запрос может идти через другой канал. Возможное решение — сохранять IP-адрес запроса
  • смотреть с какого браузера клиент приходит, если это «Опера Мини», вероятнее всего, канал плохой или с оплатой
  • опять же «Опера», если включена функция «Опера Турбо» (определяется по IP-адресу клиента), клиент экономит трафик, значит канал с оплатой
  • проверить грузятся ли картинки, способов много, но данные получаем постфактум, после загрузки страницы. Логика та же — выключил картинки, экономит. Загрузку Flash контролировать смысла не имеет — многие выключают, чтобы не видеть рекламы
  • проверять не пришёл ли человек через канал сотового оператора (по IP-адресу). Безлимиток, которые бы не деградировали по скорости после какого-то лимита пока исчезающе мало, так что имеет смысл отдавать в этом случае «обеднённый» контент. Мобильные браузеры определять смысла не имеет — клиент может прийти через WiFi
  • в комментариях подсказали, что в «Андроидах» 2.2 и выше есть специальное
    API, чтобы определять способ подключения
  • ещё вариант из комментариев — определять модель телефона/планшета и по базе смотреть есть ли у него GSM/3G или WiFi
    Кто-нибудь ещё какие-то пути видит?

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

Кодировка rot13 в Пайтоне

В стандартном интерпретаторе Пайтона есть много такого, что иначе как «пасхальным яйцом» не назовёшь. Например, можно попробовать импортировать модули «__hello__», «this» или сделать «from __future__ import braces» (попробуйте), но следующее просто гениально, хотя, видимо, получилось случайно.

В файле программы на Пайтоне в специальном коментарии принято указывать кодировку файла. В случае с латиницей работает и без этого, если применяется UTF-8, то это делать обязательно. Интерпретатор поддерживает множество кодировок (честно сказать, я не знаю сколько именно) и одна из них — rot13. Используются те же самые кодировки, что и в методах encode и decode у строки. Я думаю после считывания файла программы именно они и вызываются.

Вот вполне валидная программа, которая выполняется и делает нечто осмысленное:

# coding: rot13

vzcbeg __uryyb__
cevag "Zl anzr vf Ritral Fgrcnavfpuri nxn Obyx!".rapbqr("rot13")

Кодируется только текст программы, поэтому-то мне и пришлось «rot13» написать как есть.

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

Проверка типа соединения в «Андроидах»

Оказывается в «Андроидах», начиная с версии 2.2 есть специальное свойство у navigator.connection, которое позволяет узнать тип соединения: «navigator.connection.type». Объект «navigator.connection» содержит так же несколько констант, с самодокументируемыми названиями, которые содержат все возможные значения типа соединения: UNKNOWN, ETHERNET, WIFI, CELL_2G, CELL_3G.

with (navigator.connection)
if (type == CELL_2G || type == CELL_3G) {
    // медленное и/или платное
}

На последней, на данный момент прошивке iOS на iPhone 4, увы, это свойство не поддерживается.

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

JPEG vs. DjVu

Мне кажется, формат DjVu получает незаслужено мало внимания. Те, кому надо хранить документы, делают это, чаще всего, в JPEG или TIFF (а то и в PNG), а об DjVu вообще мало кто слышал. Я взял первый попавшийся в поиске документ, чтобы проиллюстрировать всю мощь формата.

JPEG vs. DjVu (69.42КиБ)

Картинку я уменьшил (до 636 по ширине) и сконвертировал в два формата. Слева на картинке JPEG, справа DjVu. Картинка в JPEG занимает 85КБ (качество — 85%, сжато jpegtran), в DjVu — 13КБ (качество — «normal», сжималось any2djvu). Выигрыш в 6,5 раз при сходном качестве.

За счёт чего достигается такой результат?

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

Поэтому обрабатываемое изображение разделяется на три слоя: фон, передний план и маску. По сути, изображение разделяется на две части: то, что будет сохранено с низкой детализацией (иллюстрации и фон) и то, что с высокой детализацией (текст). Маска нужна, чтобы при просмотре наложить одно на другое. Обе части сжимаются вейвлет-преобразованием, но с разным качеством, а маска (она однобитная) сжимается алгоритмом JB2.

Эффективность сжатия DjVu сильно зависит от того есть ли на картинке задний фон, если его нет и изображение только чёрно-белое, то размер отсканированной страницы в разрешении 600dpi (говорит нам Википедия) — всего 15КБ!

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

Спяааат устааалые игрушки, книжки спяааат…

Сегодня скрипач в метро, в переходе с Театральной на Охотный ряд играл «Спят усталые игрушки…». А у меня рефлекс ещё с советских лет, я же в детстве смотрел «Спокойной ночи, малыши!», там если играла эта музыка, то всё, Хрюша и Степашка прощаются с вами, пора спать. Весь рабочий настрой с утра сбил! Нельзя так, товарищ!

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

☁☁ ✈ ☁☁ ☀

Мы тут с женой в отпуск собрались, не теряйте! Как получится писать не знаю. Повторяю маршрут, если что. Сегодня в 22:40 вылетаем.

Москва → Нижнекамск → Лениногорск → Сергеевск → Казань → Москва → Санкт-Петербург → Хельсинки → Таллин → Рига → Варшава → Москва

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

По родным

пробабушка Вера (39.20КиБ)

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

Больше всего меня поразило, что́ сельский фельдшер «прописал» её сестре, Вере в качестве лечения от кори. Его «рецепт» заключался в том, чтобы занавесить окна красным. Девочка умерла, в восемь лет, шёл 1946 год.

На фотографии — монашка Вера Гусева (справа), это уже другая Вера, двоюродная сестра Пелагеи Евдокимовой, мамы мужа уже упомянутой моей двоюродной бабушки Вали.

Оставить комментарий

Как я расслабляюсь

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

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

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

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

Мать-ехидна

Ума нет (45.98КиБ)

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

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

Здравствуй, Питер!

Питер (59.74КиБ)

Здравствуй, ночной Питер! Расположились на тринадцатом этаже, в хостеле «Островок». Хороший, чистый хостел с бесплатным WiFi. Горизонт завален, сил ни на что больше нет, пойдём спать.

P.S. Это не белые ночи, это выдержка 30 секунд.

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

Питерское метро

Питерское метро (46.49КиБ)

Мы в Питере второй раз, а в метро — в первый. По сравнению с московским станции скучные или мы были на какой-то неправильной ветке (поднялись по синей и проехали две станции по зелёной, сидим недалеко от Финского залива).

Сильно поразили выходы на некоторые станции — останавливаешься в тоннеле, вдруг стена открывается и через двери видно станцию. Безопасность выше, но иногда неудобно — если сидишь в первом вагоне, то не все двери могут открыться, для самых первых таких «ворот» в стене может не оказаться.

А вот странность — купил карточку на 10 поездок, оказалось, что между активациями должно проходить не менее 10 минут. В Москве иначе — я могу по карточке пройти хоть 10 раз подряд или провести 10 человек. С чем связано это ограничение я не понимаю.

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

Новая «Лада»

Новая «Лада» (77.04КиБ)

Три года назад, в 2008 году, я снял на выставке в МВЦ новый автомобиль компании «Лада». А сегодня увидел его в бизнес-линче Лебедева. Написано, что это «новый кроссовер „Лада Си-Кросс“». Как же он новый, если ему три года?

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

Хостел

До недавнего времени я не знал что такое «хостел», кажется до той самой поры, когда Илья Бирман в гостях у Инфотаньки не оборонил, что остановился в хостеле.

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

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

Расскажу о последнем, чтобы вы имели представление о том, какие бывают хостелы.

Сначала недостатки.

Это центр, пять минут до Невского проспекта и даже ночью тут кипит жизнь, что в открытое, по причине жары, окно слышно превосходно. А ещё в окно влетают, одурев от такого гостеприимства, прыткие питерские комары. Так что ночь сегодня была тяжёлая. А так же, нам всё равно, но для многих недостаток — нет телевизора (в «Островке» — был).

Около хостела (95.49КиБ)

Достоинства.

Вокруг красиво, из окна нашего шестого этажа видны исторические здания и скверик с памятником Пушкину, внутри хостела чисто, ходят в тапочках, можно купить за 50 рублей персональные или воспользоваться бесплатно «общественными». У нас на этаже есть кухня с бесплатным чаем и кофе, бесплатные же фен, стиральная машинка, сушилка, утюг и гладильная доска. Настоящее спасение — две хорошие душевые кабины, одна из них с радио. Чуть не забыл — бесплатный WiFi.

Что есть в номере.

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

Сейфа нет, поэтому по городу мы гуляем, взяв всё самое ценное, а шмотки лежат в номере.

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

Океанариум в Питере

Группа оранжевых и золотых карпов кои плавает в прозрачной воде над песчаным дном среди темных камней.
Женщина в профиль смотрит на большую рыбу осетра в аквариуме, где также видны другие рыбы и декорации из камней и дерева.
Крупный план серебристой пираньи с красными плавниками, плавающей среди зелёных водных растений в аквариуме; на заднем плане видны другие рыбы.
Яркая оранжевая дискуса с белыми узорами и красными глазами плавает в аквариуме среди зелёных растений и других рыб.
Крупный план головы и части тела арованы с крупными серебристыми чешуйками, плавающей в аквариуме на фоне камней и зелёных водорослей.
Женщина и девочка смотрят на огромную аровану в аквариуме с водорослями и корягами.
Два длинных морских угря (один жёлто-полосатый, другой чёрно-жёлтый) плавают среди камней и двух красных креветок-чистильщиков в аквариуме.
Пёстрый морской лев с длинными ядовитыми плавниками и полосатым телом плавает в аквариуме на фоне камней.
Крупный план краба с длинными оранжевыми клешнями, выглядывающего из круглого окна в оранжевой стене аквариума; на заднем плане видны другие морские обитатели в воде.
Подводный вид: два химеровидных существа с длинными хвостами и одна оранжевая морская звезда на песчаном дне среди камней.
Акула плывёт в аквариуме, вид снизу вверх; на поверхности воды — блики от освещения, в глубине — другие рыбы и камни.
Крупный план фиолетовой рыбы-тигра с характерным клювообразным ртом и чешуёй, плавающей в аквариуме на фоне размытых кораллов и камней.
Белая скат-хвостокол плывёт в аквариуме, подняв голову вверх, на фоне камней и размытой водной среды.
Крупный план наутилуса с полосатой раковиной и щупальцами, плавающего в аквариуме под фиолетовым светом.
Девочка и женщина смотрят на тюленей в аквариуме: один плывёт у скалы, другой всплывает, выпуская струю пузырей.

До свидания, Питер! Сегодня поедем в Хельсинки, поезд через два часа.

Напоследок побывали в океанариуме, красиво — безумно.

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

← сюда туда →