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

23 января 2012

Основные темы пятого выпуска: FreeBSD, Haskell, парное программирование, алгоритм шифрования lameCrypt на Perl и отрывки кода на PHP, имеющие отношение к поисковой оптимизации. Предыдущие выпуски: первый, второй, третий и четвертый.

1. Один интересный прием на Haskell

Этот отрывок кода я подглядел в архиве почтовой рассылки haskell-cafe:

{-# LANGUAGE FlexibleInstances, UndecidableInstances,
ScopedTypeVariables, OverlappingInstances #-}


import System.Random

class (Bounded a, Enum a) => BoundedEnum a
instance (Bounded a, Enum a) => BoundedEnum a
instance BoundedEnum a => Random a where
  random gen = randomR (minBound :: a, maxBound :: a) gen
  randomR (f, t) gen =
    (toEnum r :: a, nextGen)
    where
      (rnd, nextGen) = next gen
      r = fromEnum f + (rnd `mod` length [f..t])

Он позволяет говорить…

r <- randomIO :: Anything

…для любого типа Anything, являющегося экземпляром классов Enum и Bounded. Это позволяет не писать множество функций genRandomTypeN для каждого типа TypeN. В некоторых программах такой прием может быть очень полезен.

2. Удаленное парное программирование в screen

Есть несколько способов организовать удаленное парное программирование. Можно использовать для этого VNC или вашу IDE (такая возможность точно есть в Visual Studio, а также существует несколько плагинов для Eclipse). Но если вы и ваши коллеги предпочитают использовать VIM, то для удаленного парного программирования вы можете использовать утилиту screen.

Допустим, программисты с никами afiskon и eax решили программировать в паре с использованием screen. Для этого afiskon заходит на unix-сервер, где также имеет учетную запись eax, и говорит:

screen -R pairprog
:multiuser on
:acladd eax

Затем eax заходит на тот же сервер и выполняет команду:

screen -x afiskon/pairprog

Вот и все! См также man screen, особенно его часть про управление доступом (команда aclchg).

3. Оптимизация сайта под запросы с опечатками

Эту идею я подглядел на Blogerator.ru (см конец статьи). Идея состоит в том, чтобы находить в статье словосочетания на латинице и дописывать в конце эти словосочетания, набранные в русской раскладке. Например, если в статье встречаются слова «perl», «freebsd» и «haskell», то в конце статьи должно быть написано «зукд», «акууиыв» и «рфылудд». Это дело несложно автоматизировать:

  // находим все словосочетания на английском
  $content = preg_replace('/<[^>]+?>/', '', get_the_content());
  preg_match_all('/\s+([a-z][a-z_\-\ ]{3,}[a-z])\s+/i',
    $content, $match);

  // приводим их к нижнему регистру и удаляем повторы
  $keywords = array_map("strtolower", $match[1]);
  $keywords = array_slice(array_unique($keywords), 0, 10);

  // получаем опечатки
  $replaceFrom = "abcdefghijklmnopqrstuvwxyz";
  $replaceTo = mb_convert_encoding("фисвуапршолдьтщзйкыегмцчня",
                                   "CP-1251", "UTF-8");
  $funcCode =
    'return mb_convert_encoding('.
      'strtr($x, "'.$replaceFrom.'", "'.$replaceTo.'"), '.
      '"UTF-8", "CP-1251");';
  $rusKeywords = array_map(create_function('$x',$funcCode), $keywords);

  // объединяем
  $keywords = implode(", ", array_merge($keywords, $rusKeywords));

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

4. BlogSpot + ZoneEdit

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

  1. Создаем блог на blogspot.com;
  2. Регистрируемся на zoneedit.com;
  3. Регистрируем доменное имя;
  4. Присваиваем доменному имени DNS’ы от ZoneEdit (например, ns5.zoneedit.com и ns7.zoneedit.com);
  5. Через ZoneEdit ставим в соответствие домену IP-адреса блогспота (на данный момент это 216.239.38.21, 216.239.32.21, 216.239.34.21 и 216.239.36.21);
  6. Проверяем настройки с помощью whois и dig (помним, что на обновление зоны нужны сутки);
  7. Если все ОК, прописываем в свойствах блога доменное имя;
  8. Получили бесплатный хостинг и бесплатные DNS сервера. Оплате подлежит только продление домена раз в год;

О том, как заработать на таком сайте, вы можете узнать из заметки Схема заработка в GoGetLinks, которая работает. Из недостатков приема — (1) зависимость от BlogSpot и ZoneEdit, (2) о добавлении сайта в SAPE придется забыть.

5. OpenDNS и GoogleDNS

OpenDNS:

  nameserver 208.67.222.222
  nameserver 208.67.220.220

GoogleDNS:

  nameserver 8.8.8.8
  nameserver 8.8.4.4

Запомнить наизусть!

6. Определение объема свободной памяти во FreeBSD

Во FreeBSD для определения суммарного объема свободной оперативной памяти с помощью, скажем, утилиты top требуется произвести дополнительные вычисления в уме. Я лично все время забываю, что с чем нужно складывать, поэтому предпочитаю использовать утилиту freecolor (легко ставится из пакеджей или портов).

Утилита freecolor

На приведенном скриншоте freecolor говорит, что 34% оперативной памяти (703 Мб) свободно. Все просто и понятно.

7. Проверка IP на наличие в спам-списках

Перепост отсюда:

www.spamhaus.org/query/bl?ip=1.1.1.1
www.senderbase.org/senderbase_queries/detailip?search_string=1.1.1.1
support.clean-mx.de/clean-mx/publog?ip=1.1.1.1
www.spamcop.net/w3m?action=checkblock&ip=1.1.1.1

Еще больше таких сервисов можно найти здесь.

8. Как не нужно шифровать данные

Некоторые задачи требуют быстрого решения. Если у вас нет времени на установку CPAN-модуля Crypt::Rijndael (код требуется развернуть на сотне серверов, нужен таск на админов, …), можете воспользоваться алгоритмом вроде этого:

#!/usr/bin/env perl

use strict;
use Digest::MD5 qw/md5_hex/;

#use String::CRC32 qw/crc32/;
#sub md5_hex { sprintf("%08x", crc32(@_)) }

sub lameCrypt {
  my ($str, $key, $decrypt) = @_;
  return '' unless length($str);

  unless($decrypt) {
    my $iv = '';
    while(length($iv) < 16) {
      my $t; $t .= rand() for(0..7);
      $iv .= md5_hex($iv.time().$$.$t);
    }
    $str = substr($iv, 0, 16).unpack("h*", $str);
  }

  my $l_len = int(length($str)/2);
  my $r_len = length($str) - $l_len;
  my $splitRe = qr/^(.{$l_len})(.{$r_len})$/o;

  my ($rounds, $left, $right) = (32, undef, undef);
  for my $i(1..$rounds) {
    ($left, $right) = $str =~ $splitRe;
    my $f = '';
    while(length($f) < $r_len) {
      $f .= md5_hex(
          $f.$left.($decrypt ? $rounds - $i + 1 : $i).$key
        );
    }
    my $j = 0;
    $right = join '', map {
                 sprintf("%x", hex($_)^hex(substr($f, $j++, 1)))
               } split(//, $right);
    $str = $right.$left;
  }

  $str = $left.$right;
  return $str unless($decrypt);
  return pack("h*", substr($str, 16, length($str)-16));
}

my $str = "secret message";
my $key = "aaa123";
my $enc = lameCrypt($str, $key, 0);
my $dec = lameCrypt($enc, $key, 1);
print "str = $str\nenc = $enc\ndec = $dec\n";

Алгоритм представляет собой сеть Фейстеля, причем размер блока равен длине (де)шефруемой строки. Если в строке нечетное количество байт, то при разбиении блока левая половина делается на один байт меньше правой. Функция F основана на алгоритме MD5.

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

9. FreeBSD — установка модулей Python из PyPI

Для установки модулей Python под FreeBSD оказалось очень удобно использовать утилиту pip.

pkg_add -r py27-pip # устанавливаем pip
pip search wordpress # поиск модулей
pip install pil # установка модуля
pip uninstall pil # удаление модуля
pip freeze # список установленных модулей

См также http://pypi.python.org/pypi.

10. Статистика поисковых запросов своими руками

В каком-нибудь footer.php дописываем:

<?php
$ref = $_SERVER['HTTP_REFERER'];
if(preg_match('/^http:\/\/(www\.)?(yandex|google)/', $ref)) {
  $fid = fopen("/path/to/ref.txt", "a");
  fwrite($fid, date("Y-m-d")."\t".$_SERVER['REQUEST_URI']."\t$ref\n");
  fclose($fid);
}
?>

Ждем пару недель, после чего скармливаем файл ref.txt следующему скрипту:

#!/usr/bin/perl

# ref.txt parser v 0.1
# (c) Alexandr A Alexeev 2012 | http://eax.me/

use strict;
use warnings;
use utf8;

use URI::Escape;

my $gre= qr"www\.google\.[^/]+/.*?[\#\?\&]{1}(?:as_)?q=([^\&]*)"i;
my $yre= qr"yandex\.[^/]+/.*?[\?\&]{1}(?:text|query)=([^\&]*)"i;
my $ire= qr"www\.google\.[^/]+/(notebook|reader|imgres|webhp)"i;

my %stat; # {url \t query} = cnt
my $fails = 0;
while(my $line = <>) {
  chomp($line);
  my($date, $url, $ref) = split /\t/, $line;
  my $query;
  if($ref =~ $gre) {
    $query = $1;
  } elsif($ref =~ $yre) {
    $query = $1;
  } else {
    next if($ref =~ m"^http://[^/]+/?$"i);
    next if($ref =~ m"www\.google\.[^/]+/search$"i);
    next if($ref =~ m"doubleclick\.net/pagead/"i);
    next if($ref =~ $ire);
    warn "Failed to parse: $ref\n";
    $fails++;
  }
  next unless($query);
  $query = uri_unescape($query);
  $query =~ s/\+/ /g;
  $query =~ s/\s+/ /g;
  $query = lc($query);
  $stat{"$url\t$query"}++;
}

if($fails) {
  warn "Total fails: $fails\n-----------\n";
}

for my $url_query(sort { $stat{$b} <=> $stat{$a} } keys %stat){
  my($url, $query) = split /\t/, $url_query;
  my $cnt = $stat{$url_query};
  printf "%09d\t%s\t%s\n", $cnt, $url, $query;
}

Затем можно прогнать полученный список запросов через wordstat.yandex.ru и закупить внешних ссылок или провести внутреннюю оптимизацию сайта (перелинковка, заголовки и тп).

Собственно, это все. Как обычно, я буду несказанно рад вашим комментариям и вопросам.

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

Метки: .


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