среда, 3 сентября 2014 г.

ICFPC-2014 - результаты

Ну вот и опубликовали результаты. Какой итог - в общем зачёте заняли 44 место из 142 команд. В молниеносном раунде 53 место из 94 команд. Ну, в 20-ку не попали, но в первой трети. :)

пятница, 22 августа 2014 г.

Nagios, нотификация по jabber (xmpp), sms и языковый интернационал

В общем, есть программа nagios для мониторинга, в ней есть нотификации о падении сервисов (ну и вообще настраивается). И можно даже гибко добавлять то, что нужно. Самое удобное - jabber (xmpp) и sms. email у него из коробки есть. Да и email отправляет в очередь почтового сервера, а вот если просто использовать скрипты для отправки, то может случиться так, что нет инета, недоступен сервер jabber или sms api. Но при этом скрипт отработал, хоть и вывалился с ошибкой. С отправлением на email всё понятно. Там отправляется всё на почтарь и висит в его очереди. Что ж. Нам тогда тоже нужна очередь. :)

В качестве очереди нужно было что-то довольно простое и которое умело бы удобный интерфейс командной строки. Вроде бы подошёл redis. Ну на самом деле, положить в очередь:
redis-cli rpush queue "test message"
 Взять из очереди:
redis-cli lpop queue
В общем, очередь у нас получилась легко. Ну и главный критерий при выборе инструментов был, чтобы получалось всё легко. Далее, эту очередь нужно было обрабатывать. Я заранее не знал, какой формат я там выдумаю, а парсить на баше не очень то и хотелось, поэтому я хотел было взять старый добрый picolisp, но передумал, и взял elisp (это тот, на котором построен emacs). И вот что получилось:
#!/usr/local/sbin/emacs-clean --script
; -*- mode: Emacs-Lisp -*-

(defun message-as-string (message)
  (with-output-to-string
    (let ((first (car message))
          (rest (cdr message)))
      (if first
          (princ first)
        (princ ""))
      (dolist (line rest)
        (terpri)
        (if line
            (princ line)
          (princ ""))))))

(defun receive-from-queue (queue-name)
  (process-lines "redis-cli" "lpop" queue-name))

(defun send-to-queue (queue-name message)
  (process-lines "redis-cli" "rpush" queue-name (message-as-string message)))

(defun tmp-queue (queue-name)
  (concat queue-name "-tmp"))

(defun process-mail-message (message)
  t)

(defun process-xmpp-message (message)
  (condition-case nil
      (progn
        (process-lines "send-xmpp" (car message) (message-as-string (cdr message)))
        t)
    (error nil)))

(defun process-sms-message (message)
  (condition-case nil
      (progn
        (process-lines "send-sms" (car message) (message-as-string (cdr message)))
        t)
    (error nil)))

(defun process-message (queue-name message)
  (let ((success-state (pcase queue-name
                         ("mail" (process-mail-message message))
                         ("xmpp" (process-xmpp-message message))
                         ("sms" (process-sms-message message)))))
    (unless success-state
      (send-to-queue (tmp-queue queue-name) message))))

(defun process-queue (queue-name loop-queue)
  (while (let ((next-in-queue (receive-from-queue queue-name)))
           (unless (equal '("") next-in-queue)
             (process-message queue-name next-in-queue)
             loop-queue)))
  (while (let ((next-in-tmp-queue (receive-from-queue (tmp-queue queue-name))))
           (unless (equal '("") next-in-tmp-queue)
             (send-to-queue queue-name next-in-tmp-queue)
             t))))

(pcase (length argv)
  (0 (dolist (queue '("xmpp" "sms"))
       (process-queue queue t)))
  (1 (process-queue (car argv) nil))
  (_ (progn
       (princ "Usage: process-queue ")
       (terpri))))
Смысл заключается в том, чтобы прочитать из очереди по типу сообщения (xmpp, sms), а потом вызвать программу для доставки. Если же произошла какая-то ошибка, то вернуть обратно в очередь, которую затем обработает этот же скрипт, запустившись в кроне.

XMPP решил отправлять питоновским скриптом, ибо он нагуглился быстрее всего. Я его немного, правда, модифицировал, чтобы конфиги читал, да и адресов несколько было:
#!/usr/bin/python
import sys, xmpp, ConfigParser

if len(sys.argv) != 3:
    print("usage: %s " % sys.argv[0])
    sys.exit(1)

config = ConfigParser.ConfigParser()
config.read("/etc/send-xmpp.ini")
xmpp_jid = config.get("general", "jid")
xmpp_pwd = config.get("general", "password")

toliststring = sys.argv[1]
tolist = toliststring.split(",")
msg = sys.argv[2]

jid = xmpp.protocol.JID(xmpp_jid)
client = xmpp.Client(jid.getDomain(), debug = [])
client.connect()
client.auth(jid.getNode(), str(xmpp_pwd), resource = "SrvMonitor")
for to in tolist:
   message = xmpp.protocol.Message(to, msg)
   message.setAttr("type", "chat")
   client.send(message)
client.disconnect()
Конфиг - это обычный INI файл. Для отправки SMS использовался сервис LetsAds. У них есть API, как и у всех. Туда просто отправлял через curl:
#!/bin/bash

if [[ $# -ne 2 ]]; then
  echo "Usage: $0 <phone> <message>"
  exit 1
fi

source /etc/send-sms.conf

TO=$1
MSG=$2

URL="http://letsads.com/api"
XML="<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<request>
    <auth>
        <login>$PHONE</login>
        <password>$PASS</password>
    </auth>
    <message>
        <from>$FROM</from>
        <text>$MSG</text>
        <recipient>$TO</recipient>
    </message>
</request>"

CURLRESULT=`curl --silent --data "$XML" $URL`
CURLEXITCODE=$?
RESULTERROR=`echo "$CURLRESULT"|grep '<name>Error</name>'`

if [[ ! $CURLEXITCODE -eq 0 ]] || [[ ! -z "$RESULTERROR" ]]; then
  exit 1
fi
Ну и последний штрих - скрипт, отправляющий в очередь:
#!/bin/sh

QUEUE_NAME=$1
TO=$2
MESSAGE=$3

redis-cli rpush "$QUEUE_NAME" "`printf "%s\n%s" "$TO" "$MESSAGE"`"
process-queue "$QUEUE_NAME"
Собственно, он и используется в самом нагиосе для того, чтобы положить в очередь:
/usr/local/sbin/queue-notification sms "$_CONTACTPHONE$" "$NOTIFICATIONTYPE$ : $HOSTALIAS$/$SERVICEDESC$ is $SERVICESTATE$ ($OUTPUT$)"
В общем, всё довольно просто и прозрачно. Для пущей надёжности можно было бы ещё добавить сохранение состояния редиса после запихивания сообщения в очередь, но этим уже страдать не стал.

четверг, 21 августа 2014 г.

Пресс снова бросить курить

Как только не переведут... Или ещё раз о сложностях перевода. Такое вот увидел на одном планшете IconBIT. Довольно долго не мог понять как звучала фраза в оригинале:


среда, 20 августа 2014 г.

Модный апач и добрый пиколисп

В общем, так вышло, что пришлось обновляться. Обновился также и апач до версии 2.4. В старой версии 2.2 ещё продолжал работать модуль mod_auth_pam и было очень удобно, что я имел аутентификацию такую же, как и системную. В новой версии этот модуль за каким-то лядом выпили и всё перестало работать. Ну ляд там вполне понятный, конечно, кривой код, кривой в итоге модуль. Рекомендовали вместо этого использовать mod_authnz_external. Это, конечно, не то, но тоже решение. Программка pwauth для проверки пользователя по паролю была в комплекте, а вот ещё нужная вещь ограничение по группам пользователя не нашлось. Но нашёлся какой-то перловый скрипт, который шёл в исходниках этого модуля, который почему-то не заработал. Может, поэтому его и не включили в дистрибутивный пакет. Пришлось писать. Основная идея - берем с помощью getent группы и пользователей и создаём списки групп, куда входят как пользователи, которые участвют в списке, так и те, чья группа является основной.
Для реализации пришлось думать что брать. Нужно было, чтобы можно было обрабатывать списки (lisp, ну как же) и при этом чтобы можно было легко и прозрачно взаимодействовать с системой. В прошлом мне нравился Scheme Shell, но его судьба мне теперь неизвестна, вроде на 64 битных платформах с ним туго, хотя, вроде, есть multiarch, но привлёк некий picolisp - с очень свежим (или не очень) взглядом на мир. В общем, в целом обычный лисп, команды относительно удобно вызываются. Пример вызова "getent passwd":

(in (list 'getent "passwd")
  <какие-то действия>)
 Ну а дальше дело пошло. :) В общем, вот целиком готовый скрипт. Ну и как у меня выглядит конфиг апача, раз уж речь о нём тоже зашла. Это в конфиге virtualhost.
        # External auth
        DefineExternalAuth sysauth pipe /usr/sbin/pwauth
        DefineExternalGroup sysgroup pipe /usr/local/sbin/sysgroup
 А это в конфиге уже непосредственно того ресурса, который нужно разграничивать:
        AuthType Basic
        AuthBasicProvider external
        AuthExternal sysauth
        GroupExternal sysgroup
        AuthName "BAZON.RU projects"

        require external-group developers

вторник, 19 августа 2014 г.

Итальянская мебель

В общем, привезли мебель в магазин, прямо из Италии. Собирали не местные, а командированные сербы. Ну а мы туда своё оборудование понавешали. Кстати, для последнего сделано очень удобно - задняя стенка стола на петлях.

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

ICFPC-2014 - невероятно, но факт!

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


суббота, 2 августа 2014 г.

ICFPC-2014 - мелочь, а приятно

В общем, один из чуваков решил не дожидаться официальных результатов и захотел составить неофициальную таблицу. Для этого он просил запустить у себя и скинуть ему цифры. Не поленился swizard, замерял, отправил. Расстраивает, что в общем зачёте нас даже нет, зато на картах мы там где-то тусуемся в пределах видимости топа. А по карте world-2 так вообще на первом месте! :) Об этом уже похвастался swizard у себя в журнале, ну и я тоже не смог удержаться. :)


среда, 30 июля 2014 г.

Планета трэша и угара

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

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

Ivideon и порядок камер

Есть такая замечательная программа, хотя и проприетарная, для просмотра и записи с IP камер как Ivideon. Не скажу, что всё в ней хорошо, но в целом, лучше аналогов. Хотя бы в том, что сервер и клиент работают на linux системах. Да и с мобильных приложений просмотр возможен тоже, правда, только по подписке. Ну интерфейс слабоват в плане удобства. Но что больше всего не понял, так это то, что с сервера список камер приходит в каком-то своём порядке. Писал в службу поддержки по этому вопросу. Подтвердили, сказали, что да, действительно порядок не соблюдается.

Облачные технологии и мышление мамонта

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

ICFPC-2014 report

Ну вот, он и завершился. Первое, что хочу сказать - было круто. Большое спасибо моим товарищам по команде - swizard, sectoid и grep-z. В позапрошлом году участвовали мы на пару с swizard'ом, а прошлогодний я конкретно прослоупочил. Помня контест 2012 года, подумали, что неплохо бы ещё рабочих рук и светлых голов и потому кинули объяву. На которые откликнулись sectoid и grep-z.

В этом году нужно было программировать поведение пакмана в одноименной игре и поведение приведений, которые за этим пакманом гоняются и хотят его съесть. Код пакмана нужно было написать на ассемблере некой лямбда машины, приведённой в спецификации, а для привидений на обычном трушном ассемблере. Кстати, орги назвали пакмана лямбда-меном, а его управляющую часть "General Computing Processor" (GCC). Привидения так привидениями и остались, а их управляющая часть "GHost Cpu" (GHC). Что как бы намекает, но по смыслу наоборот. :)

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

В общем, как получили задание, так сразу решили написать транслятор некоего лиспа, который мы назвали "intermediate lisp", в код GCC. Не обошлось без багов, например, путали порядок аргументов во фрейме и то, как они располагаются в стеке. Но обошлось. Стратегией сразу занялся swizard и заключалась она в том, чтобы всё жрать, а от гостов бегать. Собственно, где-то такое решение и засабмитили на лайтнинг. Хотя, теперь могу ошибаться. :)

Как завершился лайтнинг раунд, орги добавили дополнительную спецификацию, где и раскрывались "undocumented" который мы уже, в принципе, и знали. Сразу сели и подумали по нашим ограничениям. Размер программы гостов содержал максимум 256 инструкциий, а врмя на выполнение ограничивало его на 1024 инструкции. Поэтому делать что-то сложное для них теряло смысл. Решили сконцентрироваться на пакмане.

Но пакманом плотно занимался swizard, за транслятор плотно засел sectoid. Витало несколько идей - трансляции ilisp в common lisp, чтобы можно было отлаживаться и другая - трансляции common lisp  в ilisp, чтобы тоже можно было отлаживаться. Пытались реализоваться оба варианта, но победил последний. Правда, как высказался swizard, наверное, имело смысл сделать транслятор сразу в GCC.

В общем, чтобы не мешаться, мы с grep-z решили накидать какой-нибудь простой алгоритм для гостов. И тут меня почему-то торкнуло, что надо реализовать волновой алгоритм поиска пути. Товарищ grep-z же решил, что надо попробовать тупо простое сближение. При простом сближении госты тупо застревали на стандартной карте, пока рядом не пробегал пакман. Закончив волновой алгоритм, обнаружилось, что он не укладывается в 1024 инструкции выполнения. Тогда я придумал ещё одну хитрю вещь - на одном запуске GHC исполнять часть алгоритма, на другом - другую часть и т.д. Но боты так не могли долго принять решение и я от этой затеи отказался. :)

Время уже поджимало, долго возились с транслятором и компилятором. Я начал читать какие ещё есть алгоритмы поиска пути. В итоге просто решил запоминать тупиковые клетки и туда не ходить. При этом если клетка граничила с другим тупиком, то там тоже считалось, что хода нет. В итоге родился гост, который преследовал пакмана. Нашли ссылку про стандартное поведение гостов в классическом пакмане и тогда я добавил ещё одного госта, который идёт на опережение на 4 клетки с пакманом, а при расстоянии меньшем переключается на преследование. И в финальный сабмишн ушло два этих госта. Сюда компилятор не писали, испугались ограничений. :) Вместо этого написали некое подобие макроассемблера.
 Но программировать на нём - всё равно АДъ!

Что же было не так? Всё же, не хватало знаний по лямбда исчислению. Незнание современных методов поиска пути тоже удручало. Думаю, что надо было попытаться сделать компилятор. Не знаю пока, уложились бы мы с этим компилятором в 256 байт, но повторюсь, это АДъ! Хотя, как привыкнешь, вроде обыденно. Постоянно нас преследовали какие-то ошибки в трансляторе GCC. Вместо отладки ИИ занимались правкой багов.

Что же было отлично? Common Lisp! Хотя, в последнее время я программировал на clojure, но Common Lisp чертовски приятен тоже. Технологично - язык получился hosted и пакмана разрабатывать было хорошо. Хорошая команда. Надеюсь, в следующем году мы точно победим! :)

понедельник, 28 июля 2014 г.

ICFPC-2014 over

Этот трёхдневный марафон под названием ICFPC-2014 закончился. В этом году участвовал в команде из 4-х человек под названием "Skobochka". Было весело. Подробности отпишу позже, как отосплюсь, а пока смотрите наши исходники.