Странности с Google Chrome

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

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

chrome broken

Еще иногда бывает что гифки не показываются. Для их запуска приходится щелкнуть рядом, что бы выделить гифку, тогда запускается. Проверял на разных сайтах и без расширений - без результата. Не знаю что с этим делать, на всякий случай воткнул на сайт такой код, success для ajax действий.

$('#tab_content' ).height( $('#tab_content' ).height()+1 );

Может сталкивался кто? Подскажите куда копать.


javascript, неведомая хуйня      

Как стать "Rock Star" программистом

Вот несколько советов:

  • Найдите хорошего руководителя который будет критиковать ваш код, пусть он научит вас решать проблемы на собственном примере. Вы поймете что выросли, когда сможете оспорить его мнение правильными аргументами.
  • Всегда увеличивайте сложность и масштабы проблем которые пытаетесь решать. Запомните что у большинства людей нет 20-летнего опыта, у них есть один год опыта повторяющийся 20 раз. Не становитесь таким.
  • Заботьтесь о таких вещах как документация, имена методов и функций, покрывайте код тестами. Ваш код должен выглядеть профессионально и доступно, ведь с ним будут работать и другие люди.
  • Изучайте все доступные библиотеки и модули, даже если они не требуются сейчас, вы все равно должны знать об их существование. Если вам приходится работать с незнакомыми компонентами — старайтесь полностью разобраться с их назначением.
  • Если вы что-то не понимаете, то это должно стать стимулом пойти и разобраться в этом. Всегда погружайтесь глубоко.
  • Используйте лучшую IDE для вашего языка, максимально изучите ее и выучите все хоткеи. Хорошая IDE очень сильно ускорит вас.
  • Когда вы сталкиваетесь с новой проблемой, например вы никогда не работали с SOAP/XML, прежде чем начинать программировать почитайте что пишут в интернете на эту тему. Это поможет вам понять как другие люди решают задачи и с какими проблемами сталкиваются.
  • Семь раз отмерь, один раз отрежь.
  • Не забывайте что вы делаете продукт которым будут пользоваться другие. Постоянно общайтесь с заказчиками, следите за их ожиданиями, убеждайтесь что они знают чем вы занимаетесь и вы понимаете чего они хотят.

Это вольный перевод этой заметки, просто захотелось оставить тут.


работа, разработка      

Gmail Show-M.-Later

Gmail Show M later

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

Есть более древние варианты в галерее скриптов, Gmail Snooze например, но они позволяют работать только с дневными интервалами и устроены таким образом, что письмо добавленное в 23:00, в 01:00 снова окажется в инбоксе. Поэтому я сначала модифицировал, а потом полностью переписал. В моей реализации, письма живут более правильной жизнью.

Испытательный срок длился две недели. Это только последней стабильной версии, до этого были еще другие реализации, пробовал использоваться Cache вместо ScriptDB, но он слишком часто терял ключи. С этой версией проблем не возникало, пару раз, было что скрипт зависал, но я забил на это дело, т.к. повторить ошибку мне не удалось.

Касательно объемов данных. Каждому пользователю google выделяется 50мб под ScriptDB, но может быть и больше, если у вас платный аккаунт. Что бы упереться в размер данных, нужно будет очень постараться, поэтому до первой проблемы, решать ее не собираюсь. Тестировал максимум на 20 активных письмах, все прошли полный цикл без ошибок. Наверно, если писем будет больше, то возможен тайм–аут. Если столкнулись с проблемой, пишите, буду исправлять.

Инструкцию и комментарии мне писать было лень, поэтому они не сильно подробные, но я постарался все расписать максимально доступно, в стиле пойди сюда — кликни тут.

Буду рад ответить на вопросы.
Буду очень рад, если появится перевод на другие языки.

https://github.com/Rpsl/Show–M–Later


gmail, javascript      

Nginx изменение картинки по рефереру

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

В целом весьма логично, если раньше все боялись за свой трафик, то теперь вопросы трафика мало кого интересуют, поэтому и приоритеты сместились в другую сторону. Хотя я видел ситуацию, когда на одном из рабочих ресурсов, образовался хотлинк канал японского трафика на 250mb/s.

Попробуйте открыть это изображение в новой вкладке (убедитесь что броузер не закешировал)

раньше тут была картинка

Рассматривая разные решения, я нашел самый простой способ, делать это с помощью nginx и встроенного модуля ngx_http_referer_module.

test_images.conf

server {
        listen 80;
        server_name images.dev;
        root /www/data/test_images;

        location /test_images {
                valid_referers none blocked server_name images.dev;

                if ($invalid_referer) {
                        rewrite ^(.*)/(.*)$ /images_bad/$2 last;
                }

                rewrite ^(.*)/(.*)$ /images_ok/$2;
        }

        location /images_ok {
                internal;
                alias /www/data/images/test_images/ok;
        }

        location /images_bad {
                internal;
                alias /www/data/images/test_images/bad;
        }
}

Собственно механика очень простая. Мы определяем с помощью "valid_referers" список правильных доменов, можно добавить в него домены поисковиков, например, что бы при поиске картинок пользователю показывалась правильная картинка. Потом мы создаем два внутренних location, которые отвечают за показ правильных и не правильных картинок. В случае не правильного реферера, в конструкции if мы делаем редирект на локейшн с картинками, которые должны отдаваться жуликам, которые ленятся скачивать картинку на свой сервер. Ну вот, в общем и все. Осталось только позаботиться, что-бы у нас были необходимые картинки.

Тут можно решать разными путями, например, при создание оригинальной картинки создавать ее "обработанный" вариант. Но мне больше нравится ленивая загрузка, которую я, когда-то давно, делал в iCacher, основная идея проста: при попытке запроса "обработанной" картинки, если ее нету, управление передается скрипту, который проверяет ее оригинал и делает ее "обработанную" копию, которая отдается пользователю. При повторном обращение, запрос не дойдет до скрипта и пользователю отдастся статический файл. Таким образом мы получаем генерацию изображений по требованию. Еще можно добавить крон скрипт, который будет удалять "обработанные" картинки через 30 дней.

Я не уверен, что моя реализация хороший пример и буду рад если вы ее покритикуете. Плюс, я так и не придумал как избавиться от if в данном случае ( вариант хранения файлов в images_ok/1/ считаю уебским ).


banners, cache, images, nginx      

Шутка дня

<!‐‐[if lte IE 7]> <style> * {font-family: "Comic Sans" !important;} </style> <![endif]‐‐>

css      

Thunderbird всё

thunderbird Многие люди радуются тому, что Mozilla закрывает поддержку Thunderbird с целью сфокусироваться на других задачах, а мне печально. Многие считают, что thunderbird это пережиток прошлого и при текущем витке интернета он остается не востребованным, ведь есть gmail и прочие облака. Я, честно говоря, даже чуть-чуть согласен, но объясните мне, как пользоваться Exchange'м в Linux?

При всей своей медлительности и неповоротливости, thunderbird оставался единственным вменяемым почтовым клиентом для *nix систем. Еvolution? Claws mail? Вы их видели? Это же верх уебищности. И веб-интерфейс у Exchange вменяем только под 9 IE, под остальными броузерами он выдает урезанную версию себя, которой пользоваться не возможно.

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

Что делать? Я в печали.


mail, thunderbird, работа      

Почему жилье дорожает

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

Я Вам сейчас очень просто объясню, почему дома подорожали к зарплате - бензин тут ни при чем. Допустим, мы - я, Вы и Хроноскопист летели на самолете через Тихий океан. В пути мы втроем накушались абсента, надебоширили, отломали дверь от туалета, и нас за это выкинули в море через аварийный выход. По счастью, рядом с местом нашего падения обнаружился маленький безымянный полинезийский остров. Выбравшись на берег, мы посовещались, и решили считать его новым государством под названием Соединенные Штаты Абсента (США).

Когда нас выкидывали из самолета, то багажа нам, естественно, не выдали. Поэтому, всех материальных и нематериальных активов у нас - только туалетная дверь, которую Вы таки прихватили с собой. И вообще, несмотря на абсент, Вы у нас оказались самым запасливым - в бумажнике у Вас, совершенно случайно, обнаружилась банкнота в $100. Таким образом, в наших США имеются нефинансовые активы - дверь, и финансовые активы, они же денежная масса - $100. Это все наши сбережения. Поскольку у нас больше вообще ничего нет, то можно сказать и так - у нас есть один материальный актив - дверь, обеспеченный денежной массой в $100. Т. е. наша дверь стоит $100.

Немного протрезвев, мы решаем, что надо как-то обустраиваться. Самый быстрый из нас оказался Хроноскопист. Он тут же объявил, что создает банк и готов взять в рост имеющиеся у населения денежные сбережения под 3% годовых - ну не сидится человеку без дела. Вы отдаете ему $100, и он их записывает в блокнот в статью "Пассивы -\ Дипазиты". Но я тоже не лаптем щи хлебал - зря я что ли столько времени занимаюсь расследованием экономического мухлежа - я знаю как изъять у Вас и дверь и $100. Я предлагаю Вам взять Ваши $100 в рост под 5% годовых. Вырываю листик из своего блокнота и пишу на нем - "Аблегиция на $100 под 5% годовых". Вы чувствуете, что Вам поперло. Забираете деньги у расстроенного Хроноскописта с дипазита и отдаете их мне в обмен на мою аблегацию.

Я беру Ваши $100 и кладу их на дипозит в банк обратно обрадованного Хроноскописта.
По хорошему, на этом можно было бы и успокоиться и пойти всем заняться делом - пальму потрясти или за моллюсками понырять, снискать себе хлеб насущный, так сказать. Но Вы ж знаете - я неуемный финансовый гений, такие пустяки как кокосы и устрицы меня не интересуют. Помыкавшись по нашему острову - 50 шагов от южного побережья до северного, и 30 с запада на восток, я придумываю гениальную комбинацию. Я подхожу к Вам и предлагаю на пустом месте заработать еще 1% годовых. Взять в банке Хроноскописта кредит под 4%, и купить у меня еще одну аблигацию под 5%. Вторую аблегацию на $100 я тут же выписываю на блокнотном листике, и машу ею у Вас перед носом. Недолго думая, Вы бежите в банк и берете кредит $100 под залог моей первой аблегации на $100. Они там есть - я их туда положил на дипазит. Вы отдаете мне заемные $100 и прячете вторую аблегацию к себе в бумажник - теперь у Вас есть моих аблегаций на $200. А $100 я кладу в банк - теперь у меня там $200 на дипазите. Хроноскопист аж подпрыгивает от радости - кредитный бизнес попер.

Думаете я на этом остановлюсь? Ага, сейчас - я уже выписал Вам третью аблегацию. Бегом в банк за кредитом под залог второй аблегации. Ближе к вечеру, набегавшись по острову с этой сотней баксов и изодрав все листочки из блокнота на аблегации, мы имеем следующую картину. У Вас на $5000 моих аблегаций, а у меня на $5000 дипазитов в банке. Теперь, я чувствую, что пришло время прибрать Вашу дверь к рукам. Я предлагаю купить ее у Вас за $100. Но Вы вредничаете - дверь-то всего одна, и заламываете цену в $1000. Ну, $1000 так $1000 - в конце концов у меня на депозите лежит целых $5000. Я на последнем блокнотном листочке направляю платежное поручение Хроноскописту, перевести $1000 с моего дипазита на Ваш, и забираю Вашу дверь.

Если нашу бухгалтерию отдать американскому экономисту с гарвардским дипломом, он сообщит нам, что наши США располагают $1000 материальных активов в виде двери, и $10000 финансовых активов в виде аблегаций и дипазитов. Т. е. что стоимость нашего совокупного имущества увеличилась за день в 110 раз.

Менее тонкий и образованный человек сказал бы, что мы - три дебила, у нас как была одна дверь и $100, так и осталось, и что только конченные дебилы могли целый день рвать листочки из блокнота, вместо того, чтобы нарвать кокосов. Кто из них прав - решайте сами. Но механизм относительного роста цен на дома именно такой, что в США, что в Японии, что в России.


деньги, жизнь      

Percona Server Configuration Wizard

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

percona

Проходим небольшой тест, отвечая на вопросы и на выходе имеем подобный конфиг:

# Generated by Percona Configuration Wizard (http://tools.percona.com/) version REL5-20120208
# Configuration name zlo generated for gmail@rpsl.info at 2012-07-05 10:31:23

[mysql]

# CLIENT #
port                           = 3306
socket                         = /srv/mysql/mysql/mysql.sock

[mysqld]

# GENERAL #
user                           = mysql
default_storage_engine         = InnoDB
socket                         = /srv/mysql/mysql/mysql.sock
pid_file                       = /srv/mysql/mysql/mysql.pid

# MyISAM #
key_buffer_size                = 32M
myisam_recover                 = FORCE,BACKUP

# SAFETY #
max_allowed_packet             = 16M
max_connect_errors             = 1000000
skip_name_resolve
sysdate_is_now                 = 1
innodb                         = FORCE

# DATA STORAGE #
datadir                        = /srv/mysql/mysql/

# CACHES AND LIMITS #
tmp_table_size                 = 32M
max_heap_table_size            = 32M
query_cache_type               = 0
query_cache_size               = 0
max_connections                = 500
thread_cache_size              = 50
open_files_limit               = 65535
table_definition_cache         = 1024
table_open_cache               = 256

# INNODB #
innodb_flush_method            = O_DIRECT
innodb_log_files_in_group      = 2
innodb_log_file_size           = 128M
innodb_flush_log_at_trx_commit = 1
innodb_file_per_table          = 1
innodb_buffer_pool_size        = 1456M

# LOGGING #
log_error                      = /srv/mysql/mysql/mysql-error.log
log_queries_not_using_indexes  = 1
slow_query_log                 = 1
slow_query_log_file            = /srv/mysql/mysql/mysql-slow.log

Ну и в качестве бонуса, рекомендую почитать доклад "Optimizing MySQL Configuration" от Percona


mysql, percona      

Nginx allow POST static files

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

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

Кратко о проблеме:

Все знают о том что в Facebook'e есть iframe страницы, но не все знают что Facebook эти страницы запрашивает через POST, а не через GET, как делают все остальные. Поэтому все fb:iframe приложения запрашивая у Nginx'а страницы в ответ будут получать ошибку:

405 "Method Not Allowed"

Вариант который предлагает dotZero выглядит примерно вот так ( это я для истории и поисковых запросов оставлю ):

upstream fb_static {
    server localhost:8001;
}

server {
    listen       443;
    server_name  _;

    #allow_static_post on;

    error_page 405 =200 @405;

    location @405 {
        proxy_method GET;
        proxy_pass http://fb_static;
    }
}

server {
    listen 8001;
    server_name _;

    location / {
        root "/var/www/fb";
    }
}

Вариант конечно хороший и самое главное рабочий, но чисто эстетически он убогий. Давайте попробуем так:

server {
    listen  80;
    server_name _;

    # Тут мы описываем поведение
    # для нашей кастомной ошибки
    error_page 405 = $uri;

    # Дефолтный location
    location / {
        access_log off;
        root    /srv/path
        try_files $uri $uri/index.html /index.php$is_args$args;
    }
}

Что тут происходит? Мы складываем весь статический контент который будет запрашивать facebook в отдельную директорию, просто, для красоты. Определяем location для этой директории, который будет всегда возвращать код ошибки, например, 599. И определяем поведение для обработки этой ошибки, как попытку отдать данные по этому урлу.

Вот и все, работает. Читайте мануалы.

UPD: вернул конфиг до состояние обработки напрямую 405 error_page, т.к. поведение описанное до этого, не совсем соответствовало реальности. Таки образом, после запроса файла через POST, будет выдана 405 ошибка, которая обработается в error_page 405 = \$uri и будет отправлена в location /. То есть либо файл найдется и будет отдан, либо управление будет передано в index.php.


facebook, nginx      

PHP: detect UTF-8

Пару недель назад, мне кто-то доказывал, что mb_detect_encoding, работает в разы быстрее своих надуманных конкурентов. Задача простая, проверить входящую строку на принадлежность к UTF-8. Логика простая, либо UTF-8, либо нет. В повседневной жизни, обычно не приходится выбирать из зоопарка кодировок и, чаще всего, строка либо в utf8, либо в cp1251.

Сделал простой синтетический тест. Прогнал определение через функцию 10000 раз. Посмотрел кто быстрее.

Вариант 1, который мне нравится:

$s = microtime(true);

for( $i=0; $i<10000; $i++ )
{
    $string = 'sdf;gklaj;skdjf;sdkfls;dfjk';

    if( preg_match('//u', $string ) )
    {

    }
}

$e = microtime(true);

echo "\n\n" . $e-$s;

Средний результат выполнения скрипта на моей машине ~0.020 сек. Сравнивал я его с более правильным решением, которое выглядит так:

$s = microtime(true);

for( $i=0; $i<10000; $i++ )
{
    $string = 'sdf;gklaj;skdjf;sdkfls;dfjk';

    mb_detect_encoding( $string, array('UTF-8'), true );
}

$e = microtime(true);

echo "\n\n" . $e-$s;

Средний результат выполнения скрипта на моей машине ~0.050 сек. После этих тестов, решил прогнать на больших объемах данных, сгенерировал текст размером 10к байт и пропустил через ф-ции. Для preg_match время выполнения составило ~0.120 сек, для mb_detect_encoding ~0.7 сек. Из этих изысканий можно сделать вывод, что определение через preg_match работает в разы быстрее чем стандартные механизмы, но, вероятно, проигрывает в количестве доступых фич. На самом деле, есть еще три миллиона разных способов решить эту задачу, расскажите чем пользуетесь вы?


php, utf