Razor E300 Scooter

Человек в джинсах и кроссовках стоит на синем электрическом самокате Razor на асфальтированной дорожке в парке.
Razor E300 Scooter

Жена (спасибо, моя хорошая!) подарила на день рождения электросамокат «Скутер», вчера наличие свободного времени и хорошая погода совпали, мы решили его опробовать. Семь часов зарядки и 20 км хода, максимальная скорость — 25 км/час, защита от брызг и грязи, максимальная нагрузка — 90 кг.

С этими утренними пробками весной и летом буду доезжать до метро, а там на метро до работы, а то 40-50 минут добираться я уже устал, у меня от работы до дома пять км. Только надо привыкнуть к тому, что регулятора скорости нет (можно только включить и выключить мотор) и с заносами надо быть осторожнее.

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

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

Сетевая игра на bash: шахматы ★

Я давно хотел написать какую-нибудь сетевую игру на bash, причём желательно, чтобы управление было удобное, с клавиатуры, обычными курсорным клавишами. Вообще, тема интерактивного взаимодействия в bash глубже, чем «введите число, нажмите „Enter“» не раскопана. Мне пришлось всё изобретать и исследовать самостоятельно. Я очень старался найти что-то похожее по уровню интерактивности, но не нашёл.

Поскольку тонкости управления с клавиатурой съели очень много моего времени, я не стал заморачиваться с тонкостями совместимости, поэтому игра тестировалась только под Mac OS X, есть ненулевая вероятность, что она заработает и под Linux и уж точно её можно допилить там до рабочего состояния.

Для работы игра требует наличия nc (aka Netcat) и терминала с поддержкой 256 цветов (под Mac OS рекомендую iTerm2). При наличие интереса к игре, допилю до терминала на 16 цветов и /dev/tcp. Кстати начал выкладывать все свои шел-поделки на ГитХаб.

Два скриншота терминала с запущенной шахматной программой chess.sh на localhost:50000, показывающие начальную позицию и ход белых (e4).

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

Играть просто — в каждый момент времени активна только одна доска (на скриншоте — правая, у неё буквы и цифры вокруг доски ярче), на активной доске курсор двигается курсорными клавишами — ←, →, ↑ и ↓, взять фигуру и поставить её на доску — по клавише пробела или Enter. Как только вы поставили фигуру на доску, ход переходит к сопернику. «Съесть» фигуру соперника проще простого — достаточно поставить свою фигуру на чужую. В игре есть защита — нельзя «съесть» свою фигуру.

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

#!/bin/bash
# Network chess by Evgeny Stepanischev //bolknote.ru 2011

if [ $# -ne 2 ]; then
    echo Usage: $0 host-of-opponent port
    exit
fi

# Хост оппонента
HOST="$1"

# Общий порт
PORT="$2"

# Клавиатурные комбинации извстной длины
SEQLEN=(1b5b4. [2-7]. [cd]... [89ab].{5} f.{7})

# Фигуры
WHITE=(♙ ♙ ♙ ♙ ♙ ♙ ♙ ♙ ♖ ♘ ♗ ♕ ♔ ♗ ♘ ♖)
BLACK=(♜ ♞ ♝ ♛ ♚ ♝ ♞ ♜ ♟ ♟ ♟ ♟ ♟ ♟ ♟ ♟)

# Наш ход?
OURMOVE=

# Я чёрный или белый?
MYCOLOR=

# Доска
declare -a XY

# Курсор
CX=1 CY=7
TAKEN=

# Необходимые нам клавиатурные коды
KUP=1b5b41
KDOWN=1b5b42
KLEFT=1b5b44
KRIGHT=1b5b43
KSPACE=20

# Восстановление экрана
function Restore {
    echo -ne "\033[5B\033[5B\033[?25h\033[m"
    stty "$ORIG" 2>/dev/null
    (bind '"\r":accept-line' 2>/dev/null)
}

trap Restore EXIT

# Выключаем Enter
(bind -r '\r' 2>/dev/null)
# Выключаем остальную клавиатуру
ORIG=`stty -g`
stty -echo

# Убирам курсор
echo -e "\033[?25l"

# Отдаём события клавиатуры в сеть
function ToNet {
    echo $1 | nc "$HOST" "$PORT"
}

# Реакция на клавиши курсора
function React {
    case $1 in
        $KLEFT)
              if [ $CX -gt 1 ]; then
                  CX=$(($CX-1))
                  PrintBoard
              fi
           ;;

        $KRIGHT)
              if [ $CX -lt 8 ]; then
                  CX=$(($CX+1))
                  PrintBoard
              fi
            ;;

        $KUP)
              if [ $CY -gt 1 ]; then
                  CY=$(($CY-1))
                  PrintBoard
              fi
           ;;

        $KDOWN)
              if [ $CY -lt 8 ]; then
                  CY=$(($CY+1))
                  PrintBoard
              fi
    esac

    # Отдаём события клавиатуры в сеть
    [ "$OURMOVE" ] && ToNet $1
}


# Проверка совпадения с известной клавиатурной комбинацией
function CheckCons {
    local i

    for i in ${SEQLEN[@]}; do
        if [[ $1 =~ ^$i ]]; then
            return 0
        fi
    done

    return 1
}

# Функция реакции на клавиатуру, вызывает React на каждую нажатую клавишу,
# кроме KSPACE — на неё возвращается управление

function PressEvents {
    local real code action

    # Цикл обработки клавиш, здесь считываются коды клавиш,
    # по паузам между нажатиями собираются комбинации и известные
    # обрабатываются сразу
    while true; do
        # измеряем время выполнения команды read и смотрим код нажатой клавиши
        # akw NR==1||NR==4 забирает только строку №1 (там время real) и №4 (код клавиши)
        eval $( (time -p read -r -s -n1 ch; printf 'code %d\n' "'$ch") 2>&1 |
        awk 'NR==1||NR==4 {print $1 "=" $2}' | tr '\r\n' '  ')

        # read возвращает пусто для Enter и пробела, присваиваем им код 20,
        # а так же возвращаются отрицательные коды для UTF8
        if [ "$code" = 0 ]; then
            code=20
        else
             [ $code -lt 0 ] && code=$((256+$code))

             code=$(printf '%02x' $code)
        fi

        if [ $code = $KSPACE ]; then
            [ "$OURMOVE" ] && ToNet $KSPACE

            SpaceEvent && return
            continue
        fi

        # Если клавиши идут подряд (задержки по времени нет)
        if [ $real = 0.00 ]; then
            seq="$seq$code"

            if CheckCons $seq; then
                React $seq
                seq=
            fi

        # Клавиши идут с задержкой (пользователь не может печатать с нулевой задержкой),
        # значит последовательность собрана, надо начинать новую
        else
            [ "$seq" ] && React $seq
            seq=$code

            # возможно последовательность состоит из одного символа
            if CheckCons $seq; then
                React $seq
                seq=
            fi
        fi
    done
}

# Проверяем чёрная или белая фигура
function CheckColor {
     echo -n ${1:0:1}
}

# Первичное заполнение доски
function FillBoard {
     local x y ch

     for y in {1..8}; do
         for x in {1..8}; do
             ch='S '

             if [ $y -le 2 ]; then
                 ch=B${BLACK[$x+8*$y-9]}
             else
                 if [ $y -ge 7 ]; then
                     ch=W${WHITE[$x+8*$y-57]}
                 fi
             fi

             XY[$x+100*$y]=$ch
         done
    done
}

# Вывод букв по краю доски
function PrintBoardLetters {
     local letters=abcdefgh

     [ -z "$OURMOVE" ] && echo -ne "\033[30m" || echo -ne "\033[0m"

     echo -n '   '

     for x in {0..7}; do
         echo -n "${letters:$x:1} "
     done
     echo
}

# Вывод цифры по краю доски
function PrintBoardDigit {
    [ -z "$OURMOVE" ] && echo -ne "\033[30m"
    echo -en " $((9-$1))\033[0m "
}

# Вывод доски
function PrintBoard {
     local x y c ch
     local colors=('48;5;209;37;1' '48;5;94;37;1')

     PrintBoardLetters

     for y in {1..8}; do
        PrintBoardDigit $y

        for x in {1..8}; do
            c=${colors[($x+$y) & 1]}
            ch=${XY[$x+100*$y]}

            if [[ $CX == $x && $CY == $y ]]; then
                c="$c;7"
                [ "$TAKEN" ] && ch=$TAKEN
                [ $MYCOLOR == B ] && c="$c;38;5;16"
            fi

            [[ $(CheckColor "$ch") == "B" ]] && c="$c;38;5;16"

            echo -en "\033[${c}m${ch:1:1} \033[m"
        done

        PrintBoardDigit $y
        echo
     done

     PrintBoardLetters

     echo -e "\033[11A"
}

# Приём событий
function NetListen {
    nc -l $PORT
}

# Готовы слушать события сети
function NetEvents {
    local code

    while true; do
        code=$(NetListen)

        [[ "$code" == "$KSPACE" ]] && SpaceEvent && return

        React $code
    done
}

# Реакция на нажатие Space и Enter — взять или положить фигуру
function SpaceEvent {
    local xy

    # Проверяем, есть ли фигура под курсором
    let xy="$CX+$CY*100"

    # Фигуры нет
    if [ "${XY[$xy]:-S }" = "S " ]; then
        if [ -z "$TAKEN" ]; then
            echo -en "\007"
        else
            # Положили фигуру
            XY[$xy]=$TAKEN
            TAKEN=
            return 0
        fi
    # Фигура есть
    else
        # Мы не должны позволять «съесть» свою фигуру
        if [[ $(CheckColor "$TAKEN") == $(CheckColor "${XY[$xy]}") ]]; then
            echo -en "\007"
        else
			# Фигура есть «в руке», мы «съедаем» противника
			if [ "$TAKEN" ]; then
			    XY[$xy]=$TAKEN
                TAKEN=
                return 0    
			else	
                # «В руке» ничего не было, мы взяли фигуру
                TAKEN=${XY[$xy]}
                XY[$xy]="S "
            fi
        fi
    fi

    return 1
}

# Очистка клавиатурного буфера
function ClearKeyboardBuffer {
    # Быстро — через zsh
    which zsh &>/dev/null && zsh -c 'while {} {read -rstk1 || break}' && return

    # Медленно — через bash
    local delta
    while true; do
        delta=`(time -p read -rs -n1 -t1) 2>&1 | awk 'NR==1{print $2}'`
        [[ "$delta" == "0.00" ]] || break
    done
}

FillBoard

# Кто будет ходить первым
ToNet HI
[[ "$(NetListen)" == "HI" ]] && OURMOVE=1
sleep 0.2
ToNet ULOOSE

[ "$OURMOVE" ] && MYCOLOR=W || MYCOLOR=B

PrintBoard

# Основной цикл — обрабатываем события из сети или с клавиатуры
while true; do
    if [ -n "$OURMOVE" ]; then
        ClearKeyboardBuffer
        PressEvents
        OURMOVE=
    else
         NetEvents
         OURMOVE=1
    fi

    PrintBoard
done

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

Bashnut Battery

Есть такая программа — coconutBattery, красиво показывает под MacOS X состояние батареи и некоторые другие характеристики. Поскольку я тут тренируюсь писать под Bash, решил сегодня повторить её функционал. Полностью не получилось, так как новая версия MacOS X выдаёт что-то странное в параметре потребляемой мощности, но остальное повторил в точности. С параметром «Age of your Mac» я смухлевал, беру данные с онлайн-сервиса (без подключения к интернету этот параметр будет выдавать NA), но зато я эти данные кеширую на сутки.

Bashnut Battery (17.12КиБ)

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

Сам код — далее.
Код ниже:

#!/bin/bash

# Хост для информации о серийнике
HOST='www.chipmunk.nl'

# Выбираем информацию о батарее, получится что-то вроде
# Amperage 18446744073709550574 Flags 4 Capacity 6632 Current 6338 Voltage 8192 CycleCount 14 и тд

BATTERY=( $(\
    ioreg -w0 -l |
    egrep '(Max|Design)Capacity|(Legacy|IO)BatteryInfo|product-name|Temperature|PlatformSerialNumber' |
    tee >(awk -F{ '/(Legacy|IO)BatteryInfo/ { gsub(/ |\}|"/, ""); gsub(/,|=/, " "); print $2 }') |
    tee >(awk -F'"' '/(Max|Design)Capacity|product-name|Temperature|PlatformSerialNumber/ { gsub(/[=<>-]/, ""); print $2 $3 $4}') |
    grep -vF '"' |
    tr '\n' ' '
))

# Достаём значение по ключу из BATTERY
function GetBatVal {
    local i

    for ((i=0; i<${#BATTERY[@]}; i+=2)); do
        if [ $1 = ${BATTERY[$i]} ]; then
            echo ${BATTERY[$i+1]}
            break
        fi
    done
}

# Получаем информацию о неделе выпуска
function GetPlatform {
    local tmpfile="$TMPDIR/battery-age-mac"

    # Файл с кешем, чтобы не дёргать сервис каждый раз
    if [ -e $tmpfile ]; then
        # проверим время создания файла
        eval $(stat -s $tmpfile)

        # Если кеш устарел, то удаляем его
        if [ $((`date +%s` - $st_mtime)) -gt 86400 ]; then
            rm -f $tmpfile
        else
            cat $tmpfile
            return
        fi
    fi

    local date=($(\
        curl --connect-timeout 3 "http://$HOST/cgi-fast/applemodel.cgi?serienummer=$1" 2>/dev/null |
        sed 's/<BR>/`/g' | awk 'BEGIN {RS="`"} /Production (year|week)/{gsub("<[^>]+>", ""); print $2 $3}' |
        sort | cut -d: -f2 | tr "\r\n" '  '
    ))

    if [ ${#date[@]} -le 1 ]; then
        echo NA
        return
    fi

    local scale
    local diff

    # Считаем количество недель
    let diff="($(date +%Y)-${date[1]})*52177 + ( $(date +%V) - ${date[0]}) * 1000"

    # Выбираем что будем отображать — недели, месяцы, годы
    if [ $diff -gt 5 ]; then
        diff=$(( $diff / 4340 ))
        scale=Month

        if [ $diff -gt 12 ]; then
            diff=$(( $diff / 12 ))
            scale=Year
        fi
    else
        diff=$(( $diff / 1000 ))
        scale=Week
    fi

    [ $diff -gt 1 ] && scale=${scale}s

    echo $diff $scale | tee $tmpfile
}

# Рисуем прогрессбар
function PrintBat {
    # Если терминал поддерживает 256 цветов, покажем красиво
    if [[ $TERM =~ 256 ]]; then
       local colors=("38;5;160" "38;5;220" "38;5;34")
    else
       # Иначе, увы, цвета попроще
       local colors=(31 33 32)
    fi

    local c=${colors[0]}

    [ $1 -ge 13 ] && c=${colors[1]}
    [ $1 -ge 20 ] && c=${colors[2]}

    local bar=$(cat)
    local prg=$(printf "%0$1s" | tr 0 ${bar:2:1})
    local rep="\033[${c}m$prg\033[30m"

    echo -e ${bar/$prg/$rep}
}

# Возраст Мака
age=$(GetPlatform `GetBatVal IOPlatformSerialNumber`)

# Всё достаточно очевидно: боксы с информацией
cur=$(GetBatVal Current)
max=$(GetBatVal Capacity)
let percent="($cur*40/$max)"

echo -e '\033[1m\n  Bashnut Battery by Evgeny Stepanischev\033[0m'

echo
echo   '  Battery charge'
echo    ┌──────────────────────────────────────────┐
printf '│ Current charge:                % 5d mAh │\n' $cur
printf '│ Maximum charge:                % 5d mAh │\n' $max
echo   '│                                          │'
echo -e '│ ████████████████████████████████████████ \033[0m│' | PrintBat $percent
echo    └──────────────────────────────────────────┘

des=$(GetBatVal DesignCapacity)
max=$(GetBatVal MaxCapacity)
let percent="($max*40/$des)"

echo   '  Battery capacity'
echo    ┌──────────────────────────────────────────┐
printf '│ Current capacity:              % 5d mAh │\n' $max
printf '│ Design capacity:               % 5d mAh │\n' $des
echo   '│                                          │'
echo -e '│ ████████████████████████████████████████ \033[0m│' | PrintBat $percent
echo    └──────────────────────────────────────────┘

echo  '  Details'
echo    ┌──────────────────────────────────────────┐
printf '│ Mac model:             % 17s │\n' $(GetBatVal productname)
printf '│ Age of your Mac:       % 17s |\n' "$age"
printf '│ Battery loadcycles:                % 5d │\n' $(GetBatVal CycleCount)
printf '│ Battery temperature:             % 5s˚С |\n' `echo "scale=1;($(GetBatVal Temperature)+5)/100" | bc`
echo    └──────────────────────────────────────────┘

echo -e "\033[0m"

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

Электронный документооборот

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

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

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

Электронный документооборот (47.10КиБ)

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

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

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

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

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

Бинарные часы на bash

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

Bash Binary Clock (9.50КиБ)

Бинарные часы — популярное сейчас развлечение программистов, вроде написания игры «Жизнь». Как можно догадаться из названия, они показывают время в двоичной системе исчисления. Самое интересное в моей реализации — как подавляется ввод клавиатуры, это неочевидно. Всё дело в следующих строчках:

# Нажатие «Enter» нужно отключать отдельно
bind -r '\r'
# Сохраняем предыдущее состояние
ORIG=`stty -g`
# Отключаем остальную клавиатуру
stty -echo
# На выходе всё нужно восстановить как было
function Restore {
    stty "$ORIG"
    bind '"\r":accept-line'
}

trap 'Restore' EXIT

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

Текст программы внутри.

#!/bin/bash

declare -a xy

# Выключаем Enter
bind -r '\r'
# Выключаем остальную клавиатуру
ORIG=`stty -g`
stty -echo

function Restore {
    stty "$ORIG"
    bind '"\r":accept-line'
    echo -ne "\033[5B\033[?25h\033[m"
}

trap 'Restore' EXIT

# Цвета наших «стрелок»
colors=(30 34)

# Очистка графического массива
function Clear {
    xy=
}

# Подготовка маски одного разряда
function Print {
    mask=$(printf '%08d' `echo "obase=2; $1" | bc`)
    let pos="$2*4"

    for x in {0..1}; do
        for y in {0..3}; do
            xy[$pos+$x+$y*100]=${mask:$x*4+$y:1}
        done
    done
}

# Печать часов на экран
function PrintClock {
    echo -e "\033[?25l\033[1mBash Binary Clock by Evgeny Stepanischev\033[0m\n"

    for y in {0..3}; do
        for x in {0..9}; do
            c=${colors[${xy[$x+$y*100]:-0}]}
            echo -ne "\033[${c}m▣"
        done
        echo -e "\033[0m"
    done

    # после печати часов передвигаем курсов так,
    # чтобы следующий кадр выводился поверх предыдущего
    echo -en "\033[8A"
}

# Вывод часов
function Clock {
    Clear
    for i in {0..2}; do
        Print $1 $i
        shift
    done

    PrintClock

    echo -e "\n"
}

while true; do
    Clock `date "+%H %M %S"`
    sleep 1
done

Я писал под «Мак», так что на других системах может и не завестись.

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

34

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

Отдельной строкой хочу выделить большую работу — конвертацию корпоративной «Вики» «Яндекса» в UTF-8, заодно я там детально разобрался во всех проблемах PHP с UTF-8.

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

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

Занятость каналов WiFi

Утилита, чтобы посмотреть занятость каналов (11.09КиБ)

Что делать перед днём программиста как не программировать? Я настраивал точку доступа дома и пытался выбрать более свободный канал. Быстро найти подходящую утилиту под Mac OS X я не смог, поэтому начал её писать на bash. До конца не дописал (хотел ещё обозначить сколько устройств на одном канале висит), то что есть выкладываю — не пропадать же добру!

Дальше.

#!/bin/bash
declare -a dots

TEMP=$(mktemp -t `basename "$0"`)
trap "/bin/rm -f $TEMP" EXIT

if [ -z $1 ]; then
    /System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -s > $TEMP
else
    /bin/cp "$1" $TEMP
fi

# Если название точки содержит пробел, у нас всё поедет, надо избавиться от названия
# для этого мы меряем с каким отступом идёт первая строка (6 — это длина слова SSID, плюс пробелы)
cutname=`awk 'NR==1 {l=length; gsub(/^ +/, ""); print l-length+6}' $TEMP`

# Название будет отрезано командой cut
while read line; do
    line=($line)

    chs=(${line[2]//,+/ })

    # Берём только каналы 2,4ГГц
    if [ ${chs[0]} -gt 13 ]; then
        continue
    fi

    # Округляем уровень сигнала
    let lvl="(100 + ${line[1]} + 9) / 10"
    # Уровень прозрачности верхней линии
    let alpha="$lvl*10 - (100 + ${line[1]})"

    # Номера каналов
    let start="${chs[0]}-2+1"
    let end="${chs[0]}+2+${chs[1]:-0}*5+1"

    # Набор точек для рисования прямоугольника wifi-точки
    for x in $(seq $start $end); do

        # Прямоугольник закрашивается сплошным…
        for y in $(seq 0 $(($lvl - 1)) ); do 
            dots[$x+$y*100]=10
        done

        # Кроме верхней границы, она закрашивается значением
        # наибольшей насыщенности
        let xy="$x+($y+1)*100"

        if  [[ -z ${dots[$xy]} || ${dots[$xy]} -lt $alpha ]]; then
            dots[$xy]=$alpha
        fi
    done
# отрезаем заголовок, отрезаем название точки, сортируем по уровню сигнала
done < <(tail -n +2 $TEMP | cut -b${cutname}- | sort -rgk2)

# Блоки по насыщенности границы
blocks=(_ ░ ░ ░ ▒ ▒ ▒ ▒ ▒ ▒ █)

# Цвета вертикальной оси
colors=(32 32 32 32 32 33 33 31 31 31 31)

# Счётчик вертикальной оси
lvl=0

declare -i alpha

# Отрисовка шкалы и данных точек
for y in {10..0}; do
    printf "\033[${colors[-$lvl/10]}m% 4d " $lvl
    let lvl="$lvl - 10"

    for x in {0..15}; do
        alpha=${dots[$x+100*$y]}

        if [ $alpha -le 0 ]; then
            echo -n '   '
        else
            b=${blocks[$alpha]}

            echo -ne "\033[37m$b$b$b"
        fi
    done

    echo
done

# Горизонтальная ось
echo -e "\033[30m     -- -- 01 02 03 04 05 06 07 08 09 10 11 12 13"

echo -e "\033[0m"

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

Горе-киберсквотер

Из аськи:

Denis_S: вас не интересует домен связанный с вашей фамилией?
Евгений Степанищев: нет, нафига он мне?
Denis_S: ну не знаю) ладно тогда извините
Евгений Степанищев: тем более, что он свободен
Denis_S: stepanishev.ru ?
Евгений Степанищев: я не Степанишев

Много, интересно, у него ещё таких доменов «связанных» с фамилиями? Simdorov.ru? Kozllow.ru?

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

Переход на «Льва»

Купил себе «Льва» на ноут (это новая Mac OS X), разочарован. Некоторые программы не работают, некоторые начали работать с глюками. Опытные маководы сказали мне, что надо было подождать пару версий, я же неопытный, я не знал. Со стороны казалось, что продукция «Эпла» оплот стабильности, единства и заботы о пользователи. Ничего подобного, здесь так же как везде. Более того, на «Айпаде» тоже единством и не пахнет. Я себе поставил несколько книг и читалок, у каждой свой интерфейс, свои жесты, какие-то из них блокируют поворот экрана, обычный бардак.

Вот, кстати, что подо «Львом» говорит скомпилированная ещё на прошлой версии операционки программа (это мои «уголки» на «Go»):

libcgo: thread-local storage 0x108 not at %gs:0x8a0 - x=0 y=0
Abort trap: 6

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

Заботу о пользователе я тоже как-то не ощутил. Во «Льве» поменяли важные жесты, а прокрутка экрана стала работать в другую сторону.

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

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

Суеверные авиалинии

12, 14 (14.63КиБ)

Снято в самолёте вчерашнего рейса «Донавии» из Казани. В первый раз такое вижу, а может не замечал раньше просто — в самолёте нет тринадцатого ряда.

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

«Айпад» — слепое пятно у стюардесс

Не в первый раз замечаю (сегодня проверю ещё раз), что «Айпады» — это такое слепое пятно у стюардесс. Когда они просят выключить оборудование при взлёте и посадке, можно преспокойно продолжать читать с «Айпада», они не обращают внимания. Интересно, почему?

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

Луна не является спутником только Земли

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

…если посчитать силы, с которыми Луну притягивает Земля и Солнце обнаружится интересный факт: Солнце притягивает Луну в 2,2 раза сильнее, чем Земля! Выливается это еще и в то, что вектор результирующего ускорения тела все время имеет составляющую, направленную к Солнцу, то есть оно всегда Солнцестремительное, но не всегда Землестремительное…

Луна и впрямь вращается около Солнца (падает на Солнце!), а не около Земли, но на это движение сильно влияет Земля. Таким образом, систему Земля-Луна правильнее называть двойной планетной системой, обращающейся около Солнца.

В статье есть прекрасная картинка, иллюстрирующая как именно выглядит обращение системы Земля-Луна вокруг Солнца (зелёная линия — Земля, красная — Луна):

Земля-Луна (24.24КиБ)

В школе-то, я же помню, нам показывали модель, где все планеты с разными скоростями вращались вокруг Солнца, а Луна бешенно крутилась вокруг Земли.

Статью, кстати, рекомендую прочитать целиком, там много интересного.

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

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

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

С позднего вечера субботы до вечера воскресенья — в Москве.

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

«Яндекс.Пробки» в Казани

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

Стойкое ощущение, что в казанских «Пробках» не учитывается никаких источников данных, кроме пользовательских устройств (когда вы пользуетесь приложением для «Карт», приложение пользуется вами — передаёт «Яндексу» как быстро вы двигаетесь на этом участке).

Например, вчера я ехал по мосту «Миллениум», на котором была грандиозная пробка, прямо за моим указателем положения дорога на глазах «краснела».

Исправить ситуацию можно следующим образом.

Во-первых, помните я рассказывал, что в Казани есть интерактивная карта движения транспорта? Это уже готовые датчики загруженности дороги. Там есть скорость и координаты, чтобы померить ситуацию и обозначены остановки, чтобы убрать ложные срабатывания.

Во-вторых, нужно поставить по камере в важных участках Казани. Взглянем на карту.

Казань (66.00КиБ)

Город условно делится на две части — левый берег и правый берег реки Казанки. Больша́я часть казанцев ежедневно пересекает реку в обеих направлениях, а сделать это можно строго по одному из четырёх мостов Казани (слева направо) — Кировский дамбе, Ленинской дамбе, мосту Миллениум и Третьей транспортной дамбе (сейчас последняя перекрыта, но работает её дублёр).

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

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

В-третьих, часть важных дорог для «Яндекс.Карт» похоже не существует. На дублёре Третьей транспортной дамбы aka «Старый мост» (который работает вместо самой дамбы) я вообще ни разу не увидел хоть какой-то информации о пробках, Чистопольская в сторону Ямашева не существует тоже — на клиенте Андроида там у меня пунктир, дорожной информации нет, а эта дорога связывает два моста — Миллениум и Третью транспортную. Это только те места, где я обычно проезжаю.

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

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

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

Айти-парк Казани

Видеопутеводитель по «Айти-парку» Казани. Там же есть небольшой рассказ о фирме, в которой я сейчас работаю, она тоже находится в «Айти-парке». Ещё обратите внимание на дата-центр и, деталь, на каждой двери есть QR-код, а так же Microsoft Tag. Можно узнать поподробнее что находится за каждой дверью.

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

Аналог conditional comments появится в CSS

Ура, ребята из W3C одумались и в CSS появится аналог conditional comments. Первого сентября появился черновик нового модуля CSS3 — «CSS Conditional Rules Module Level 3». Самое интересное в нём — новое правило «@supports», которое позволяет проверить поддерживает ли браузер определённый функционал (жаль только нет правила «@supports-but-buggy»).

Есть поддержка «not», «or» и «and», а так же группировки скобками:

@supports (transition-property: color) or
          ((animation-name: foo)) and
           (transform: rotate(10deg))) {
  // …
}

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

@supports ( box-shadow: 2px 2px 2px black ) or
          ( -moz-box-shadow: 2px 2px 2px black ) or
          ( -webkit-box-shadow: 2px 2px 2px black ) or
          ( -o-box-shadow: 2px 2px 2px black ) {
  .outline {
    color: white;
    box-shadow: 2px 2px 2px black;
    -moz-box-shadow: 2px 2px 2px black;
    -webkit-box-shadow: 2px 2px 2px black;
    -o-box-shadow: 2px 2px 2px black;
  }
}

Я легко могу представить когда нужна будет ещё более ветвистая и страшная конструкция. Трудности я понимаю — нужно хорошо вписать конструкцию в уже существующий синтаксис CSS. Была бы моя воля, я бы сделал что-то вроде такого:

.outline {
     box-shadow: 2px 2px 2px black !fallback(no-box);
    -moz-box-shadow: 2px 2px 2px black !fallback(no-box);
    -webkit-box-shadow: 2px 2px 2px black !fallback(no-box);
    -o-box-shadow: 2px 2px 2px black !fallback(no-box);
}

@fallback no-box, no-smth-else {
    /* попадаем сюда, если все условия с таким именем внутри селектора не выполнились */
}

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

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

Деньги vs. спасибо

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

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

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

У меня большой Айпад

<AnYKEy> Заметил, в последнее время часто подписи в почте: «Отправлено с iPhone», «Отправлено с iPAD». Может тоже вставлять в подпись что-то вроде: «А у меня большой х██»?

С «Башорга» цитата.

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

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

Руферы в Казани

Казань (93.51КиБ)

Руферы (от англ. «roof» — крыша) — это ребята забирающиеся на крыши и верхушки труднодоступных объектов. Одна из команд московских руферов побывала в Казани и выложила фотоотчёт об этом в ЖЖ. Редкая возможность посмотреть на Казань с необычного ракурса.

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

Кстати, на этом же снимке видна стройка Дворца водных видов спорта.

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