пятница, 3 марта 2017 г.

What's the difference between JavaScript and Java?

Lots of people working in IT don't understand that Java and JavaScript are almost completely unrelated to each other. The best explanation how similar they are would be to say in a non-techie way:
Java and Javascript are similar like Car and Carpet are similar. 
or
Java is to JavaScript as ham is to hamster.
One may say "Ham is to Hamster... technically they are both meat...". JavaScript sounds like it has something to do with Java. It doesn’t.

Yes, both are programming languages and belong to the programming world. However, aside from this apparently confusing similarity, the two languages could not be further from the same thing.  Apart from some superficial syntactical similarities, they have nothing in common.

This page will be the page for the guys, who are still asking this kind of question, will redirect them here :)

пятница, 22 июля 2016 г.

Картинка путь предпринимателя и путь стартапера

Попалась на глаза очень замечательная картинка, иллюстрирующая путь предпринимателя и путь стартапера (картинка из интернета, копирайты сохранены).


Согласно статистике, более 90% (девяносто процентов) всех интернет-стартапов заканчиваются неудачей в течение первых 120 (ста двадцати) дней.

четверг, 10 декабря 2015 г.

error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

It seems everyone at least once faced issues with SSL certificates on Mac. That happens after certain period of time, or after another system update, and everything that uses OpenSSL stops to work.

My situation was next: I did system update on OSX El Capitan, plus updated webserver and PHP... and then composer and rest things which are using OpenSSL stopped to operate. On composer update and self-update I was kept getting error messages alike:

bash-3.2# composer self-update
Downloading https://getcomposer.org/version

[Composer\Downloader\TransportException]
The "https://getcomposer.org/version" file could not be downloaded: SSL operation failed with code 1. OpenSSL Error messages:
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
Failed to enable crypto
failed to open stream: operation failed

Investigation showed, that there's no easy way to restore the previous state. So the decision was made to extract certificates from Apple’s Keychain via simple bash script:

cert_file="$( openssl version -d | awk -F'"' '{print $2}' )/cert.pem"
mkdir -p "${cert_file%/*}"
security find-certificate -a -p /Library/Keychains/System.keychain > "$cert_file"
security find-certificate -a -p /System/Library/Keychains/SystemRootCertificates.keychain >> "$cert_file"

I hope this article will help someone to do economy of time! Happy coding!


вторник, 29 сентября 2015 г.

Как почистить состояние GIT и удалить теги (clean GIT state and delete GIT tags)

Хотел бы опубликовать список простеньких команд GIT, которые, в принципе, должны быть постоянно под рукой, для возврата гита в исходное состояние, согласно origin, если интенсивно идёт работа с бренчами и тегами.

Для того чтобы почистить все бренчи, которые не существуют больше на remote, но оставить свои локальные, которых нет в origin, в GIT существует простая команда:

git fetch [remote] --prune

# или
 
git remote prune [remote]

Для того, чтобы удалить все теги GIT, которые больше не существуют в origin, но остались локально воспользуйтесь командой:

git fetch --prune [remote] +refs/tags/*:refs/tags/*

Таким образом, если ваш remote имеет название origin, тогда команды примут следующий вид

git fetch --prune origin +refs/tags/*:refs/tags/*
git fetch origin --prune

среда, 3 сентября 2014 г.

Сodeigniter нашёл нового хозяина

Практически год прошёл с момента, когда EllisLab объявили о своих намерениях о прекращении поддержки CodeIgniter как отдельного продукта и старте поиска новых хозяев для проекта. Этого шага многие ожидали, ExpressionEngine выродился в самостоятельную единицу и уже больше не пересекался с CodeIgniter и поддержка двух движков для EllisLab не имела никакого экономического обоснования.
И вот недавно в официальном твитере, проскочила интригующая реплика, о том что нашли новый дом для CI:
Whew! Lengthy search and process is winding down. @codeigniter has a new home. Details will follow soon.
Интрига держится до сих пор, других официальных сообщений со стороны EllisLab пока не поступало. Очень интересно, кто же, всё-таки, будет новым хозяином столь популярного фреймворка!
___
Update: проект был передан British Columbia Institute of Technology

пятница, 19 октября 2012 г.

CodeIgniter: Affected Rows fix on DB insert/update batch functions

During last phase of the development on another CodeIgniter based project, I did import/export functionality, and used Active Record’s insert/update batch functions.

I figured out, that CodeIgniter’s core with CI_VERSION=2.1.2 doesn’t allow you to calculate the number of affected rows on batch functions. That’s the function to get the affected rows doesn’t work when using the batch insert or update functions. More details posted in the issue https://github.com/EllisLab/CodeIgniter/issues/126, it was opened a year ago, though in the open state still.

I decided to fix that myself, patched the native CI’s Active Record Class. From now the batch functions could return the number of affected rows instead of only TRUE. If everything worked but no records were affected the function would return 0. When there's an error in the parameters passed it will return FALSE, so no confusion here.

Here are the methods I patched, so you could freely use them or just send that to CI’s devs to fix that issue in the newer versions of the framework:

    /**
     * Insert_Batch
     *
     * Compiles batch insert strings and runs the queries
     * (affected rows fix by WebAurum (http://webaurum.blogspot.com),
     * for more information see issue https://github.com/EllisLab/CodeIgniter/issues/126 )
     *
     * @param    string    the table to retrieve the results from
     * @param    array    an associative array of insert values
     * @return    object
     */
    public function insert_batch($table = '', $set = NULL)
    {
        if ( ! is_null($set))
        {
            $this->set_insert_batch($set);
        }

        if (count($this->ar_set) == 0)
        {
            if ($this->db_debug)
            {
                //No valid data array. Folds in cases where keys and values did not match up
                return $this->display_error('db_must_use_set');
            }
            return FALSE;
        }

        if ($table == '')
        {
            if ( ! isset($this->ar_from[0]))
            {
                if ($this->db_debug)
                {
                    return $this->display_error('db_must_set_table');
                }
                return FALSE;
            }

            $table = $this->ar_from[0];
        }
            
        $affected_rows = 0;

        // Batch this baby
        for ($i = 0, $total = count($this->ar_set); $i < $total; $i = $i + 100)
        {

            $sql = $this->_insert_batch($this->_protect_identifiers($table, TRUE, NULL, FALSE), $this->ar_keys, array_slice($this->ar_set, $i, 100));

            //echo $sql;

            $this->query($sql);

            $affected_rows += $this->affected_rows();
        }

        $this->_reset_write();


        return $affected_rows;
    }

    /**
     * Update_Batch
     *
     * Compiles an update string and runs the query
     * (affected rows fix by WebAurum (http://webaurum.blogspot.com),
     * for more information see issue https://github.com/EllisLab/CodeIgniter/issues/126 )

     *
     * @param    string    the table to retrieve the results from
     * @param    array    an associative array of update values
     * @param    string    the where key
     * @return    object
     */
    public function update_batch($table = '', $set = NULL, $index = NULL)
    {
        // Combine any cached components with the current statements
        $this->_merge_cache();

        if (is_null($index))
        {
            if ($this->db_debug)
            {
                return $this->display_error('db_must_use_index');
            }

            return FALSE;
        }

        if ( ! is_null($set))
        {
            $this->set_update_batch($set, $index);
        }

        if (count($this->ar_set) == 0)
        {
            if ($this->db_debug)
            {
                return $this->display_error('db_must_use_set');
            }

            return FALSE;
        }

        if ($table == '')
        {
            if ( ! isset($this->ar_from[0]))
            {
                if ($this->db_debug)
                {
                    return $this->display_error('db_must_set_table');
                }
                return FALSE;
            }

            $table = $this->ar_from[0];
        }

        $affected_rows = 0;

        // Batch this baby
        for ($i = 0, $total = count($this->ar_set); $i < $total; $i = $i + 100)
        {
            $sql = $this->_update_batch($this->_protect_identifiers($table, TRUE, NULL, FALSE), array_slice($this->ar_set, $i, 100), $this->_protect_identifiers($index), $this->ar_where);

            $this->query($sql);

            $affected_rows += $this->affected_rows();
        }

        $this->_reset_write();

        return $affected_rows;
    }

суббота, 29 сентября 2012 г.

Codeigniter Bootstrap Pagination

Twitter Bootstrap стал безумно популярным фронт-энд фреймворком. Всё чаще и чаще слышу от клиентов, хочу «бутстрэп» (хотя они до конца сами не понимают что это), это больше дань моде, ну это такое. В этой статье хочу рассказать, как адаптировать стандартый pagination класс CodeIgniter-а под новомодный Bootstrap style.

Я находил много решений, вплоть до кастомного MY_Pagination класса для стилизации Bootstrap под CI, каждый ухитряется, как может. Но, я полагаю, это не лучший выход. Вы лишаетесь гибкости, перекрывая нативный класс пагинации кодигнайтера, если выходит новая версия CodeIgniter обновился класс Pagination, то прийдётся заново его адаптировать и искать что изменилось.

Гораздо более удобный способ, это через конфигурацию самого Pagination навесить все необходимые стили и изменить только «обвёртку» для стандартных элементов интерфейса. Сделать это легко. Создаём в папке application/config/ файл с именем pagination.php. В этот файл дописываем следующий конфиг для Pagination Class:

/* twitter bootstrap overrides */
$config['full_tag_open'] = '<div class="pagination pagination-centered"><ul>';
$config['full_tag_close'] = '</ul></div><!--/pagination-->';

$config['first_link'] = '&laquo; First';
$config['first_tag_open'] = '<li class="prev page">';
$config['first_tag_close'] = '</li>';

$config['last_link'] = 'Last &raquo;';
$config['last_tag_open'] = '<li class="next page">';
$config['last_tag_close'] = '</li>';

$config['next_link'] = 'Next &rarr;';
$config['next_tag_open'] = '<li class="next page">';
$config['next_tag_close'] = '</li>';

$config['prev_link'] = '&larr; Previous';
$config['prev_tag_open'] = '<li class="prev page">';
$config['prev_tag_close'] = '</li>';

$config['cur_tag_open'] = '<li class="active"><a href="">';
$config['cur_tag_close'] = '</a></li>';

$config['num_tag_open'] = '<li class="page">';
$config['num_tag_close'] = '</li>';
/* END twitter bootstrap overrides */

Ну и финальный штрих, это подгрузить наш конфигурационный файл в место, где происходит инициализация pagination в самом контроллере, например:


$this->config->load('pagination', TRUE);
$config = array_merge($this->config->item('pagination'), Array(
  'base_url'   => site_url('items/'),
  'total_rows'  => $total,
  'per_page'   => 10,
  'uri_segment'  => 2
  ));
$this->load->library('pagination');
$this->pagination->initialize($config);

Всё, теперь в любом месте, где вы будете рендерить элементы для постраничной навигации, будет выводиться Codeigniter Bootstrap Pagination. Приведеный выше пример гарантированно рабочий и отлаженный, работает на версии CodeIgniter Framework 2.1.2 и Twitter Bootstrap Version 2.1.1.

понедельник, 9 июля 2012 г.

Задержка события ready и особенности работы jQuery.holdReady()

jQuery.holdReady() появился c версии v.1.6 и позволяет отложить выполнение события ready. Наиболее часто используется для того чтобы задержать событие ready, в случае динамической загрузки скриптов (или плагинов jQuery).

Простейший пример использования:

$.holdReady(true);
$.getScript("myplugin.js", function() {
$.holdReady(false);
});

Вроде как всё лаконично и можно использовать, но не тут-то было. У него есть одна неприятная особенность: jQuery.holdReady() не будет иметь никакого эффекта, если перед этим уже произошло ready event.


Что это означает на практике? – Если мы попытаемся сделать динамическую загрузку дополнительных JavaScript файлов, к примеру ajax-ом после того как страница уже была загружена, и хотели бы придержать использование методов и объектов JS-плагинов, до полной загрузки необходимых файлов, то holdReady() не отработает вообще.

Выходом из ситуации, когда нужно подождать пока не инициализируются все объекты, а использование jQuery.holdReady() уже невозможно после наступления ready event-а может быть:
1. использование callback вызовов после успешной ajax-загрузки и только тогда использовать сами загруженные объекты;
2. Сделать периодический опрос по таймеру (setTimeout), пока объявляемая функция или объект не станут доступными.

понедельник, 28 ноября 2011 г.

Which is correct: "bare" or "bear"?

Забавная переписка была недавно с англоговорящим клиентом. Из-за очередной задержки со стороны клиента, он мне приносил извинения и прозвучала фраза наподобие:

... We are finalizing a UI person and hence the delay. Please bare with us ...

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

Так вот, как же всё-таки правильно надо было написать "bare" или "bear"? У обоих слов совершенно разные значения:
1. у слова bare значение "неприкрытый", "голый";
2. а слово bear – переносить/перевозить, выдерживать нагрузку, терпеть.

Таким образом, оборот вида "Bear with me" будет означать "потерпите немного", в то время как "Bare with me" будет к кому-то просьбой раздеться :-)

Правильным примером употребления, в нашем случае, могло бы стать предложение вида:

Please bear with us while we remodel our store.

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

воскресенье, 23 октября 2011 г.

MySQL Replace Substring with Another String

В последнее время, часто начали задавать вопрос, как заменить подстроку в строке в MySQL во всей таблице и напрочь отказываются посмотреть в мануал.
Для того чтобы найти часть оригинальной строки и заменить её другой подстрокой в SQL запросах в MySQL применяется функция REPLACE(). Простейший запрос на поиск и обновление записей во всей таблице примет вид:

UPDATE [table_name] SET [field_name] = REPLACE([field_name],'[string_to_find]','[string_to_replace]');

Например, если ваш блог на WordPress переместился в директорию на уровень ниже или на другой домен, то для замены/обновления permalinks в WordPress нужен простой MySQL запрос на update:

UPDATE wp_posts SET post_content = REPLACE(post_content, 'http://www.oldsite.com/blog', 'http://newsite.com');

вторник, 26 апреля 2011 г.

Disabling arrow keys at Fancybox (отменить перехват курсорных клавиш в Fancybox)

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

Чтобы обойти дефолтное поведение, решил создать дополнительную переменную в конфиге, и подправить функцию навигации плагина.

Для начала я добавил новую переменную в файл, где хранились дефолтные значения оцпий для Fancybox, назвал её disableNavButtons:

$.fn.fancybox.defaults = {
 ...
 disableNavButtons : true,
 ...
};

Затем, пропатчил функцию fancybox_set_navigation, в условных выражениях добавил обработчики на проверку равен ли e.keycode 37 или 39 и при этом currentOpts.disableNavButtons выставлено в false. И если условие выполняется, то переназначить действия для левой и правой курсорных клавиш.

function fancybox_set_navigation() {
  $(document).unbind('keydown.fb').bind('keydown.fb', function(e) {
    if (e.keyCode == 27 && currentOpts.enableEscapeButton) {
      e.preventDefault();
      $.fancybox.close();
    
    } else if (e.keyCode == 37 && !currentOpts.disableNavButtons) {
      e.preventDefault();
      $.fancybox.prev();
    
    } else if (e.keyCode == 39 && !currentOpts.disableNavButtons) {
      e.preventDefault();
      $.fancybox.next();
    }
    ...

вторник, 29 марта 2011 г.

Про что директора не говорят своим менеджерам

Что-то, меня, уже в какой раз, потянуло на чтение мыслей по управлению процессами, проходящими в IT-компаниях...  Попались на глаза, и решил перепечатать у себя в блоге, тезисы из книги "Чёрная книга менеджера" Панкратова В.

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

  1. Работа. Если ты сказал, что что-то невозможно, а потом сделал – кого волнует, что ты скажешь в следующий раз? Дела не делаются у одних и тех же людей, независимо от компании или проекта. Когда понимаешь, что ошибся, нормальному человеку хочется делать ещё и ещё. “Сделал или не сделал” не имеет никакого отношения к “знал или не знал”.
  2. Опыт. Ты чего-то стоишь, пока ты в этой конторе, а за ее пределами ты снова идешь искать работу, чтобы продать свои навыки и продолжать верить в иллюзию, что твои навыки ценны сами по себе. Твой навык не самостоятелен, на рынке он будет конвертироваться в бабло, только если кто-то даст тебе проект, заказчика и людей.
  3. Деньги. Если тебя от бизнеса нужны только бабки и в голове у тебя только “дай”, то откуда у меня будет по отношению к тебе хоть полграмма уважения? С чего ты тогда удивляешься, что получая прибавку к зарплате, ты автоматически продвигаешься в очереди на увольнение? Если человек самостоятельно делает хотя бы 80% поставленных ему задач, значит мы ему платим среднюю ЗП по рынку. Если около 100% – то платим выше рынка и думаем, как его голову приложить еще. Если человек делает все на автомате, его надо заменить кем-то попроще и включить его голову туда, где не хватает головы.
  4. Люди. У твоего сотрудника есть вещи поважнее тебя и твоих планов.
  5. Мотивация. Как твои люди будут относиться к делу, к компании, к Заказчику и друг-другу если ты им талдычишь что вокруг все плохо и все полные урюки? Откуда у твоих людей возьмется мотивация что-то делать, если ты сам этого не хочешь? Если человек не делает, его надо учить, если не помогает – тогда лечить, если все равно не помогает – тогда мочить. Увольнять и идти дальше, даже урезанным составом. Пусть работает трое, чем не работает четверо.
  6. Время. Приходить вовремя – это такой знак уважения. Уважения, к которому ты не привык, потому что еще сам не стоишь ничего, а демонстрируя неуважение, ты дешевеешь прямо на глазах. Как менеджер, трать время на управление людьми, а не на исследование технологий и т.п., ибо: а) тебе платят не за это; б) ты всё равно не станешь лучше своих подчинённых, которые занимаются работой в режиме нон-стоп.
  7. Опоздания. Перезванивай, если опаздываешь. Предупреждай, если сроки проекта сдвигаются. У заказчика тоже могут быть планы, он может терять реальные деньги или с трудом построенную репутацию, которая может стоить дороже, чем весь твой отдел с потрохами.
  8. Уважение. Если ты не уважаешь, значит ты еще сам не заработал и не испытал уважения. С такими не договариваются, таким просто говорят что надо делать. Нервный, это тот, кто кричит на своего шефа, а тот кто кричит на подчиненных, тот просто хам. Самые серьезные вещи говорятся тихо и спокойно. Да, иногда не теми словами, но очень спокойно. Уважение к заказчику строится на том простом факте, что нам он платит бабки, которые уже успел заработать сам.
  9. Проблемы. Решая вопрос, решай проблему, а не человека. Любая задача решается множеством способов, если только ты не дотянул ее до проблемы и не решаешь свои комплексы, вместо того, чтобы делать дело с помощью тех умных и талантливых людей, которые тебе доверил бизнес, надеясь что ты сможешь или научишся делать дело.
     

Такая словесная шоковая терапия, в первую очередь неплохо прочищает мысли и чакры. Как сказал автор в предисловии, "Эта книга — неприятная прививка от заносчивости и звезд в глазах, которыми иногда болеем мы как ИТ-шники...".

True

четверг, 3 марта 2011 г.

Совещения - реальная альтернатива работе

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

Гибкая методология разработки (англ. Agile software development) — это концептуальный каркас, в рамках которого выполняется разработка программного обеспечения...

Основные идеи, которые продвигает agile методология, можно свести к следующим пунктам:

  • Личности и их взаимодействия важнее, чем процессы и инструменты;
  • Работающее программное обеспечение важнее, чем полная документация;
  • Сотрудничество с заказчиком важнее, чем контрактные обязательства;
  • Реакция на изменения важнее, чем следование плану.

Ну как такое может работать в типичной команде разработчиков?! Где каждый ленится написать строчку кода, добавить комментарий к функции или задокументировать сложную логику, продумать тест-кейсы... Сразу хочется распечатать и повесить весёлый плакат, замечательно иллюстрирующий это:

Сильный тимлид, профессиональная команда разработчиков, жёсткая система менеджмента, адекватное планирование и тщательное QA - вот залог качественного программного продукта на выходе.

среда, 2 марта 2011 г.

Графическая интерпретация тригонометрических функций (graphical interpretation of trigonometric functions)

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

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

Графическая интерпретация тригонометрических функций

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

вторник, 1 марта 2011 г.

Простой RSS-ридер на PHP (Simple RSS reader using PHP)

Думаю, что такое RSS все знают, это базовый XML формат для публикации сводной информации по сайту. Сама аббревиатура RSS как раз это и раскрывает: Really Simple Syndication (RSS 2.x), что дословно переводится как «очень простой сбор сводной информации».

Допустим, у нас есть главный сайт и отдельно блог с новостями, они разнесены на разные поддомены и работают с разными БД, на разных CMS. Нам необходимо встроить в новостной блок на главной странице последние новости, опубликованные в блоге. Для этого нам вовсе не понадобится писать функций импорта, который будет обращаться к другой БД, разбираться со структурой таблиц, например, движка WordPress. Есть более простой путь это реализовать – сделать экспорт-импорт через RSS.

Функцию экспорта краткой версии новостей (постов из блога) нам писать не придётся, RSS-каналы есть в любом блоггерском движке. А вот написать клиентскую часть, на PHP, тоже не составит труда, для этого надо написать простой парсер RSS-канала.

Что же представляет из себя RSS-канал, давайте рассмотрим. Корневой элемент RSS-документа содержит единый элемент channel. Элемент channel содержит метаданные о канале, включая интересующие нас title (заголовок), language (язык), pubDate (дата обновления канала) и link (URL блога). Так же внутри содержатся статьи, заключённые в тег item. Каждый item имеет элемент link, с URL на статью, ну и непосредственно заголовок title и описание description, которые содержат простой текст.

PHP5 имеет достаточно «жирные» инструменты, для доступа к различным узлам XML, а всё благодаря SimpleXML API. Есть прекрасная функция simplexml_load_file(), которая и делает всю работу. Она не только загружает документ из указанного URL, парсит (разбирает) документ, но и ставит указатель на корневой элемент документа, которым выступает у нас 'rss'.

Приведу пример простого RSS-ридера на PHP используя SimpleXML API:

<?php
$items_to_display = 2;
$url = "http://webaurum.blogspot.com/feeds/posts/default";
$rss = simplexml_load_file($url);
if ($rss)
{
  echo '<h1>' . $rss->channel->title . '</h1>';
  echo '<br/>' . $rss->channel->pubDate . '<br/>';
  $items = $rss->channel->item;
  $item_count = 0;
  foreach($items as $item)
  {
    $title = $item->title;
    $link = $item->link;
    $ts = strtotime($item->pubDate);
    $published_on = date("Y-m-d", $ts);
    $description = $item->description;
    echo '<h3><a href="' . $link . '">' . $title . '</a></h3>';
    echo '<span>' . $published_on . '</span>';
    echo '<p>' . $description . '</p>';
    if(++$item_count >= $items_to_display)
      break;
  }
}
?>

Скрипт обращается по адресу указанному в переменной $url, считывает RSS feed, парсит документ, и выводит количество записей, ограниченных количеством, заданном в переменной $items_to_display.

Такой скрипт вообще можно положить отдельным файлом на сервере, и делать простой SSI include в обычную статичную html страницу, во всех местах, где нужен этот блок новостей.

пятница, 18 февраля 2011 г.

Функция цитирования текста для ответного сообщения (function for wrapping/quoting text on replies)

Писал приложение, в котором была необходимость создать внутреннюю почту, с возможностью отослать письмо и c возможностью на это email потом ответить. Возникла задача цитирования текста предыдущего сообщения при ответах на входящие письма, наподобие, как делают всякого рода email clients, или тот же gmail с web-интерфейсом.

Например:

> Это quoted text.
> Всё что тут было написано, было написано
> не мной, во входящем сообщении.

Можно, конечно, взять и написать примитивную логику, подобно:

str_replace("\n","\n> ","> ".$text);

Но, это плохое решение, если хочется сделать красивое повторное цитирование уже ранее процитированного текста. Обратите внимание, как это делает gmail или другие email клиенты:

> повторное цитирование:
>
>> Это quoted text.
>> Всё что тут было написано, было написано
>> не мной, во входящем сообщении.

При повторном цитировании текста,  вначале строки, возле угловой скобки ставится отступ лишь в том случае, если рядом стоит «чистый текст», ранее не обвёрнутый в кавычки цитирования. Так что без дополнительной логики, простым str_replace() тут не обойтись.

Оказалось, что найти такую функцию на PHP среди готовых решений не так-то просто. Поэтому предлагаю свой вариант реализации на PHP:

// function for wrapping/quoting text on replies
public function quote_text(&$body)
{
  $body_quote = ">";        // quotation mark
  $rewrap_body = explode("\n", $body);
  $body = '';
  $cnt = count($rewrap_body);
  for ($i=0;$i<$cnt;$i++)
  {
    if (preg_match("/^(>+)/", $rewrap_body[$i], $matches)) {
      $gt = $matches[1];
      $body .= $body_quote . str_replace("\n", "\n" . $body_quote
         . "$gt ", rtrim($rewrap_body[$i])) ."\n";
    } else {
      $body .= $body_quote . (!empty($body_quote) ? ' ' : '') . str_replace("\n", "\n" . $body_quote . (!empty($body_quote) ? ' ' : ''), rtrim($rewrap_body[$i])) . "\n";
    }
    unset($rewrap_body[$i]);
  }
}

Функция quote_text принимает переменную по ссылке в качестве единственного параметра. Результатом работы этой функции будет процитированный текст, обвёрнутый в метки $body_quote, по схеме цитирования, описанной выше.

четверг, 3 февраля 2011 г.

Подсказки в input: text полях (default search text at input using jQuery)

На сайтах часто попадаются подсказки в input: text полях, например, в полях для поиска, когда написан текст «Поиск по сайту», а при вводе в него значения – он исчезает и пользователь может ввести критерий поиска.

Алгоритм работы данного функционала прост. Задается текст-подсказка (описание поля) по умолчанию, зачастую бледного цвета, а при фокусе на элементе всё очищается. При потере фокуса, если значение поля осталось пустым, то снова возвращается текст подсказка.

Самый простой способ, для «любителей» размещать весь код инлайн, реализуется при помощи JS, навесив два события onfocus и onblur на input элемент формы:

<input type="text" value="Поиск по сайту…" onfocus="if (this.value == 'Поиск по сайту…') {this.value = '';}" onblur="if (this.value == '') {this.value ='Поиск по сайту…';}" />

Есть, конечно, и много уже готовых плагинов для отображения подсказки в input полях, но мне почему-то больше всех приглянулся jquery.hint.js (как пользоваться расписано тут).  Как мне показалось, jquery.hint.js вполне удачное, маленькое и элегантное решение для такой задачи.

В любом случае, плагины уже нашёл после того, как написал собственное решение для этой задачи, да и подгружать отдельный js файл на каждую html страницу - непозволительная роскошь, из-за одного маленького input в блоке поиска. Вот этот кусочек js-кода, который с использованием jQuery навешивает подсказку для input text поля с id-шником search:

$('#search').focus(function(){
    if($(this).val() == $(this).attr('title')){
      $(this).val('').css('color','#333');
    }
  }).blur(function(){
    if($(this).val() != $(this).attr('title') && $.trim($(this).val()).length == 0){
      $(this).val($(this).attr('title')).css('color','#AAA');
    }
}).blur();

Сам элемент input выглядет следующим образом:

<input id="search" type="text" name="search" value="" title=" Поиск по сайту…" />

Скрипт использует значение, которое задано в атрибуте title в качестве текста подсказки и выводит его серым цветов в самом input. Как только пользователь ставит/убирает курсор в поле для ввода, срабатывает событие focus/blur, которое и показывает/скрывает текст подсказки и меняет CSS стиль для элемента.

Для того чтобы submit формы не происходил с нашим фейк-значением подсказки, я навесил дополнительное событие onsubmit="checkFakeSearchValues();" на элемент form. Эта функция выглядит следующим образом:

function checkFakeSearchValues(){
  var search = $('#search');
  if($(search).val() == $(search).attr('title')){
    $(search).val('');
  }
}

и проверяет значение поля для ввода перед submit формы.  Если пользователь ничего не вводил в поле, значение осталось равно значению текста подсказки, то оно будет почищено и оставлено пустым.

четверг, 21 октября 2010 г.

Коды кнопок добавления в социальные закладки (Share Button Codes)

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

Код формирования ссылки для сервиса Facebook:
http://www.facebook.com/sharer.php?u={ссылка на страницу}
Код формирования ссылки для сервиса Twitter:
http://twitter.com/home/?status={заголовок страницы}+{ссылка на страницу} 
Код формирования ссылки для сервиса Google Buzz:
http://www.google.com/buzz/post?url={ссылка на страницу}&title={заголовок страницы}
Код формирования ссылки для сервиса Я.ру:
http://my.ya.ru/posts_add_link.xml?URL={ссылка на страницу}&title={заголовок страницы}
Код формирования ссылки для сервиса Вконтакте:
http://vkontakte.ru/share.php?url={ссылка на страницу}
Код формирования ссылки для сервиса LiveInternet:
http://www.liveinternet.ru/journal_post.php?action=n_add&cnurl={ссылка на страницу}
Код формирования ссылки для сервиса Livejournal:
http://www.livejournal.com/update.bml?event={ссылка на страницу}&subject={заголовок страницы}
Код формирования ссылки для сервиса Memori:
http://memori.ru/link/
Код формирования ссылки для сервиса Мой Мир (mail.ru):
http://connect.mail.ru/share?share_url={ссылка на страницу}
Возможно ещё что-то упустил - смело пишите в комментариях - добавлю.

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

Программист должен проверять результат своей работы перед передачей в тестирование

Читая сегодня Хабр не смог удержаться, чтобы не процитировать золотые слова, с которыми я согласен на все 100%:

Программист должен проверять результат своей работы перед передачей в тестирование
«Моё дело писать код, а их дело проверять», «Ну а их-то зачем понанимали?» — можно услышать в таких командах. Это элементарное отсутствие гигиены, работа ради «отписаться». Где вы видели журналиста, который не перечитывает свою статью перед тем, как передать её в редакцию? Если в коллективе есть программист, который проповедует такой подход, его нужно как можно скорее ликвидировать. Какой бы он ни был классный специалист.

Рекоммендую

Попробуйте надёжный хостинг от Scala Hosting