Категория: Компьютеры

Заметки о программировании и на околокомпьютерные темы

Вложенные категории: Игры, Delphi

Контакты

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

Ещё в каждой соц. сети должны быть “Заметки о друге, видимые только вам”, чтоб написать там, допустим:
Девушка такого-то знакомого
Задавал вопросы по Харухи 3 года назад
Познакомились на ДР такого-то друга
А то смотришь на список друзей – кто эти люди?! (Ещё и фамилию некоторые меняют)

Дыра на дыре!

Компьютерщики, сыграем в игру: вас связали, все ваши компьютеры – в руках злоумышленников. Отвёртка в попе не помогает, вы молчите как партизан и паролей не говорите. Смогут ли вас в целом взломать?

Один-два сайта – это мелочи. Будем считать, злоумышленнику нужно ваше хранилище паролей или его аналог, т.е. способ получения паролей для всех сайтов, где вы зарегистрированы, а также личные секретные данные с каждого из устройств. Допускается заявить, что на каком-то устройстве их нет, но только на одном-двух.
У вас есть домашний ПК, рабочий ПК, ноутбук, планшет, мобильник. Как вы организуете защиту?

Обратите внимание:
– Если получен доступ к почте – вы взломаны! Через неё можно восстановить почти любой пароль.
– Используете куки на компьютере, и к браузеру получен доступ – вы крупно попали! Если не используете, опишите, как вы это устроили. Настройки браузера? Временный диск в памяти для кеша?
– Используете куки и залогинены в почту – вы взломаны полностью!
– Пользуетесь почтовым клиентом? Дважды попали! Пароль к почте можно вытащить из его настроек, а пароли к другим сервисам – из кешированных локально писем.
– Пользуетесь браузером? В вашем кеше много всего интересного! Незащищённый кеш приравнивается к незащищённым личным данным (с той разницей, что кеш разрешается уничтожать, а не шифровать/прятать).
– Ваша почта находится на собственном сервере? Пароль от хостинга равносилен взлому!
– Почта находится на собственном домене? Пароль от регистратора равносилен взлому! Перенаправляем почту на другой ящик и восстанавливаем пароли.
– Мобильник или планшетка в дурных руках? Там были ваши логины почты, и кешированные локально письма – вы взломаны!
– Сим-карту с вашим номером отняли? С помощью СМС на телефон восстанавливают пароль многие сервисы.
– Храните на дропбоксе бэкапы ключей шифрования, паролей, настройки подключения к компьютерам? Враг попал в дропбокс – и всё это взломано! Для простоты считаем, что сам дропбокс без пароля не откроется, хотя были случаи… Дополнительные очки тем, кто воспользуется только локально-шифрующимися сервисами типа SpiderOak/LastPass.

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

Барри Келли ушёл из Дельфи, надо же. Язык ему надоел. Интересно почитать его объяснения в комментариях:

Delphi is very procedural. It grew out of Pascal, a language designed in an era when memory was very expensive. So most of its core runtime is based around mutation and destructive updates.

But the longer I’ve been coding, the greater and greater benefit I see to more functional approaches – which pretty much require garbage collection – and persistent data structures like you see in Clojure.

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

I see the bureaucracy and busywork involved in creating class hierarchies, how it can fool you into thinking you’re doing productive work when you’re filling out various idioms and “patterns”.

Но идиомы и паттерны – это опыт: “такой подход работает”. Там, где их нет, обо всём надо подумать заново. Так что и тут не всё однозначно.

Metro 2033

Прошёл игру.

Сцены разрушенного города и метро интересны. Могло быть лучше, но всё-таки неплохо. Заброшенные туннели, подземные реки, разрушенная Останкинская башня (на неё можно залезть) – на всё это стоит посмотреть.
Графика ничем не удивляет.
Геймплей тоже, хотя кое-что неплохо (патроны как валюта). Но в целом тупые рельсы с тупыми заданиями.
Сюжет и его воплощение в игре бездарные абсолютно. Смеюсь с американцев, которые в эту чушь играют и говорят “необычный сюжет”. Куда пальцем не ткни – какая-нибудь нестыковка, нелепость, условность. Как в Doom3, короче.

Играть не особо интересно, но пройти один раз можно.

День, когда WordPress подавился метадатой

Сегодняшняя история програмистская. Кому компьютеры скучны, можете смело пропускать.

Как все знают, у меня есть отдельный блог на boku.ru. Записи туда по большей части копируются отсюда – в виде исключения я пару раз выложил там скучные рассказы, чтобы включить их в архив, но не афишировать.

Блог сделан на WordPress. Копирование записей устроено так: специальный скрипт генерирует RSS из дневника на Diary, а плагин FeedWordPress забирает RSS и импортирует в WordPress.

Категории при этом сохраняются, внутренние ссылки мой собственный плагин заменяет на местные, а если пост на дайри изменился – изменяется и пост на boku.ru, так что всё устроено достаточно удобно.

Но есть проблема. (далее)

Код FeedWordPress выглядит примерно так:

function WhatToDo(post)
  localPost = FindLocalCopy(post);
  if localPost==null then
    //New post!
    AddPostMeta(localPost, 'syndication_item_hash', post.Hash);
    return doCreateNewPost;
  else
  if not FindMeta(localPost, 'syndication_item_hash', post.Hash) then
    //Post changed!
    AddPostMeta(localPost, 'syndication_item_hash', post.Hash);
    return doUpdatePost;
  else
    //No changes.
    return doNothing;

Если пост на дайри не менялся, FeedWordPress не будет заново его импортировать и не создаст новой ревизии местного поста. Это хорошо. Но перед тем, как записать пост в базу, WordPress прогоняет его через ряд плагинов, которые меняют его содержание:
Пост на дайри (из RSS) –> (замена ссылок на местные) —-> (исправление форматирования) –> Пост на boku.ru

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

Но как это сделать? Ведь пост уже импортирован, и с точки зрения FeedWordPress, его содержимое не менялось (на дайри он остался тем же).

Для этой цели я влез в файлы FeedWordPress, и временно покромсал описанную выше процедуру. Она стала выглядеть так:

function WhatToDo(post)
  localPost = FindLocalCopy(post);
  if localPost==null then
    //New post!
    AddPostMeta(localPost, 'syndication_item_hash', post.Hash);
    return doCreateNewPost;
  else
  if not FindMeta(localPost, 'syndication_item_hash', post.Hash) then
    //Hack: Post is always changed!
    AddPostMeta(localPost, 'syndication_item_hash', post.Hash);
    return doUpdatePost;
    //TODO: Restore normal version.

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

Поправив таким образом FeedWordPress, я залил новые файлы на сервер и стал искать баг в своих плагинах. И нашёл. Исправил. Убедился, что теперь посты преобразуются правильно. Всё сохранил, применил, закрыл… а отключить хак забыл.

И ушёл.

Вторая половина этой истории началась через месяц, когда я зашёл на блог на boku.ru. Все страницы с последними постами не работали.

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

php error: maximum memory allocation exceeded

Какой-то из скриптов жрёт память? Но почему? Что я менял?

И тут я вспомнил, что забыл отключить хак.

Но постойте, а что такого? Проверки раз в полчаса – это 48 проверок в день, жалкие полторы тысячи ревизий за месяц. WordPress может обслуживать десятки тысяч постов, для MySQL лишние несколько тысяч ревизий – пустяк.

Если я напишу ещё полторы тысячи постов – вордпресс даже не поперхнётся. А полторы тысячи ревизий вывели его из строя?

Да ну! Не так он написан.

Тогда почему любая страница, которая обращается к последним постам – вылетает с переполнением памяти? База данных находится на диске – что вообще вордпресс грузит в память?

Метадату.

Каждый раз, загружая очередной пост для печати, вордпресс делает примерно следующее:

rows = exec_sql('SELECT * FROM post_metadata WHERE post_id=id');
while rows.MoveNext() do
  metadata[rows['name']]=rows['value']

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

Обычно таких записей 8-10, иногда до 15 – мелочи, в общем.
У последних записей в моём блоге их было по 60 000.

Ничего удивительного, что обращаясь к этим записям, вордпресс падал. Он не рассчитан на 60 000 записей метадаты у поста. Удивительно, откуда эти записи взялись.

Я открыл таблицу phpMyAdmin-ом, и увидел, что все они – это копии параметра syndication_permalink. Тогда всё стало ясно.

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

Да, импорт RSS происходит лишь раз в полчаса, 48 раз в сутки, и каждый пост импортируется лишь однажды – но функция проверки WhatToDo вызывается десятки раз за процедуру одного импорта. Только однажды её результат имеет значение, поэтому ревизий в базе действительно создано лишь полторы тысячи – но при каждом вызове она добавляет syndication_permalink, и этих пермалинков, совершенно одинаковых, у одного поста набираются десятки тысяч.

Ирония: вордпресс мог бы вынести десятки тысяч постов – но не десятки тысяч свойств поста.

Как всё это чинить?
Итак, испорчена таблица post_metadata: в ней для некоторых постов некоторые записи продублированы десятки тысяч раз. Нужно удалить дубли, но оставить по одной копии каждой записи.

После некоторой возни и гуглинга сотворился следующий манёвр:

CREATE TABLE `keep_ids` AS (
  SELECT MIN(`rowid`) AS `rowid` FROM `post_metadata` GROUP BY `postid`, `name`, `value`
)

Этим запросом мы находим все цепочки дублей (записей с одинаковыми данными в полях postid, name и value), и в каждой выбираем наименьший номер записи. Таким образом, мы получаем по одной копии каждой уникальной записи. Эти копии надо сохранить, а всё остальное удалить.

ALTER TABLE `keep_ids` ADD UNIQUE INDEX `rowid` (`rowid`)

Это чтобы операции с новой таблицей были быстрыми – сейчас понадобится.

DELETE FROM `post_metadata` WHERE `rowid` NOT IN (SELECT `rowid` FROM `keep_ids`)

Удаляем все записи из исходной таблицы, которые не вошли в наш “список на сохранение”. Если б в `keep_ids` не было индексов, мы бы тут завязли на несколько минут, а так – только секунд.

Ну и, наконец, удаляем временную таблицу:

DROP TABLE `keep_ids`

Победа! Число записей в post_metadata резко падает с сотен тысяч до 13 000 и блог снова работает нормально.

Названия таблиц и полей в примерах условны, и не соответствуют настоящим названиям в базе вордпресс. Код написан на условном языке, а код SQL может быть не совсем правильным, но передаёт общую мысль.

Игра по Back to the Future

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

А знакомая музыка и знакомые голоса Марти и Дока (трудно поверить, что их играли другие люди) сшивают любые разрывы и заставляют поверить, что это действительно “Назад в будущее”. Авторы могли ошибиться во стольких местах, но в большинстве не ошиблись.

Ищу бета-тестеров

Я пишу расширение для Оперы, которое показывает на экспресс-панели дневник, число комментариев, дискуссий и ю-мылов. Выглядит примерно так:

Когда появляются сообщения, выглядит так:

Нужны бета-тестеры, т.е. люди, которые будут проверять сырую версию, натыкаться на ошибки и приставать ко мне до тех пор, пока я их не исправлю. Знание HTML/Javasсript/CSS приветствуется. Ошибок будет много.

Про CSS

CSS – язык, который был создан для удобства разметки страницы, и за 15 лет разработки превратил простейшие задачи в Ад.

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

Нет, это можно сделать! Существуют целые сайты, посвящённые “center vertically” или “sticky footer”, где приведены магические заклинания, которые для этого нужно произнести. (Правда, footer случайного размера так никто и не умеет делать иначе, чем через css-3).

…Когда-то у Каганова на сайте был конкурс на лучшее слово из трёх букв. Первая, вторая и третья буквы выбирались из списков. Казалось бы, почти все буквы в списках присутствовали, но – то в одной колонке “Х” нет, то в другой “Б” или в третьей “Я”. И за какое интересное слово не схватишься – ничего не составляется. Вот и CSS так же.

Кеширование рисунков в Опере

По умолчанию в Опере очень плохо кешируются рисунки. Изменив пару настроек, можно сильно ускорить работу с ними.

(читать дальше)

Проблема

Проведите небольшой эксперимент: откройте семь-восемь огромных (не меньше 2000×3000 пикселей) картинок в отдельных вкладках, и попереключайтесь между ними. Если не знаете, где такие взять, поройтесь на Danbooru — NSFW. Видите? Каждый раз, как вы переключаетесь на следующую вкладку, картинка медленно прорисовывается снизу вверх. Это заметно на “тяжёлых” рисунках, но происходит и на мелких, даже на одной и той же странице, когда вы скроллитесь вперёд-назад.

Дело в том, что у Оперы есть два кеша: медленный кеш на диске и быстрый в памяти. Когда вы переключаетесь на следующую картинку, предыдущая выбрасывается из кеша в памяти, и потом её придётся снова загружать с диска и распаковывать (картинки запакованы для уменьшения размера).

Но почему Опера выбрасывает картинки из памяти, хотя вы открыли всего-то 7 рисунков по 5 мегабайт каждый? Это же 40 мегабайт данных, а у вас несколько гигабайт оперативки!

На самом деле, в распакованном виде эти картинки занимают гораздо больше. Умножьте 2000 на 3000 и на 4 (размер пикселя) – получите 25 мегабайт. Такова “цена” одной картинки в памяти.

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

К счастью, размер кеша можно задать вручную.

Решение

  1. Откройте opera:config
  2. Найдите параметр “Cache\Figure“. По умолчанию в нём стоит 2Мб. Укажите что-нибудь вроде 1Гб (в килобайтах: “1048576”, а если памяти хватает, в 64-битной Опере можно и 2-4Гб). Сохраните настройки.
  3. Найдите параметр “UserPrefs\Automatic RAM Cache“. Отключите его.
  4. Перезагрузите Оперу

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

Если хотите, можно поднять и следующие параметры кеша:

  • Cache\Document – тоже до гигабайта-полутора
  • Disk Cache\BufferSize – до 100 мегабайт
  • Disk Cache\Size – до 200 мегабайт, или сколько места у вас есть на диске, где лежит кеш

Какой размер кеша выбрать и чем это грозит

Если у вас 32-битная Опера, не делайте общий объём Cache\Figure и Cache\Document больше гигабайта, сколько бы памяти у вас не было. В 64-битной Опере можно (и даже полезно) установить суммарный объём кеша до половины объёма вашей оперативки.

Но тогда другим приложениям не хватит памяти!
Чушь. Внимательно послушайте: в системе Windows приложения не делят память. Опера может “съесть” 8Гб оперативки, и при этом для других приложений вся память будет свободна!
Чудеса? За кулисами Windows поступает так: если программе нужна память, а свободной памяти нет, она временно “убирает” часть памяти Оперы на жёсткий диск, в файл подкачки. Потом, когда Опере опять потребуется эти данные, система их вернёт в оперативку.

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

Тогда почему в 32-битной Опере нельзя поставить больше гигабайта?
Сколько бы у вас не было физической памяти, виртуальной памяти у 32-битных приложений всего по 2 гигабайта. Когда она кончится, приложение умрёт. Если вы больше гигабайта отдадите на кеш, Опере совсем не останется памяти на всё остальное.

Почему в 64-битной Опере можно поставить больше гигабайта?
У 64-битных приложений гигантский объём виртуальной памяти. Можете отвести под кеш хоть терабайт, место всё равно останется.

Но у меня всего 8 гигабайт оперативки, откуда возьмётся этот терабайт?
Система будет убирать часть этого терабайта на диск. В физической памяти будут оставаться только самые нужные его части.

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

Что, если у меня отключен файл подкачки?
Тогда, разумеется, постарайтесь не съесть всю доступную физическую память! Сделайте кеш поменьше.

Что, если у меня постоянно запущен отжирающий 75% памяти монстро-процесс?
Тогда, разумеется, постарайтесь уместить кеш в оставшиеся 25%! Вам не нужно, чтобы система постоянно загружала-выгружала память с диска, разрываясь между вашим монстром и Оперой.

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

Бонус: какими расширениями Оперы я пользуюсь.

Windows 8 Consumer Preview

Поставил себе последнюю превьюшку Windows 8.

Boy, does it suck.

Boy, does it suck.

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

А кнопку “Пуск” теперь убрали. Так что чувствуешь себя, как десант с вертолёта в пустыне Гоби. Безжизненная равнина, на которой виднеются только Корзина и Проводник. Ну и как отсюда куда-нибудь попасть?

Сам ланчер настолько идиотский, что пользоваться им сил нет. Программы свалены в одну кучу, иконки похожи друг на друга, названия все в духе “Windows CardSpace” и “Windows MyPrivates“. Полный хаос.

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

Из свистопердюлечных программ большинство не работают, так как требуют аккаунта в Майкрософт. Я вам сейчас перечислю:
Store, Photos, Calendar, Messaging, People, Mail: нужен аккаунт.
X-Box Live: нужен аккаунт (но можно оффлайн посмотреть дебильные картинки)
Солитёр: VISIT ESRB.ORG FOR RATING INFORMATION (Я серьёзно)
Weather: Спросило, где я живу, и повисло.
Music, Video: предлагает купить музыку и фильмы. Дебильный интерфейс.

Вообще практически всё перед запуском напоминает зарегистрироваться в Майкрософт. Даже Солитёр. “А вот если б у вас был аккаунт в Майкрософт, то вы смогли бы… Блин, я не знаю, что они смогли бы. Это Солитёр, чёрт подери. Почему я сижу и сочиняю эту чушь?”

В общем, одна большая маркетинговая лабуда.