Родная речь

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

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

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

Дополнение: первое апреля кончается, выключаю шутку, попозже напишу пост о ней, чтобы осталась на память. А пока пошёл лечиться — я острый бронхит заработал.

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

С первым апреля!

Первоапрельский сайт (41.26КиБ)

Ну, первое апреля кончается, поэтому я привёл сайт к исходному виду. Если кто не застал, то сайт у меня сегодня выглядел как на скриншоте сверху — я поменял фотку и вступительный текст, пустил псевдотатарский орнамент справа и «перевёл» весь сайт на татарский (весь, кроме пояснительного поста).

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

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

function RuTatHelper($m) {
    static $dict = null;
    
    if ($dict === null) {
        $dict = unserialize(file_get_contents("compress.zlib://ru-tat.txt.gz"));
    }

    $len = mb_strlen($m[0], 'utf-8');
    if (isset($dict[$len])) {
        $n = sprintf('%u', crc32($m[0])) % count($dict[$len]);

        $word = $dict[$len][$n];

        if (preg_match('/^\p{Lu}/u', $m[0])) {
            $word = mb_strtoupper(mb_substr($word, 0, 1, 'utf-8'), 'utf-8') . mb_substr($word, 1, $len - 1, 'utf-8');
        }

        return $word;
    } else {
        return $m[0];
    }
}

function RuTat($text) {
    return preg_replace_callback('/\p{Cyrillic}+/u', 'RuTatHelper', $text);
}

С татарскими словами просочились и русские (в татарской речи очень много русских слов), особенно забавно было, что «Поиск» у меня превратился в «Путин». Не знаю, успели ли повеселиться татары, там настоящая тарабарщина написана была, например, вместо «блог» слово «призрак» по-татарски.

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

30 банковских дней

Делал жене программу, чтобы отсчитывать от введёной даты 30 банковских дней в текущем году, может пригодится кому (в запускаемый файл преобразовал при помощи PyInstaller, получается один файл, очень удобно). При первом запуске программа скачивает календарь с сайта Calend.Ru и сохраняет рядом, потом берёт из него выходные и праздничные дни.

# coding: utf-8
import re
import httplib
import pickle
import ctypes
from datetime import date, datetime, timedelta

MB_OKCANCEL = 1
MB_SYSTEMMODAL = 4096
IDOK = 1
IDCANCEL = 2

def getCalend():
    h = httplib.HTTPConnection('www.calend.ru')
    h.request('GET', '/work/')
    return h.getresponse().read()

def getHolidays():
    table = re.findall(r'<table\s.+?time_of_death(.+)</table>', getCalend(), re.DOTALL)[0]
    return re.findall(r'<td\s+class="\S+\s+col5"\s+day="(\d+)"\s+month="(\d+)"', table, re.DOTALL)

def readHolidays():
    year = str(date.today().year)
    try:
        with open(year + '.cache', 'r') as f:
            holidays = pickle.load(f)
    except IOError:
        with open(year + '.cache', 'w') as f:
            holidays = tuple(getHolidays())
            pickle.dump(holidays, f)

    return [datetime(day=int(d[0]), month=int(d[1]), year=int(year)) for d in holidays]

def getStartDate():
    while 1:
        input = re.split(r'\D', raw_input("Enter start date (dd.mm): "))
        try:
            input = [int(x) for x in input]
            if len(input) == 2:
                break
        except ValueError:
            pass

    return (date.today().year, input[1], input[0])

delta = timedelta(days = 1)

holidays = readHolidays()
msgbox = ctypes.windll.user32.MessageBoxW

while 1:
    try:
        date = datetime(*getStartDate())

        for i in xrange(0, 30):
            while 1:
                date += delta

                if date not in holidays: break

    if msgbox(
            0,
            u'Получилась следующая дата: %02d.%02d.%04d' % (date.day, date.month, date.year),
            u'Ответ',
            MB_OKCANCEL | MB_SYSTEMMODAL
        ) == IDCANCEL:
        raise StopIteration
    except (KeyboardInterrupt, StopIteration):
        break

Программу написал быстро, а сложнее всего было её отправить — ГМэйл упорно не принимает запускаемые файлы, даже в архивах.

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

Кот изучает мир людей

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

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

Научные эксперименты это, конечно, хорошо, но накладно.

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

Дискурс Пелевин

Прочитал новую книгу Пелевина, болею же, что ещё делать?

Краткое содержание: дискурс, дискурс, дискурс, дискурс, дискурс, дискурс, гламур, гламур, дискурс, дискурс, баблос. Концовка подкачала, да, мало дискурса.

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

30 банковских дней-2

Жена попросила во вчерашнюю программу ряд улучшений внести и пожаловалась, что она на одном из компьютеров на работе запускается медленно. Ну, я решил переписать её на Гоу, раз такое дело, может быстрее стартовать будет. Кроме того, мне всегда интересно посмотреть как одна и та же программа выглядит на разных языках программирования.

package main

import (
    "encoding/json"
    "os"
    s "strconv"
    t "time"
    "net/http"
    "io/ioutil"
    "fmt"
    r "regexp"
    "bufio"
    "strings"
    fp "path/filepath"
)

type date struct {
    D byte
    M byte
    Y int
}

func CreateDate(d, m string, y int) date {
    day, _   := s.Atoi(d)
    month, _ := s.Atoi(m)

    return date{D:byte(day), M:byte(month), Y:y}
}

func (d date) FindIn(list []date) bool {
    for _, cur := range list {
        if d.D == cur.D && d.M == cur.M && (d.Y == cur.Y || cur.Y == 0) {
            return true
        }
    } 

    return false
}

func (d date) ToTime() t.Time {
    return t.Date(d.Y, t.Month(d.M), int(d.D), 0, 0, 0, 0, t.UTC)
}

func (d date) IsWeekEnd() bool {
    dw := string(d.ToTime().Weekday())

    return dw == "Saturday" || dw == "Sunday"
}


func (d date) Add(delta string) date {
    dur, _ := t.ParseDuration(delta)
    t := d.ToTime().Add(dur)

    return date{D:byte(t.Day()), M:byte(t.Month()), Y:t.Year()}
}

func (d date) String() string {
    return fmt.Sprintf("%02d.%02d.%04d", d.D, d.M, d.Y)
}

func loadCache(name string) (holidays []date) {
    f, err := os.OpenFile(name, os.O_RDONLY, 0666)

    if err != nil {
        return nil
    }

    defer f.Close()

    if err := json.NewDecoder(f).Decode(&holidays); err != nil {
        return nil
    }

    return
}

func saveCache(name string, holidays []date) bool {
    f, err := os.OpenFile(name, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666)

    if err != nil {
        return false
    }

    defer f.Close()

    if err := json.NewEncoder(f).Encode(&holidays); err != nil {
        return false
    }

    return true
}

func getCurrentCalend() []byte {
    if resp, err := http.Get("http://www.calend.ru/work/"); err == nil {
        defer resp.Body.Close()

        if body, err := ioutil.ReadAll(resp.Body); err == nil {
            return body
        }
    }

    return nil
}

func getCurrentHolidays() (dates []date) {
    table, _ := r.Compile(`(?s)<table\s.+?time_of_death(.+)</table>`)
    chunk, _ := r.Compile(`(?s)<td\s+class="\S+\s+col5"\s+day="(\d+)"\s+month="(\d+)"`)

    dates = []date{}

    year := t.Now().Year()

    for _, value := range chunk.FindAllStringSubmatch(string(table.Find(getCurrentCalend())), -1) {
        dates = append(dates, CreateDate(value[1], value[2], year))
    }

    return
}

func ReadUserInput(message string) string {
    fmt.Print(message)

    input, _ := bufio.NewReader(os.Stdin).ReadString('\n')
    return input
}

func main() {
    var currentholidays []date

    year := t.Now().Year()
    cachename := s.Itoa(year) + ".json"

    // если кеш существует
    if _, e := os.Stat(cachename); e == nil {
        currentholidays = loadCache(cachename)
    } else {
        currentholidays = getCurrentHolidays()
        saveCache(cachename, currentholidays)
    }

    // загружаем другие кеши
    caches, _ := fp.Glob("*.json")
    for _, name := range caches {
        if name != cachename {
            currentholidays = append(currentholidays, loadCache(name)...)
        }
    }

    // опрашиваем пользователя
    mask, _  := r.Compile(`^(?m)(\d+)\D+(\d+)`)

    for {
        var userdate date

        for {
            d := mask.FindStringSubmatch(ReadUserInput("Enter date (dd.mm): "))
            if len(d) > 0 {
                userdate = CreateDate(d[1], d[2], year)
                break
            }
        }

        var period int

        for {
            period, _ = s.Atoi(strings.TrimRight(ReadUserInput("Enter period: "), "\r\n"))

            if period > 0 {
                break
            }
        }

        for ; period > 0; period-- {
            for {
                userdate = userdate.Add("24h")

                if !userdate.FindIn(currentholidays) && !userdate.IsWeekEnd() {
                    break
                }
            }
        }


        fmt.Printf("Result: %s\n\n", userdate)
    }
}

Меня поразил размер скомпилированной программы. Вот эта мелочь под «Маком» занимает 3,9Мб, под «Виндой» — 3,7! Жена попросила убрать гуишное окошко, поэтому я сделал программу полностью консольной. Два разочарования: в регулярных выражениях под Виндой неверно определяется конец строки (не учитывается «\r», судя по всему) и второе — в Гоу нет ничего, чтобы работать с однобайтными кодировками, а в консоли Винды до сих пор CP866. Пришлось выводить всё по-английски, писать конвертирующую функцию мне лень.

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

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

Миронов Фёдор Тимофеевич

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

Мой двоюродный дед или «великий дядя», как это раньше называлось, Фёдор Тимофеевич, 1925 года рождения, дядя Федя, как я его звал в детстве.

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

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

Дядя Федя (128.66КиБ)

Вот только этот снимок, с наградами, я вчера увидел впервые, по крайней мере не припомню, чтобы видел его раньше. Мне прислали его из Житомира, дочь Фёдора Тимофеевича разбирала фотоальбом, прислала некоторые снимки. Я и знать не знал, что у дяди Феди столько наград! Он никогда ничего такого не рассказывал, а если кто-то при мне это и упоминал вскользь, то в памяти не отложилось.

Понятно, что бо́льшая часть, наверняка юбиленые, но слева явно видны два (!) Ордена Красной Звезды, остальные награды я различить не могу, не специалист и бликует сильно. В интернете есть открытая база «Подвиг народа», где можно посмотреть наградные листы за ордена и медали «За отвагу» и «За боевые заслуги» (правда, наградной листок одного из моих дедов, награждённых медалью «За отвагу», там не нашёлся).

Можно почитать за что дядя Федя получил эти ордена.

Первую награду старший сержант Фёдор Тимофеевич получил 22 октября 1944 года. В наступательных боях 5—7 ноября 1944 года в районе деревни Напюрки Бутне (Napiórki Butne) Ружанского повета Варшавского Воеводства проявил исключительное мужество и отвагу: противник, пытаясь вернуть потерянные рубежи, восемь раз бросался в контратаку, мой двоюродный дед мужественно отбил все контратаки и, в ходе этих боёв, из личного оружия уничножил шесть немецких солдат.

Первая награда (83.81КиБ)

Вторую награду дядя Федя получил седьмого февраля 1945 года, за то что в боевых действиях по уничтожению окружённой групировки противника в Восточной Пруссии 28-30 января 1945 года, не считаясь с опасностью для жизни, под сильным огнём противника исправлял повреждения на линии КП 29 Стрелкового корпуса с КП 73 стрелковой дивизии, сделав за короткий срок десять сростков, тем самым добился устойчивой связи:

Вторая награда (67.48КиБ)

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

Дед минимум был трижды ранен — 14 апреля 1943 года, 19 сентября 1943 года и 4 октября 1944 года, видимо это был один из этих случаев.

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

Как заставить wget игнорировать robots.txt

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

Например, сайт может запретить роботам ходить по своим страницам, тогда wget откажется скачивать такой сайт. Чтобы попросить его наплевать на эти инструкции, нужно запустить его со следующим параметром:

wget -e robots=off url-который-надо-скачать

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

__defineGetter__ в массивах в JavaScript

Метод __defineGetter__ предназначался в ДжаваСкрипте когда-то для того, чтобы назначить свойству объекта геттер, сейчас он объявлен устаревшим, тем не менее, широко поддерживается — у меня на компьютере с ним работают Сафари, Хром, Фаэрфокс и «Опера».

Я тут подумал — можно ли как-то перехватить чтение не просто свойства, а элемента массива, ведь в ДжаваСкрипте широко рекламируется эквивалентность obj[’name’] и obj.name. Провёл эксперимент, оказалось — можно, в перечисленных мною браузерах получается странный эффект:

Array.prototype.__defineGetter__('0', function() {return 1});

var v = [];
alert(v); // выводит пустой массив
alert(v[0]); // выведет единицу

Такой код из разряда «happy debugging, bitch», ломает голову — массив пустой, но нулевой элемент не пуст.

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

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

В интернете есть всё: котики, совушки и видео с регистраторов

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

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

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

У меня есть ещё и другая теория.

Как называлось село Дубовка Бавлинского района в момент основания? Как работать с Bluetooth из Пайтона на «Маке»? Где взять карту хоть какого-нибудь кладбища на территории России? Где посмотреть что входит в состав «Кока-Колы»? Где в базе документооборота «Практика» лежит поле «Исходящая дата регистрации»?

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

Так вот, другая моя теория в том, что мы привыкли в уме отфильтровывать вопросы, ответы на которые мы вряд ли найдём в интернете. Экономный ум даже не пытается подсказать нам залезть в «Гугл», потому что знает — усилия по поиску не оправдают найденного.

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

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

Как скачать документ из АИС ЦГАСО

АИС ЦГАСО (104.73КиБ)

Изучаю тут самарский электронный архив, который сделан в «Эларе». Насколько я понял, продукт называется АИС ЦГАСО. Убиваю сразу двух зайцев — разбираюсь как всё работает и пытаюсь найти нужные мне документы по родственникам.

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

Основная фишка — паралельное скачивание документов в несколько потоков. Не уверен, что это действительно работает (я не до конца понимаю как Гоу переключает свои горутины), но в теории должно. Добавлено: «полевые испытания» подтвердили, что документы действительно скачиваются параллельно. Удалось сделать крайне просто:

ch := make(chan byte, N)

for i, id := range documents {
    ch <- 1

    go func(id string, index int) {
        name := padZero5(strconv.Itoa(index)) + ".jpg"
        copyUrlToFile(strings.Replace(url, `%id`, id, 1), *dir + "/" + name)

        <-ch
    }(id, i)
}

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

В итоге, одновременно, не будет запущено более N горутин.

Пользоваться программой просто (если кому-нибудь кроме меня это надо) — нужно в браузере (я в «Хроме» пробовал, выбирать при сохранении надо формат «веб-страница полностью») перейти на чтение документа (на снимке экрана иконка книжки рядом с каждым документом), когда загрузится первая страница документа, сохранить текущий документ браузера на диск (Ctrl+S в Винде, ⌘+S на «Маке») и скормить его программе в командной строке:

go run cgodownloader.go скачанный-файл.html

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

Запуск программы (6.56КиБ)

Зато теперь просматривать удобно.

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

Удивительный Си

Кажется, на любом языке программирования можно написать очень запутанную программу. Лидер, наверное, всё-таки Перл (если не брать эзотерические языки), а вот образчик на Си:

main(_){_^448&&main(-~_);putchar(--_%64?32|-~7[__TIME__-_/8%8][">'txiZ^(~z?"-48]>>";;;====~$::199"[_*2&8|_/64]/(_&2?1:8)%8&1:10);}

Эта программа выводит время на момент компиляции в следующем формате:

Вывод программы (4.71КиБ)

У Анатолия Воробья есть полный анализ этой программы, остроумно сделано!

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

Слава Герострат

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

Напомню, что Герострат — молодой пастух, житель Эфеса, сжегший храм Артемиды в своём городе 21 июля 356 года до нашей эры. Когда его на суде спросили для чего он это сделал, он рассказал, что хотел, чтобы его имя помнили потомки. Это многие помнят, история довольно известная.

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

Ещё менее известно, что Герострат, как считается, не настоящее имя пастуха, а прозвище, которое ему дали жители города. То есть ирония выражения «слава Герострата», как мне кажется, ещё и в том, что Герострат всё-таки своей цели не достиг — своё имя он не прославил.

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

Спасибо, «Яндекс.Маркет»!

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

Узнал сколько стоит доставка в Казань — 300 рублей, что показалось мне вполне приемлемой ценой. На другом сайте доставка была бесплатна, но лучше покупать в знакомом месте. Когда товар доставили, меня ждал сюрприз. Оказывается, фирма «Х» считает «доставкой» доставку только до перевозчика, она и стоит 300 рублей, перевозчик доставляет в Казань за 300 рублей, а потом ещё, если вы не можете забрать товар со склада (а мы не могли, перевозчик по выходным и вечерами товар не выдаёт), доставка по городу обойдётся ещё в 300 рублей. Я, конечно, всё оплатил, хотя доставка вышла мне в три раза больше обещанной.

Попробовал поспорить с менеджером, бесполезно, она утверждала, что обещала мне именно такую доставку.

Ну ок, деньги заплачены, их уже не вернуть, в сердцах (эмоции-то куда-то деть надо), написал на «Яндекс.Маркете» плохой отзыв, рассказал всю историю. На следующий, кажется, день, звонит менеджер, которая принимала мой заказ, просит убрать отзыв и предлагает вернуть мне 300 рублей на телефон. Я бы, конечно, хотел 600, но аргумент, что я мог товар забрать со склада самостоятельно, показался мне убедительным. Как только я получил деньги на телефон, убрал отзыв.

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

Неожиданно оказалось, что «Яндекс.Маркет» работает ещё в одном направлении — позволяет не только выбрать товар, но и добиться справедливости.

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

Почему меня беспокоит размер программы

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

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

Поэтому данность: количество оперативной памяти ограничено, в случае моего ноута — сильно ограничено, у меня их всего 2ГиБ, это мало по нынешним временам, но что делать. Типичные современные объёмы оперативной памяти не отличаются от этой цифры на порядки, обычно это 4—8 ГиБ.

Моя память (17.74КиБ)

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

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

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

Американские полицейские тоже живые люди!

Американские фильмы давно создают впечатление, что американский полицейский этакий ангел во плоти — корректен, неумолим, лоялен. Ан нет, пошаливают, оказывается, американские полицейские. В частности — гоняют на дорогах, как российские. Доказательства этому добыла одна газета из Южной Флориды весьма остроумным способом:

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

Полицейские не подумали, что если замерить расстояние между соседними пропускными пунктами SunPass и зная время поездки между ними, то можно вычислить скорость автомобиля. (…)

Анализ данных более миллиона записей с пропускных пунктов «СанПасс» с 2004 года выявил 793 полицейских машины, которые двигались на скорости 145—210 км/ч, зачастую в нерабочее время. В нарушителях оказалась пятая часть полицейского автопарка. Более половины случаев превышения скорости зарегистрировано за пределами зоны патрулирования, большинство автомобилей ехало по стандартным маршрутам, скорее всего, домой после работы или утром на работу.

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

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

Как собрать CuneiForm по старый Линукс

Если у вас не собирается CuneiForm под Линукс с ошибкой

Kern/rstr/librstr.so.1.1.0: undefined reference to `htobe32'

То значит у вас очень старый glibc. Чтобы исправить ситуацию нужно в файл cuneiform_src/Kern/rstr/src/perc.c, в начало, добавить следующий код:

#include <endian.h>

uint32_t htobe32(uint32_t x) {
    union { uint32_t u32; uint8_t v[4]; } ret;
    ret.v[0] = (uint8_t)(x >> 24);
    ret.v[1] = (uint8_t)(x >> 16);
    ret.v[2] = (uint8_t)(x >> 8);
    ret.v[3] = (uint8_t) x;
    return ret.u32;
}

#define swapbytes(a) do { (a) = htobe32(a); } while (0)

Тогда всё соберётся. У меня собралось под ЦентОС 5.2.

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

Тонкое подчёркивание ссылок с разрывами на буквах «р», «у» и других

У меня на сайте два изменения. Во-первых, я опять втихую увеличил шрифт (я этим занимаюсь время от времени), во-вторых, я изменил стиль подчёркивания ссылок. После сайтов Тёмы и Ильи Бирмана, подчёркивание у меня казалось тяжёлым и давящим, а у них — естественным и воздушным.

Но просто сделать так же не интересно, и я решил сделать лучше. Спорно получилось ли лучше, тут есть простор для экспериментов.

Подчёркивание ссылок и Тёмы и Ильи сделано одинаково — убрано родное подчёркивание, а взамен установлено свойство border-bottom, задающее бордюр толщиной в один пиксель. Мне в этом подходе не понравилось, что бордюр находится неестественно далеко — за хвостиками букв «у», «р» и прочих.

Сначала позвольте показать что получилось, обратите внимание на разрыв на хвостике «р», когда я добился более плотного прилегания, оказалось, что перечёркивание хвостов меня не устраивает, хорошо что удалось это поправить:

Результат (21.88КиБ)

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

Я довольно долго эксперементировал и нашёл, в конце-концов, решение — я сделал цветной однопиксельный задний фон (простой ГИФ в data URI) по одному для каждого цвета ссылок: непосещённые, посещённые и с наведением мыши, а потом просто спозиционировал так как мне понравилось.

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

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

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

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

В голове перед сном я прокручивал список разрешённых к изменению свойств и одно из них, background-color показалось мне подходящим, чтобы решить мою проблему. Я нарисовал ГИФ единичной ширины, совершенно белый, но с одним прозрачным третьим с конца пикселем:

Мой фон (15.23КиБ)

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

Ок, это сработало для посещённых ссылок, но в «Хроме» и «Сафари» меня ждал неприятный сюрприз: на мгновение, до того как браузер успевал отрисовать мой ГИФ на заднем фоне, все ссылки выглядели уродливо: был виден их цветной задний фон:

Грусть-печаль (36.94КиБ)

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

Получился следующий стиль:

a {
    background: #00e url(data:image/gif;base64,R0lGODlhAQA7APABAP …и так далее… AAACCISPqcvtEEwBADs=) 0 100% repeat-x;
    background-image: -webkit-linear-gradient(90deg, #fff 0, #fff 2px, rgba(0,0,0,0) 2px, #fff 3px, #fff 59px);
}

Это полностью решило проблему — мигание на вебкитовских браузерах пропало. Кстати, я применил стиль линейного градиента, в новом формате — он работает в «Сафари» с версии 5.1 и в «Хроме» с десятой. Мне кажется, в этом нет ничего страшного — доля старых браузеров, в данном случае, ничтожна мала.

Когда я поставил подчёркивание куда мне хочется, возникла другая проблема. Эстетическая. Подчёркивание довольно уродливо перечёркивало нижние выносные элементы букв. На память, по аналогии, пришло моё баловство с фильтром Glow в Интернет Эксплорере. Там удавалось добиться интересных эффектов с задним фоном, поскольку эффект ложится и на него. Тут у меня ситуация такая же, но фильтров больше не существует, правда есть их реинкарнация —W3C заботливо слизало идею в другом синтаксисе.

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

a {
    text-shadow: 1px -1px 1px white, -1px -1px 1px white, 2px -1px 2px white, -2px -1px 2px white;
}

В браузерах, которые этот стиль не поддерживают, подчёркивание просто не будет разорвано.

Стиль, в результате выглядит примерно так:

a {
    text-shadow: 1px -1px 1px white, -1px -1px 1px white, 2px -1px 2px white, -2px -1px 2px white;
    text-decoration: none;

    background: #00e url(data:image/gif;base64,R0lGODlhAQA7APABAP … и так далее … AAACCISPqcvtEEwBADs=) 0 100% repeat-x;
    background-image: -webkit-linear-gradient(90deg, #fff 0, #fff 2px, rgba(0,0,0,0) 2px, #fff 3px, #fff 59px);
}

a:visited {
    color: #551a8b;
    background-color: #551a8b;
}

a:hover {
    background-color: red;
    color: red;
}

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

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

Mazda CX-5 и официальная сигнализация

Мы тут неделю назад машину купили, «Мазду ЦэИкс-5», долго выбирали, эти марка и модель нам понравилась больше всего:

Чёрный кроссовер Mazda CX-5 на парковке, вид сзади-сбоку, солнечный день, на фоне дороги и промышленных зданий

Речь сейчас не совсем про это. Мы хотим автозапуск в машину (на прошлой машине был, теперь без этого жить сложно), но в салоне сказали, что сигналку надо ставить у них, якобы, иначе машина снимается с гарантии. На мой взгляд, это нарушение шестнадцатой статьи «Закона о защите прав потребителей», во втором пункте русским языком написано:

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

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

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

Нету? Есть!

Да кто это придумал, что в русском языке нет слова «нету»? В словаре Ушакова есть, в Малом энциклопедическом словаре есть, а в русском языке, стало быть, нету? Единственное, «нету» не может применяться как антоним «да», такое значение в современном языке считается устаревшим.

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

Инвертирование в CSS без фильтров

Немногие знают, что инвертирование части ХТМЛ-страницы можно и без новомодных ЦСС-фильтров. Правда, количество браузеров, где это можно сделать, всё уменьшается. В данный момент такая возможность всё ещё остаётся в Эксплорере (версия 8 и выше) и «Опере» (7.0 и выше). Так как «Опера» скоро перейдёт на Вебкит, где этой возможности нет и не было, останется один Эксплорер. Файэрфокс лишился поддержки этой функции в версии 3.0 и возвращать её пока не планирует.

Я говорю о поддержке значения invert свойства outline-color. Это значение говорит браузеру, что нужно инвертировать всё, что лежит ниже. Пользоваться не очень-то удобно, но сойдёт при необходимости, результат может выглядеть, например, так:

Инвертирование при помощи outline-color (33.90КиБ)

Наложить сверху элемент с аутлайном можно любым способом, я использовал position: absolute:

<style>
.invert {
    outline: invert solid 75px;
    position: absolute;

    width: 50px; height: 0;
    margin: 75px 0 0 75px;
}
.content {
    width: 200px;
    height: 150px;
    position: absolute;
    left: 200px;
    top: 200px;
    text-align: center;
}
</style>

<div class="content">
    <div class="invert"></div>
    <img src="/i/foto.jpg">
</div>

Для того, чтобы высчитать размеры накрывающего блока, нужно немного арифметики. У меня большую размерность имеет ширина (накрываемый блок размером 200×150), поэтому будем плясать от неё. Высота накрывающего блока должна быть в этом случае равна нулю, ширина — разности между шириной и высотой накрываемого блока, outline-width, margin-top и margin-left — половине высоты накрываемого блока.

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

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

MongoDB разонравилась

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

Во-первых, видел как база два раза разлетелась и больше не собиралась. Очень неприятно, одну из коллекций спасти не удалось.

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

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

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

Котельная соломинка

Чего только не узнаешь в интернете! Оказывается некоторым людям в слове «коктейльная» слышится «котельная», что привело к появлению совершенно дикого выражения «котельная соломинка»!

Я, когда впервые прочитал, представил себе котельную трубу, засунутую в гигантский бокал.

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

Травля «Жены Футболиста»

Я не одобряю травлю «Жены Футболиста», полностью согласен с основным тезисом, описанным в статье «Потому что нельзя быть красивой такой» некого «Николаича» из ЖЖ — героиня в нашу жизнь не лезла, в депутаты не стремится, на эстраде не появляется. Зачем нужно было так унижать человека, пусть необразованного, мне неясно.

Но с остальными мыслями не согласен категорически.

Во-первых, глупо было стыдить публику через примеры, цитирую:

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

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

И второе:

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

— Она же дура! — Зато молодая. — Но ведь дура!!! — Зато Миссис Россия. — Но дура же… — Зато муж известный спортсмен. — …дура?… — Зато наверняка долларовая миллионерша.

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

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

ГЛОНАСС

Как мне видится, ГЛОНАСС имеет огромное значение для обороноспособности страны. По спутникам сейчас ориентируется много военной техники — корабли, ракеты и прочее. В случае военного конфликта вероятный противник выключит ГПС или, что ещё хуже, начнёт врать в координатах и, привет, приехали.

Мне казалось, что гражданским, нам с вами, непосредсвенной пользы никакой — если ГПС начнёт врать, то нас с вами ГЛОНАСС не спасёт — в данный момент все буржуйские чипы в наших с вами любимых смартфонах и навигаторах, обращаются к ГЛОНАССу, только если у ГПСа дела плохи — мало спутников или приём плохой. Таким образом, если ГПС будет ловиться хорошо, но врать, ГЛОНАСС опрошен не будет, а если и будет, то я не сомневаюсь, что чип отдаст предпочтение координатам из ГЛОНАССа.

Но мне было интересно — а бывают ли ситуации, когда ГПС вообще не ловится, а ГЛОНАСС виден и вчера, на демонстрации татарстанской системы «ГЛОНАСС+112» я поймал редкий кадр — трекер на машине медицинской помощи не смог поймать спутники ГПС, но поймал четыре спутника ГЛОНАССа:

4 ГЛОНАССа, 0 ГПС (109.75КиБ)

Так что, оказывается, и нам, гражданским, бывает польза от ГЛОНАССа.

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

JavaScript, совмещённый с Brainf*ck: «hello friends» ★

Помните моё поздравление с Новым годом, написанное на запутанном Джаваскрипте? Такой же принцип я использовал для привлекающего внимание баннера нашей компании.

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

Получилась следующая программа (используется расцветка для Брейнфака, чтобы было видно какие части программы он пропускает):

($=!{}[/-/+/\+@+@+!+/)-!{$:/>/+/!>/+/</}+
(_=!-{}-$+/>/)-~(/</)+
(_$=-$-{}-$+/>/)[$$=-(~-~$+~-~$-!+{$:/!</})+
_[$$+=~-~{$:/]/}+
_$-~{}+
_$[$$+~{_:-$>/]/}+
$-$$]

Оба интерпретатора выполняют её с разным результатом, Брейнфак выводит «hello», а Джаваскрипт — «friends»:

bolk@Bolk ~$ ./brainfuck <<<'($=!{}+[/-/]+/\+@+@+!+/)[-!{$:/>/+/!+>/+/<</}]+(_=!-{}+[-$]+/>/)[-~(/>[->+>+<<]>>[-<+<+>>]<<</)]+(_$=[-$][-{}]+[-$]+/>>/)
[$$=-(~-~$+~-~$-!+{$:/!+>+>+>+>+>+<<<<</})]+_[$$+=~-~{$:/[->++++>+>++++++++>++++++++>+++++++++++[<]]/}]+_$[-~{}]+_$[$$+~{_:-$>/[.>]/}]+$[-+-$$]'

hello

bolk@Bolk ~$ v8 -e 'print(($=!{}+[/-/]+/+@+@+!+/)[-!{$:/>/+/!+>/+/<</}]+(_=!-{}+[-$]+/>/)[-~(/>[->+>+<<]>>[-<+<+>>]<<</)]+(_$=[-$][-{}]+[-$]+/>>/)
[$$=-(~-~$+~-~$-!+{$:/!+>+>+>+>+>+<<<<</})]+_[$$+=~-~{$:/[->++++>+>++++++++>++++++++>+++++++++++[<]]/}]+_$[-~{}]+_$[$$+~{_:-$>/[.>]/}]+$[-+-$$])'

friends

Повозиться пришлось прилично, если честно, некоторые конструкции ДжЭс делит с Брейфаком (большинство квадратных скобок), а кое-где торчат чистые инструкции Брейнфака, засунутые в те места программы, где они не могут помешать своему соседу. Пустые циклы, которые образуются квадратными скобками я старался сводить к операции зануления ячейки („[-]“), сильно мешали плюсы, используемые в Джаваскрипте для объединения букв — они увеличивали содержимое ячейки в Брейнфаке на единицу, это приходилось учитывать.

Слово «friends» я выбрал потому что его легко записать:

"false"[0]+"true"[1]+"undefined"[5]+"true"[3]+"undefined"[1]+"undefined"[2]+"false"[3]

Принцип я когда-то более-менее подробно разбирал.

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

Оптимизирующий транслятор Brainfuck → PHP

Грех было не запустить свою же программу из предыдущего поста на собственном стареньком (2005 года) оптимизирующем трансляторе Брейнфака в ПХП. Оказалось, оттранслировал его неправильно.

Нашёл баг (неверно транслировалась последовательность «[<]» в некоторых случаях), исправил, почистил, убрал наследие ПХП 4, ввёл небольшую новую оптимизацию и выхожил на ГитХаб.

История этого интерпретатора тянется ещё с 2001-го года и сайта bf.kzn.ru, который ныне не существует. На нём у меня работал jBF, транслятор Брейнфака на Джаваскрипт и это был первый в мире интерпретатор Брейнфака, который использовал оптимизирующие техники. Вышло аж тринадцать версий интерпретатора и он довольно неплохо уделывал аналоги.

В 2005 году я переделал его на ПХП и попробовал предложить на ПЕАР (к тому времени у меня там уже было несколько модулей), но там он не прошёл предворительный осмотр, сказали, что такой модуль не нужен.

Так он у меня и валялся в разделе «Храню», пока я не запустил сегодня на нём свою программу. Должен, кстати, сказать, что интерпретатор держит марку, например, вот вычисление числа «Пи» на моём трансляторе и интерпретаторе на Джаве:  

BFi vs PHP BF (15.14КиБ)

Хотя, может быть, Джава просто медленно стартует.

Заодно, кстати, на своей же программе нашёл баг в расцветке Брейфака, которую я делал для библиотеки highlight.js.

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

← сюда туда →