LE Blog

Инженер с поэтической душой

03.05.2010 firtree_right Вакансии

Я ищу двух толковых ребят:

  1. Программист на C (хорошая школа обращения с памятью :)) Его задача — переписать с нуля наш rubygem gphoto4ruby, чтобы он работал:
    • Поверх libusb, а не поверх libgphoto2. У меня есть множество тестовых примеров.
    • Максимально позволял работать с протоколом из ruby. То есть спецификацию камеры читает ruby-программист, а не C-программист, которого я ищу.
  2. Программист на ActionScript чтобы написать на AIR оффлайновое API географических карт с рядом специфических требований.

Можно падать в комментарии или на почту kruk{at}neq4.ru. Если вас читают такие толковые ребята, то не грех и перепостить. :)

28.04.2010 firtree_right Использование Airake под Kubuntu

simple things

Введение

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

Я люблю руби. И, естественно, rake, как инструмент, продолжающий славные традиции make в руби и с помощью руби. Так же я питаю нежные чувства к ActionScript. Мне нравится AIR, который позволяет писать действительно кросс-платформенные приложения довольно быстро. Так же я неплохо отношусь к TDD, как к одному из способов разработки.

Какова же была моя радость найти инструмент, который всё это объединяет! Хотя ему уже пара лет, он по-прежнему прекрасен.

Установка составляющих

Предполагаю, что ruby, rubygems и rake уже установлены у тех, кто читает этот блог.

Далее, качаем и разархивируем куда-нибудь Adobe AIR SDK и Adobe Flex SDK (или предыдущая версия, если вы консерватор), а так же устанавливаем Adobe AIR Runtime. Чтобы установить последний, после загрузки bin-файла нужно:

chmod +x AdobeAIRInstaller.bin
sudo ./AdobeAIRInstaller.bin

Теперь добавим в PATH пути к исполняемым файлам загруженных SDK. В .bashrc добавляем:

export PATH="/path/to/air_sdk/bin:$PATH"
export PATH="/path/to/flex_sdk_4/bin:$PATH"

Так же потребуется установить java для того, чтобы на ней работал компилятор:

sudo apt-get install sun-java6-jre

После установки, независимо от того, используете вы Flex3 или Flex4, нужно переписать содержимое AIR SDK поверх Flex SDK. Мне не совсем понятен сакральный смысл этих действий, но иначе ничего не работает.

Привѣтъ, Мiръ!

Создание пустого air-приложения теперь просто:

airake airake_hello_world

Чтобы запустить его, однако, следует исправить в src/AirakeHelloWorld-app.xml и test/Test-app.xml:

...
xmlns="http://ns.adobe.com/air/application/1.5"
...

Если вы решили использовать Flex4, то вам необходимо отредактировать сгенерированное приложение, чтобы запустить его. Это связано с изменениями в стилях. Поэтому проще просто удалить всё содержимое тэга WindowedApplication в файле src/AirakeHelloWorld.mxml.

Про использование TDD в ActionScript я уже писал, поэтому подробно останавливаться не буду. Для примера в код на github включён тривиальный тест. Запуск тестирования происходит привычным образом:

rake test

Документация, если вы пишете правильные комментарии ASDoc, тоже запускается привычным образом:

rake docs

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

rake -T

Использование rake

Конечно, вся прелесть rake не только в привычных и коротких командах для разработки, но и в том, что можно создавать свои сценарии. Например, вот как могла бы выглядеть работа с версиями приложения. Добавим в файл raketasks/version.rake следующий код:

require 'yaml'

desc "Print out current version"
task :version do
  if md = File.read(YAML.load_file('airake.yml')["appxml_path"]).match(/<version>(.*)<\/version>/)
    puts "Current version is #{md[1]}"
  else
    raise "Cannot detect current version.\nMake sure appxml file contains <version>X.X.X</version> tag."
  end
end

namespace :version do

  [:major, :minor, :patch].each do |subv|
    desc "Bump #{subv} in version"
    task :"bump_#{subv}" do

      unless `git status` =~ /nothing to commit/
        raise "There are uncommitted changes. Failed to proceed."
      end 

      appxml = YAML.load_file('airake.yml')["appxml_path"]
      str = File.read(appxml)

      msg = nil
      new_version = nil

      if str.gsub! /<version>(.*)<\/version>/ do |matched|
        old_version = $1
        major, minor, patch = old_version.split(".").map(&:to_i)
        eval("#{subv} += 1")
        new_version = [major, minor, patch].join(".")
        msg = "Version bump #{old_version} => #{new_version}"
        puts msg
        "<version>#{new_version}<\/version>"
      end.nil?
        raise "Cannot detect current version.\nMake sure appxml file contains <version>X.X.X</version> tag."
      else
        File.open(appxml, "w") do |f|
          f.write str
        end

        puts `git commit -am "#{msg}"`
        puts `git tag v#{new_version}`
      end
    end
  end
end

А в Rakefile соответственно:

# Custom rake tasks
Dir.glob("raketasks/*.rake").each { |rf| load rf }

Теперь мы можем привычным образом работать с версиями приложения (а версии эти потом будут распознаваться установщиком обновлений):

rake version
rake version:bump_major
rake version:bump_minor
rake version:bump_patch

И это не предел!

Материалы для самостоятельного изучения

  1. Полный код статьи на github
  2. Инструкция по работе с airake, которая во многом повторена в этой статье с добавлением манипуляций, чтобы всё заработало.
  3. Документация по FlexUnit. Не уверен, что в поставке airake идёт самая последняя версия, но ничего не мешает написать rake task для обновления версии FlexUnit :)
  4. Документация по rake

27.04.2010 firtree_right Новьё

Новый постик в бложек лежит в черновиках. Не публикую ничего в начале и в конце недели. От Яндекса научился, хоть моя аудитория и поменьше :) На прошлой неделе не успел ничего написать из-за РИФа. Был там один день, но как докладчик, поэтому выпала первая половина недели, а не вторая.

Очень понравилась в последнее время концепция «достижений» (achievments) в играх и всём подряд. Например, Mass Effect 2 я проходил три раза, чтобы не только спасти всех компаньонов в самоубийственной миссии (no one left behind), но и сохранить их лояльность. А Portal начал проходить ещё раз, чтобы получить достижение «transmission received». Так же отлично это работает и в социальных сервисах. Например, в foursquare уже довольно подробно размечена вся Москва, потому что за внесение и посещение мест на карте дают очки, звания и знаки отличия. Например, сегодня я стал мэром «Улицы ОГИ». Павел «Ксан» Яковлев заявил, что социальным сетям типа Фейсбука или МоегоКруга следует создать для владельцев профилей Компаний систему достижений для их работников. Тогда работники компаний будут вполне себе мотивированно добиваться этих достижений, чтобы их было видно в профиле.

Ещё, с тех пор, как я приобрёл новый телефон мечты (HTC Desire), всё чаще мне попадаются упоминания и примеры Augmented Reality. Например, Google Goggles — пока мне не удалось получить от них много удививших меня результатов. Но он хорошо определяет продукты по баркодам. Если сфотографировать логотип Яндекс, то будут ссылки на википедию про Интернет и Историю Интернета, А если логотип Гугла, то ссылки будут на Гугл :). Однако второй пример поразил воображение не смотря на простоту. Карта звёздного неба от Гугла. Смотришь на небо через телефон, и все созвездия, звёзды и планеты подписаны. Это зашибись просто! Всего то нужно определить местоположение (по GPS или триангуляцией) и время с календарём. Потом акселерометр сообщает, как повернуть сферу.

А что нового у вас?

19.04.2010 firtree_right 10 000

Когда я сделал себе и Ире сайты, то решил, что у меня есть вполне себе универсальное нечто, что можно легко подстроить под определённый круг нужд. Если бы не обещанное друзьям портфолио, то я бы так и не узнал, насколько мысль о гибсоти и лёгкости настройки далека от истины :) Сегодня выставил его для тестирования — бОльшая часть работы сделана, ура!

В связи с этим часто вспоминаю правило 10 000 часов, о котором узнал из книжки Outliers (ссылка на русское издание, но читаю на английском). Её автор Malcolm Gladwell ссылается на невролога Daniel Levitin, который описал свои исследования ещё в 2006 году в книге This is your brain on music.

Исследования последнего показали, что чтобы стать экспертом мирового уровня в любом деле, необходимо 10 000 часов практики. Нет ни одного признанного мастера мирового уровня, который бы практиковался меньше, чем его конкуренты, при этом их опережая. [Это утверждение работает в обе стороны.] Первый же приводит известные примеры типа Билла Гейтса, «Битлз» и Моцарта, подтверждающих своей биографией это правило. [Кроме всех прочих тонкостей этих конкретных биографий.]

А вспоминаю я это правило в том ключе, что у меня присутствует необоснованное ожидание от себя, что всё получится сразу и круто. Поэтому когда не получается, то я здорово удивляюсь. Потом, конечно, вспоминаю, что практика прежде всего. Да. :)

З.Ы. На мероприятии Яндекса на РИФе мы с Артёмом будем рассказывать о наших технологиях съёмки и обработки панорам улиц. Корпус №6, зал №6, 21 апреля в 14:00.

09.04.2010 firtree_right Злободневно

Только ленивый не высказался сегодня про свинью, которую Apple подложил Adobe'у, внеся в лицензионное соглашение пункт, делающий бесполезной новую разработку Adobe во Flash CS5. Я никогда не разрабатывал под iPhone и, к счастью iРазработчиков, вряд ли буду. :) Фанаты Apple возрадуются, что толпы флэшеров не ринутся на их телефончики. Мой же взгляд давно направлен в сторону Android, и, наконец, я знаю, какой аппарат я куплю, когда он выйдет.

Самое интересное во всём этом — находится в будущем. Учитывая нынешнюю скорость развития технологий, это будущее не так далеко. Речь идёт о стратегических последствиях принятых решений. Стоит, к примеру, упомянуть историю конкуренции VHS и Betacam. Как открытие спецификаций сделало популярным VHS, вытеснив Betacam в сферу профессиональной видеозаписи. Меж тем, VHS уже почил, а Betacam ещё жив в своей нише. Хотя есть мнение, что наибольшее распространение получает тот формат, который выбирают производители порнографии. Возможно именно так разрешилась битва между Blu-ray и HD DVD.

Не смотря на все крики сторонников и противников, немедленных последствий для компании Apple, конечно же, не последует.

07.04.2010 firtree_right Немного о $SAFE

secure code

Введение

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

Нежная безопасность

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

print "child: "
child = gets.chomp
puts "child tainted: #{child.tainted?}"
(0..4).to_a.each do |i|
  puts "SAFE: #{i}"
  $a = "safe"
  th = Thread.new do
    $SAFE = i
    child_copy = child.dup
    Thread.current[:out] = ""

    begin
      load child_copy
      Thread.current[:out] += "1. Child loaded\n"
    rescue SecurityError => e
      Thread.current[:out] += "1. Security error: #{e.to_s}\n"
      begin
        child_copy.untaint
        load child_copy
        Thread.current[:out] += "2. Child untainted and loaded\n"
      rescue SecurityError => e
        Thread.current[:out] += "2. Security error: #{e.to_s}\n"
        begin
         Thread.current[:out] += "3. Read from file '#{child_copy}': '#{File.read(child_copy)}'\n"
        rescue SecurityError => e
          Thread.current[:out] += "3. Security error: #{e.to_s}\n"
          begin
           Thread.current[:out] += "4. Read from untainted file: '#{File.read("child.rb")}'\n"
          rescue SecurityError => e
            Thread.current[:out] += "4. Security error: #{e.to_s}\n"
          end
        end
      end
    end

    begin
      $a = "modified"
      Thread.current[:out] +=  "5. Global variable modified: $a = '#{$a}'\n"
    rescue SecurityError => e
      Thread.current[:out] += "5. Security error: #{e.to_s}\n"
    end

    begin
      Dir.mkdir "test"
      Thread.current[:out] += "6. Created directory 'test': #{File.exist?("test")}\n"
      Dir.rmdir "test"
    rescue SecurityError => e
      Thread.current[:out] += "6. Security error: #{e.to_s}\n"
    end

    begin
      Thread.current[:out] +=  "7. Dir glob: #{Dir.glob(File.join("..", "*")).inspect}\n"
    rescue SecurityError => e
      Thread.current[:out] += "7. Security error: #{e.to_s}\n"
    end

    begin
      Thread.current[:out] +=  "8. System ls output: '#{`ls`.chomp}'"
    rescue SecurityError => e
      Thread.current[:out] += "8. Security error: #{e.to_s}\n"
    end
  end
  th.join
  puts "Global variable: $a = '#{$a}'"
  puts th[:out] if th[:out]
end

Конструкция со Thread.current[:out] используется потому, что для $SAFE >= 4 нельзя ничего писать ни в какие устройства вывода.

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

Кстати, когда ещё github работал как репозиторий библиотек, спецификация gemspec выполнялась там под $SAFE = 3. Для разработчиков это выливалось в то, что нужно было перечислять все файлы своей библиотеки вручную вместо использования какого-нибудь листинга.

Суровый гайдлайн

Конечно же, только использование $SAFE не убережёт от действительно настойчивой атаки или блокирующего кода. Например:

Thread.new do
  $SAFE = 2
  class String
    def ==(other_string)
      true
    end
  end
end.join
puts "string modified: #{'a' == 'b'}"

И это на втором уровне! А на третьем открыть класс тоже можно, но вызов перегруженного оператора будет вызывать SecurityError.

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

Это не значит, что этой переменной нет применения в жизни прогрессивного человечества. Адекватное текущему состоянию применение — это гайдлайн при разработке. Руководство для программистов, которое само следит за своим исполнением. Жестковато, но зато действенно. :)

Материалы для самостоятельного изучения

  1. Код примеров в статье на github
  2. Старая, но самая подробная документация по $SAFE
  3. Просто дополнительно: шпаргалка по руби

01.04.2010 firtree_right Соха

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

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

А на моё место в компанию нек4 нужен толковый на все руки программист. Знание ruby и ActionScript 3 необходимо. Умение самостоятельно удерживать часть проекта без дополнительного контроля тоже необходимо. Зарплата на уровне. Заинтересованным — падать в каменты.

30.03.2010 firtree_right Рационально

Вот интересно, сколько людей умерло в последние 10 лет от инфаркта, рака, передозировки наркотиков и алкоголя, укуса змей, колёс автомобиля, рук хулиганов и бандитов, взрывов бытового газа и, наконец, голода и холода? Совершенно точно больше по каждому пункту, чем от кое-чего на букву «т», вопрос лишь во сколько десятков-сотен раз.

Где новости по первому каналу, почему не приняты меры? Почему мне не звонят проверить, не умер ли я от удара током или подавившись блинчиком?

28.03.2010 firtree_right Блоггерские будни

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

24.03.2010 firtree_right Процесс приёма правок в проекте с открытыми исходниками

opensource

Введение

Для работы в проекте с открытыми исходниками весьма удобна распределённая система контроля версий. Я использую git. Понятно, что есть процесс с использованием патча, высылаемого по почте, но этот процесс не является эксклюзивным для распределённой системы контроля версий. Поэтому я опишу процесс с так называемым pull request.

Постановка задачи

Пишет мне некто Tallak Tveide, сообщая, что он сделал копию моего проекта у себя на github и внёс несколько правок, которые ему были необходимы, и от которых другие ребята, пользующиеся этой библиотекой только выиграют. Ветка, в которой находятся нужные мне правки, называется eos_40D_bugs. Это довольно кстати, что нашёлся человек с Кэноном, потому что я испытываю всё на Никонах :)

Каковы же мои действия?

Решение

Заходим в наш локальный рабочий репозиторий и добавляем новый источник правок:

git remote add tallakt git://github.com/tallakt/gphoto4ruby

Теперь рассмотрим правки:

git fetch tallakt eos_40D_bugs:develop

Эта команда заберёт из репозитория tallakt с ветки eos_40D_bugs исправления и создаст локальную версию в локальной ветке develop. Чтобы увидеть исправления:

git diff develop

Что выдаст нам исправления относительно текущей ветки.

git checkout develop

Чтобы работать с правками и тестировать то, что получилось.

Если я пока не готов сливать исправления с основной веткой master, но хочу ещё поработать с этим из разных мест, то мне нужно создать ветку develop в моём центральном репозитории на github, который относительно локальной копии у меня обычно называется origin.

git push origin develop

Это создаст ветку develop на удалённом репозитории, с которой я потом смогу работать из другого локального репозитория, выполнив:

git pull origin develop

После того, как я доволен изменениями и хочу сделать официальный релиз:

git merge master
git branch -d develop
git push origin master
git push origin :develop

Первая команда, предполагая, что текущая ветка — develop, сливает её в master. Вторая команда удаляет локальную ветку develop. Третья команда отправляет изменения в ветку master на центральном репозитории. Четвёртая команда удаляет ветку develop на центральном репозитории.

Материалы для самостоятельного изучения

  1. Несколько шпаргалок от github
  2. Дельная документация по git

Послесловие

Как вы заметили, в этом году мои статьи сопровождаются прекраснейшими тематическими картинками авторства Ирины Троицкой — моей прекрасной супруги. Её перу также принадлежит дизайн сайта и логотипа.