понедельник, 7 марта 2011 г.

GitHub и ключики

Одной из особенностей github.com явлеется активное использование SSH ключей. Для общения с GIT репозиторием по SSH каждый пользователь должен в вебе указать свои public SSH ключи. Но в том SSH все авторизуются все под одним пользователем git и система уже по ключу определяет к каким репозиториям давать доступ.

Таким образом получается, что public key для github.com может принадлежать только одному пользователю. Всё бы ничего и система вполне себе удобная и рабочая, но она не предусматривает наличия клинического идиота типа меня.

Я когда-то давно зарегистрировался на github.com со своим ником Alexxz, одноразовым паролем и имейлом. Ну, надо мне там что-то было, а пользоваться я не собирался. Тогда же я похоже и указал там один из своих public keys.

Недавно я там зарегистрировался с другим ником (Alexxz ведь уже занят) и завёл репозиторий. И вот сейчас мне захотелось добавить тот самый ключик на github.com к новому аккаунту и естественно я получил милую надпись
Oops! The key has already been taken. 
В ответ на это я написал им в поддержку письмо и жду ответа. Очень надеюсь, что они смогут вернуть мне мой основной ник.

А мораль у этой истории одна. Используйте самоустойчивый почтовый ящик, чтобы не было нужды пользоваться одноразовыми email адресами.

пятница, 12 ноября 2010 г.

Первое использование github

Решил тут опробовать github. Понять насколько он удобен и практичен. Для опыта выбрал разработку невидимой флешки, которая управляется яваскриптом и единственное назначение которой - проигрывать интернет-радио (Icecast, Shoutcast). Честно говоря, у меня не возникло никаких проблем с использованием github, а также я удивился насколько легко и просто удалось создать этот проект. Самая сложная и непонятная часть github для меня оказалась - хостинг сайта проекта. Но это - не основная задача github, потому записывать в минусы нельзя 8).

А вот собственно и сам проект Invisible radio player .

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

пятница, 8 октября 2010 г.

C++ оглядываясь назад

Потребовалось мне тут написать простейшую программку, которая прочитает файл, выкусит из него значение, увеличит (уменьшит) и запишет его обратно в файл. Способов реализации столь тривиальной задачи - миллион, но я захотел размять мозги и пальцы и решил написать её на C++ (да и хотелось, чтобы работало максимально быстро).

Программируя 3 года на PHP я, конечно, сильно расслабился. Прочитать файл - один вызов. Регуляркой выкусить нужное значение - второй вызов. Проверить аргументы командной строки - третий вызов. Записать изменённое значение в файл - четвёртый вызов.

Вот то, от чего я отвык:

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

Я отвык, что преобразование строки в число и числа в строку это проблема. Мне ни разу не очевидно, почему, когда надо получить первое число из строки, мне надо хардкодить, вместо того, чтобы вызвать одну готовую функцию.

Ещё расстроило немного то, что хоть C++ и объектно ориентированый язык, аргументы командной строки в него передаются также как в С через argc и argv. Пришлось даже функцию написать, которая преобразовала это безобразие в коллекцию строк.

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

воскресенье, 12 сентября 2010 г.

php unserialize

Обнаружил, что в PHP функция unserialize может серьёзно задуматься, если целевой объект - большой массив. В причинах пока не разобрался.

ini_set('memory_limit', '512M');
$file = '/tmp/1';
$data = range(1,2000000);

echo "Test serialize\n";
$time0 = microtime(1);
file_put_contents($file, serialize($data));
$time1 = microtime(1);
unserialize(file_get_contents($file));
$time2 = microtime(1);

$timeset = $time1-$time0;
$timeget = $time2-$time1;

echo "Serialize set time $timeset get time $timeget\n";


echo "Test JSON\n";
$time0 = microtime(1);
file_put_contents($file, json_encode($data));
$time1 = microtime(1);
json_decode(file_get_contents($file), true);
$time2 = microtime(1);

$timeset = $time1-$time0;
$timeget = $time2-$time1;

echo "JSON set time $timeset get time $timeget\n";

Результат работы

Test serialize
Serialize set time 1.39576292038 get time 31.2712199688
Test JSON
JSON set time 0.270380973816 get time 1.33044695854

среда, 4 августа 2010 г.

МТС: Как отключить рекламу в SMS

Компания МТС не перестаёт меня радовать. Оказывается через интернет помощник можно не только отключить все левые "бесплатные" услуги от оператора. Так можно ещё отказаться от получения рекламы. Узнал я об этом просто написав им в поддержку. Вот ответ.

Алексей, для отказа от SMS-рассылки Вы можете воспользоваться бесплатным сервисом "Интернет-Помощник". Предварительно установите, пожалуйста, пароль для доступа (от 4 до 7 цифр) к сервису, набрав с мобильного телефона комбинацию *111*25# клавиша вызова (запрос бесплатный). Для входа в "Интернет-Помощник" перейдите, пожалуйста, по ссылке https://ihelper.mts.ru/selfcare/logon.aspx, где Вам будет предложено ввести 10-значный номер телефона и пароль. Затем выберите, пожалуйста, подраздел "Тарифы, услуги и скидки", далее "Управление услугами"/"Подключить новые услуги". Добавьте услугу "Запрет приема информационных SMS и SMS/MMS с сайта МТС".



Описание услуги есть на странице http://www.mts.ru/services/communication/sms/ (вкладка Запрет приема SMS)

Вобщем я приятно удивлён. Спасибо МТС!

четверг, 1 июля 2010 г.

PHP socket_select - не подходит для написания сетевых приложений

UPD В первой редакции статьи я ошибочно писал про stream_select. Статья отредактирована подобающим образом.

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

Алгоритм до безобразия прост.

Шаг 1. socket_select рапортует, что данные в буфере. Вычитываешь их и обрабатываешь.

Шаг 2. Вычитываешь и обрабатываешь предпоследний пакет данных. И пока ты его обрабатываешь в буфер приходит недостающий последний пакет.

Шаг 3. Ты вызываешь socket_select и ждёшь данные. Так как данные уже пришли, socket_select тебе об этом не говорит. Получается, что в буфере уже лежат нужные тебе данные, но не предоставляется никакого механизма узнать об этом. Потому ты будешь ждать ответа пока данные снова не придут в этот сокет. А они могут вообще не придти, если протокол последовательный.

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

Выводы:
socket_select в общем случае не подходит для задачи написания сетевого приложения. В общем случае надо использовать работу с неблокирующими сокетами и перебор сокетов. Обнаружил, что недавно зарелизилась libevent для PHP надо будет попробовать инструмент в действии. В конце концов она работает не на селектах, а на epoll и kqueue.

UPD Для написания сетевого приложения можно использовать stream_select, она лишена указанного недостатка socket_select

PS. Спасибо Clanth

четверг, 24 июня 2010 г.

readme задолбал. Начинаю борьбу

Написал скрипт для greasemonkey, который убивает onclick у всех ссылок и перекидывает на целевую страницу.

function gs_init(){

els = document.getElementsByTagName('a');
for(el in els){
els[el].onclick="";
}
if(document.getElementsByClassName('newstext')[0].childNodes[1].childNodes[0].href)
document.location = document.getElementsByClassName('newstext')[0].childNodes[1].childNodes[0].href;
}
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", gs_init, false);
}

вторник, 22 июня 2010 г.

Поисковики

Несколько достаточно полезных поисковиков.

Поиск картинок по картинкам

http://www.tineye.com/ - находит картинки, похожие на заданную. Мне был полезен, когда надо было определить знаменитость по фотографии.

Поиск названия шрифта по картинке

http://new.myfonts.com/WhatTheFont/ - находит шрифт по хожий на шрифт с картинки. Однажды пришлось исправлять текст на картике, а подобрать похожий шрифт не получалось.

Поиск музыки по мелодии
http://www.midomi.com/ - находит музыкальное произведение по мелодии. Бывает такое, что в песне ни слова не разобрать, да и слышал ты её где-нибудь на рынке. Этот сервис поможет найти песню.

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

воскресенье, 20 июня 2010 г.

PHP abstract static function - о_0

<?php

abstract class A {
abstract static function f1();
static function f2(){
echo self::f1("\n");
}
}

class B extends A {
static function f1(){return 'test';}
}

B::f2();


Fatal error: Cannot call abstract method A::f1() in 1.php on line 6

среда, 16 июня 2010 г.

Определение фазы луны по дате на PHP

Потребовалось мне как-то определить время охоты на обортней. Вроде логично - полнолуние. Полез я разыскивать, что такое полнолуние и понял, что понятие "полнолуние" - весьма непродолжительное. Всего-то мгновение. Причем не обязательно в нашей половине планеты будет ночь. Сначала хотел ограничить ночь полнолуния - от заката до рассвета в дату полнолуния. И тут я наступил на ещё один камень, оказывается ночь - не одна дата, а (внезапно) две. Потому решил привязаться к менее дискретному понятию - фазам луны. Итог, ночь полнолуния, когда фаза луны между 14.5 и 15.5 от заката до рассвета. И вот собственно PHP код для определения фазы луны.

function get_moon_phase_normalize( $v ){
    $v = $v - floor( $v );
    if($v < 0) {
        $v = $v + 1;
    }
    return $v;
}

function get_moon_phase($timestamp){
    $date = date("Y-m-d", $timestamp);
    list($Y, $M, $D) = explode('-', $date);
    $YY = $Y - floor(0.0 + (12 - $M) / 10);
    $MM = ($M + 9)%12;
    $K1 = floor(365.25 * ($YY + 4712));
    $K2 = floor(30.6 * $MM + 0.5);
    $K3 = floor(floor(($YY / 100) + 49) * 0.75) - 38;
    $JD = $K1 + $K2 + $D + 59;
    if($JD > 2299160)
        $JD = $JD - $K3;
    $IP = get_moon_phase_normalize(($JD - 2451550.1) / 29.530588853);
    $AG = $IP*29.53;

    return $AG;
}


Алгоритм взят с http://blogs.msdn.com/b/rucoding4fun/archive/2009/09/07/arduino.aspx

понедельник, 24 мая 2010 г.

Расширение индексов InnoDB может изменить производительность неожиданным образом

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

В статье на www.mysqlperformanceblog.com наглядно показано, что это правило верно не всегда. Дело в том, что в InnoDB особое внимание уделяется clustered index. Clustered index идёт как замыкающий элемент каждого ключа. То есть индексы надо рассматривать как (a, id) и (a,b,id). Теперь, зная это, подумаем что произойдёт с запросом

SELECT * FROM table WHERE a = 3 ORDER BY id LIMIT 1;

если мы уберём ключ (а) и оставим ключ (a,b).

Вообще статья заставила меня переосмыслить использование и оптимизацию ключей в InnoDB.

вторник, 18 мая 2010 г.

Shift + NumPad. О вреде хоткеев или NumPad не работает

В один прекрасный день я обнаружил, что у меня в Ubuntu перестал работать NumPad. Вернее работать он продолжал, а вот цифры и кнопки арифметики работать перестали. Только при выключенном NumLock функционал курсора оставался на клавишах. Я переключился из Xorg в консоль и обнаружил, что в консоли NumPad работает.

Делаю вывод, что проблема сугубо программная, а не аппаратная, потому полез в гугл и вот, что я там обнаружил. Оказывается проблеме уже больше 2 лет. Появляется она, если по неосторожности нажать Shift+NumLock. В этом случае включается управление курсором мыши с клавиатуры. Так как одиночные нажатия сдвигают курсор на один пиксел, заметить, что курсор передвинулся довольно сложно. Вот и получается формулировка, что NumPad не работает. Чтобы отключить управление надо повторно нажать Shift+NumLock.

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

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

четверг, 25 февраля 2010 г.

python и чайник

икогда, икогда е стригите огти около оутбука!!
Если вы надумали поэкспериментировать с питоном, то самой очевидной и бестолковой ошибкой будет назвать файл тестового скрипта тем же именем, что и библиотеку. Убил два часа на то чтобы понять, что ошибка

File "/home/alexxz/pygame.py", line 4, in
screen = pygame.display.set_mode((640, 400))
AttributeError: 'module' object has no attribute 'display'

вызвана тем, что меня угораздило файл назвать pygame.py. Для того, чтобы исправить ситуацию просто переименуйте файл и удалите pygame.pyc.

четверг, 24 декабря 2009 г.

Audacious2 и русские ID3 теги в Ubuntu karmic coala

Для того чтобы Audacious2 научился воспринимать русские ID3 теги в Ubuntu Karmic Coala надо добавить и сгенерить соответствующую локаль ru_RU.CP1251 и изменить настройки проигрывателя. "Язык для автоматического определения кодировки" надо указать "Русский", а "Кодировку по умолчанию" - CP-1251 соответственно.

четверг, 3 декабря 2009 г.

Вот такой странный Mysql

mysql> explain SELECT * FROM last_registrations ORDER BY date DESC LIMIT 100;
+----+-------------+--------------------+-------+---------------+--------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------------------+-------+---------------+--------+---------+------+------+-------+
| 1 | SIMPLE | last_registrations | index | NULL | k_date | 4 | NULL | 100 | |
+----+-------------+--------------------+-------+---------------+--------+---------+------+------+-------+
1 row in set (0.01 sec)

mysql> explain SELECT * FROM last_registrations ORDER BY date DESC LIMIT 1000;
+----+-------------+--------------------+-------+---------------+--------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------------------+-------+---------------+--------+---------+------+------+-------+
| 1 | SIMPLE | last_registrations | index | NULL | k_date | 4 | NULL | 1000 | |
+----+-------------+--------------------+-------+---------------+--------+---------+------+------+-------+
1 row in set (0.00 sec)

mysql> explain SELECT * FROM last_registrations ORDER BY date DESC LIMIT 10000;
+----+-------------+--------------------+------+---------------+------+---------+------+--------+----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------------------+------+---------------+------+---------+------+--------+----------------+
| 1 | SIMPLE | last_registrations | ALL | NULL | NULL | NULL | NULL | 868402 | Using filesort |
+----+-------------+--------------------+------+---------------+------+---------+------+--------+----------------+
1 row in set (0.01 sec)

пятница, 20 ноября 2009 г.

PHP в руках прогрммиста на Си (микроскоп и гвозди)

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

Вот такой замечательный способ выводить большой кусок html я обнаружил у одного бывшего Сишника:

echo '<div class="search_menu"><table width="73%" cellpadding="0" cellspacing="0" border="0"><tr>';
echo '<td><div id="menu_item_internet"><a href="#" onclick="openMenu(\'internet\');return false;">Интернет</a></div></td>';
echo '<td><div id="menu_item_photo" class="aktiv"><a href="#" onclick="openMenu(\'photo\');return false;">Фото</a></div></td>';
echo '<td><div id="menu_item_video"><a href="#" onclick="openMenu(\'video\');return false;">Видео</a></div></td>';
echo '<td><div id="menu_item_files"><a href="#" onclick="openMenu(\'files\');return false;">Файлы</a></div></td>';
echo '<td><div id="menu_item_job"><a href="#" onclick="openMenu(\'job\');return false;">Работа</a></div></td>';
echo '<td><div id="menu_item_refer"><a href="#" onclick="openMenu(\'refer\');return false;">Рефераты</a></div></td>';
echo '</tr></table></div>';


пятница, 13 ноября 2009 г.

AUTO_INCREMENT в InnoDB

Весьма неожиданное поведение автоинкремента было обнаружено в InnoDB (MySQL >= 5.0).

С MyISAM всё достаточно просто - берётся значение из параметров таблицы, используется для вставки и увеличивается на единицу для следующей вставки. При вставке заданного значения в таблицу, значение AUTO_INCREMENT соответствующим образом подпрыгнет подстраиваясь под вставляемое. Если вставлялось значение меньше чем AUTO_INCREMENT, то значение счётчика не подпрыгнет. Значение AUTO_INCREMENT можно изменить при помощи ALTER TABLE `table` AUTO_INCREMENT value; При этом MyISAM не анализирует это значение, а просто задаёт. Если при вставке в уникальный столбец автоматическое значение уже есть, то происходит ошибка DUPLICATE KEY;

C InnoDB всё гораздо интереснее. Автоинкрементируемое поле должно обладать ключом. При старте сервера значение AUTO_INCREMENT сбрасывается до максимального существующего значения +1. Нумерация может быть непоследовательной из-за транзакций. Задать значение меньше максимально существующего невозможно, альтре отработает, не выдав ошибки, но фактическое значение он не изменит. Задать значение много больше максимального возможно, но при рестарте сервера оно сбросится до максимального.

PS В InnoDB начиная с MySQL 5.1 появилось понятие "блокировка автоинкремента". Подробнее об этом можно почитать AUTO_INCREMENT Handling in InnoDB

пятница, 6 ноября 2009 г.

Очередной пример говнокода

Вот так извращаются разработчики, чтобы не писать массив с названиями месяцев:

function getTime($time)
{

    $time1=substr($time,0,-1);
    $time1=$time;
    $time1=strtotime($time1);
    setlocale(LC_ALL, 'ru_RU.KOI8-R', 'ru_RU', 'ru', 'RU');
    $time1=strftime("%e %B %Y", $time1);
    $time1=convert_cyr_string ($time1, 'k', 'w') . ' года';
    return $time1;
}

Руки бы оторвать им.

пятница, 30 октября 2009 г.

php-proxy script 2

Положил я свой прокси за nginx и тут же обнаружил две неприятные проблемки. Во-первых, нельзя отвечать на HTTP/1.0 заголовком HTTP/1.1. А nginx проксирует именно по 1.0.

Вторая гадость заключена в том, что nginx разбивает Set-Cookie на несколько хедеров, а чтобы можно было установить несколько хедеров с одинаковым названием, есть второй аргумент у функции header.

Потому встречайте вторую версию: http://alexxz.ru/php-proxy-0.0.2.tar.gz

четверг, 29 октября 2009 г.

php proxy script

Потребовался мне маленький пхп прокси скрипт, который получал бы запрос и проксировал его на другой домен. Я вспомнил, когда-то давно, когда я ещё очень плохо и наивно программировал, была у меня мысль написать его. Для чего? А вот представьте: есть крупная локалка со своим хостингом. На машине хостера есть бесплатный и быстрый интернет. Задача получить какой-нибудь сайт внутри локальной сети бесплатно. И вот тогда я не смог ни найти подходящего скрипта, ни написать своего. И вдруг такая задача встала снова. Я решил, что это судьба, и потратил 3 часа на написание и отладку такого скрипта.

Да, он пока далёк от совершенства. Да, ещё не умеет кешировать картинки. Да, не поддерживает докачку. И ещё много чего другого он не умеет. Но, он уже есть. И мне его пока достаточно.

Кому нужен - берите по адресу http://alexxz.ru/php-proxy-0.0.1.tar.gz . Для использования - просто распаковать в "корень сайта".