barbitoff programmer`s blog

Здесь я публикую заметки из программерской жизни: грабли, на которые мне случилось наступить, проблемы, для которых было найдено элегантное (или не очень) решение, а также все, с чем мне пришлось столкнуться и чем хотелось бы поделиться =)
PS Если хотите меня поблагодарить - на странице есть 3 места, чтобы это сделать =)

суббота, 30 апреля 2011 г.

Открытие ссылок в браузере в C#

System.Diagnostics.Process.Start("http://ya.ru");

суббота, 23 апреля 2011 г.

C# - аналог ключевого слова synchronized для методов в Java

Иногда нужно, чтобы некоторый метод объекта выполнялся в каждый момент времени только одним потоком (т.е. чтобы вызовы к данному методу объекта сериализовывались, т.е. ставились в очередь). Для такого контроля конечно можно использовать, например, семафор, но в Java было предусмотрено специальное ключевое слово - synchronized. В C# есть аналогичная конструкция, которая, правда, не является частью языка:
using System.Runtime.CompilerServices;

        [MethodImplAttribute(MethodImplOptions.Synchronized)]
        protected void someSyncMethod() { ... }
Также как и в Java, синхронизированными могут быть помечены сразу несколько методов класса, при этом, т.к. при вызове любого синхронизированного метода блокируется объект-хозяин, в любой момент времени возможно будет выполнение лишь одного из них.

воскресенье, 17 апреля 2011 г.

Настройка mysql-сервера на работу с cp1251 по умолчанию

В my.ini (/etc/mysql/my.cnf в Linux) прописать слудующее (в блоке [mysqld]:

character-set-server=cp1251
collation-server=cp1251_general_ci

Или соотв. параметрами командной строки.

Настроить клиент mysql на данный character set можно опцией тамже, но в блоке [mysql]:

default-character-set=cp1251

Просмотреть текущие параметры collation (соединение / БД / сервер) можно запросом:

SHOW VARIABLES LIKE 'colla%'

суббота, 16 апреля 2011 г.

Связь серверов БД в MySQL

Столкнулся с проблемой поиска в MySQL аналога db-link в Oracle / linked server в MS SQL Server, т.е. возможностью в одном запросе / процедуре использовать как локальную БД, так и удаленную.
В MySQL эта задача решена следующим образом (в версиях, начиная с 5.0):
1) Во-первых, в опциях mysql (my.ini) необходимо убрать "skip-federated" и добавить "federated" (или просто запускать mysqld с соотв. ключом).
2) На локальном сервере создается таблица, по структуре аналогичная удаленной, но в качестве движка используется FEDERATED (т.е. делаем на удаленной базе SHOW CREATE TABLE `xxx`, после чего заменяем STORAGE ENGINE на FEDERATED). Также к SQL-запросу создания таблицы нужно добавить параметр CONNECTION="mysql://user_name[:password]@host_name[:port_num]/db_name/tbl_name". Получается запрос вроде:
CREATE TABLE federated_table (
    id     INT(20) NOT NULL AUTO_INCREMENT,
    name   VARCHAR(32) NOT NULL DEFAULT '',
    other  INT(20) NOT NULL DEFAULT '0',
    PRIMARY KEY  (id),
    INDEX name (name),
    INDEX other_key (other)
)
ENGINE=FEDERATED
DEFAULT CHARSET=latin1
CONNECTION='mysql://fed_user@remote_host:9306/federated/test_table';
3) Всё, запускаем скрипт, после чего все манипуляции с данной таблицей (кроме DDL) ведут к манипуляцием с удаленной таблицей, хотя по всех запросах она будет как-будто локальная.

Если таблиц, подключающих к одной и той же удаленной БД, много, может быть удобнее создать связанный сервер командой вида:
CREATE SERVER s
FOREIGN DATA WRAPPER mysql
OPTIONS (USER 'Remote', HOST '192.168.1.106', DATABASE 'test');
Тогда в параметре CONNECTION можно будет указать только имя сервера (в данном приере - 's'). Сам этот вариант не пробовал (не возникало необходимости), не совсем пока понимаю как в данном случае задать имя удаленной таблицы.
Пока поддерживаются только MySQL удаленные сервера. Транзакции также не поддерживаются на должно уровне.
Подробнее почитать можно в документации:
http://dev.mysql.com/doc/refman/5.6/en/federated-storage-engine.html
http://dev.mysql.com/doc/refman/5.6/en/create-server.html

пятница, 15 апреля 2011 г.

undefined reference to 'timer_settime'

Проблема:
При компиляции программы, работающей с таймером, линковщик выдает ошибки типа:
undefined reference to 'timer_create'
undefined reference to 'timer_settime'
Решение: при компиляции использовать ключ -lrt

Вот примерчик их использования для периодической генерации SIGALRM:

#include <signal.h>
#include <sys/time.h>
#include <time.h>
...
timer_t mytimer;
struct sigevent timer_event;
/*
* - use signals
* - send SIGALRM
*/
timer_event.sigev_notify=SIGEV_SIGNAL;
timer_event.sigev_signo= SIGALRM;
if (timer_create(CLOCK_REALTIME, &timer_event, &mytimer) < 0)
{
printf("timer create error");
exit(0);
}
if(timer_settime(mytimer,CLOCK_REALTIME,&timerSettings,NULL)!=0)
{
printf("timer setting error");
exit(0);
}
while(1)
pause();

пятница, 1 апреля 2011 г.

Рисование дуги окружности в ActionScript

Встроенных средст рисования дуг в ActionScript нет, поэтому пришлось написать свою функцию:

protected function drawArc(gr:Graphics,centerX:Number,centerY:Number,R:Number, startAngle:Number, endAngle:Number, angleStep:Number=1):void
        {
            var xc : Number, yc : Number;
            xc = centerX+R*Math.sin(startAngle*Math.PI/180);
            yc = centerY-R*Math.cos(startAngle*Math.PI/180);
            gr.moveTo(xc,yc);
            for (var i:Number=startAngle+angleStep; i<=endAngle; i+=angleStep)
                {
                xc = centerX+R*Math.sin(i*Math.PI/180);
                yc = centerY-R*Math.cos(i*Math.PI/180);
                gr.lineTo(xc,yc);
                }
        }

Форматирование отображения чисел с плавающей точкой в ActonScript

Не нашел я в ActionScript аналога С-шного / php-шного sprintf для того, чтобы задать параметры отображения числа с плавающей точкой (Number) при преобразовании в строку.. Зато у Number есть метод Number.toFixed(p), преобразующий его в число с фиксированной запятой, где p - число разрядов после запятой.

urlencode / urldecode в ActionScript

Функции ActionScript, аналогичные вышеуказанным - escape() и unescape().

Аналог php`шного var_dump() для Flash / ActionScript

Нашел очень полезную функцию для получения дампа любых объектов в ActionScript, типа var_dump() в php. Используется она очень просто:

import com.flexer.Debug;

...

Debug.dump(someObj) ;

Сам класс можно скачать тут: http://www.flexer.info/2008/06/25/dump-debug-method-like-var_dump-function-in-php-and-debug-class/ или тут: http://narod.ru/disk/360902001/var_dump_sources.zip.html

Обновление изображения с помощью JavaScript

Иногда бывает нужно обновить динамически генерируемое изображение с сервера (например, капчу). Это можно сделать, добавив к адресу изображения рандомное число:
$("#someDynamicImg").attr('src', $("#someDynamicImg").attr('src')+"?"+Math.random());
В случае, если в адресе изображения уже есть строка поиска (как в капче), вместо "?" нужно поставить "&"

Сравнение годов в MySQL

Наткнулся тут на очень опасную особенность MySQL (может правда это свойственно не только ей и вообще является нормальным поведением, но для меня оно стало неожиданным):

В одной из таблиц базы есть поле типа YEAR. Так получилось, что в него попал год "0000", и из админки (написанной на php) я решил его удалить. Вводимый в поле год для удаления intval`ился на стороне сервера, т.е. моё желание удалить год "0000" превратилось в желание удалить год "0". Какое же было мое удивление, когда вместо одной строки, из БД удалилось 800+ строк, и причем строка с годом "0000" осталась на месте. А удалились строки с 2000 годом.

Действительно, SELECT * FROM `table` WHERE `year` = '0' выдает строки с 2000 годом, а ни как не с нулевым. Это связано с тем, что при проведении выборок или присваиваний значений полям числа 0-69 преобразуются в 2000-2069, а 70-99 - в 1970-1999.

Часто моргает лампочка на приемнике Logitech cordless rumblepad 2

Проблема такая: на ресивере часто моргает лампочка, сам геймпад работает (реагирует на вкл/выкл вибрации), винда тоже норм его видит, вот только на нажатия кнопок на паде не реагирует. Перезагрузка / перестановка драйверов не помогает.
Решение: вынуть из геймпада 1 аккум, зажать кнопки 5 и 7, и, не от пуская, вставить аккум обратно. И всё работает)

Ubuntu и щелчки винчестера на ноутбуке

Поставил Ubuntu 10.10 Desktop на нетбук Asus EEEPC T101MT и столкнулся со следующей проблемой: при питании от батареи винчестер с периодичностью раз в 20-40 сек издает странные звуки (типа щелчков), как будто все время останавливается, паркует головки, а потом снова раскручивается. При этом под родной Win7 все в порядке. Понятно, что дело это нехорошее, Load Cycle Count в SMART винчестера растёт с пугающей скоростью (на момент решения проблемы он составил 1010), да и звуки неприятные. Снятие галочки "замедлять винчестеры по необходимости" в "Управлении питанием" ничего не изменило.

Решилась проблема следующим образом: в /lib/hdparm/hdparm-functions заменить:
строка 82/254
hdparm_set_option -B128
на:
hdparm_set_option -B255
Все, щелчки прекращаются. Вообще, возникают они из-за т.н. Advanced Power Managment винчестера, которые включается убунтой при переходе на питание от батареи. Значение по-умолчанию (128) по-разному воспринимается разными винтами, видимо мой WD`шка его поняла совсем экстремально.

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

Настройка D-Link DIR-615 для Beeline

Промучался пол дня с настройкой DIR-615 под билайн, а все вот почему: оказалось, что адрес L2TP сервера надо прописывать не как доменное имя (tp.internet.beeline.ru), а в виде IP, иначе роутер сервера не видет. Почему, не знаю, но оно так (через nslookup сервера с компа тоже почему-то не видно, а вот пингом он пингуется, оттуда я и узнал его IP).

Рабочие настройки под питерский Билайн приведены ниже:


Посмотреть на Яндекс.Фотках

Политика безопасности JavaScript и локальные IP

В соответствии с политикой безопасности JS запросы (XMLHttpRequest) на локальные адреса (например, в подсети 192.168.x.0) запрещены (если только сам сайт, с которого идет запрос, не локален). Причем никакой ошибки не отображается (по крайней мере при использовании jQuery, даже через метод .ajax с указанием обработчика ошибок), просто запроса не происходит (по крайней мере в Опере тишина наблюдается даже в консоли ошибок JS; как дела обстоят в FF не в курсе, т.к. меня на тот момент, когда я столкнулся с данной проблемой, интересовала Opera с её UserJS).

document.domain и префикс "www"

По крайней мере по мнению Opera, www.mysite.ru и mysite.ru являются РАЗНЫМИ доменами, со всеми вытекающими (например, запрещается доступ из одного окна / фрейма в родительское / дочернее). Странно, но факт, приходится считаться, иначе вылазит что-нить такое:

ReferenceError: Security error: attempted to read protected variable

Редирект средствами JavaScript

location.replace("newURL");

Работа с cookies в JavaScript


2 функции, облегчающие чтение / запись cookies:
function setCookie (name, value, expires, path, domain, secure) {
      document.cookie = name + "=" + escape(value) +
        ((expires) ? "; expires=" + expires : "") +
        ((path) ? "; path=" + path : "") +
        ((domain) ? "; domain=" + domain : "") +
        ((secure) ? "; secure" : "");
}

function getCookie(name) {
    var cookie = " " + document.cookie;
    var search = " " + name + "=";
    var setStr = null;
    var offset = 0;
    var end = 0;
    if (cookie.length > 0) {
        offset = cookie.indexOf(search);
        if (offset != -1) {
            offset += search.length;
            end = cookie.indexOf(";", offset)
            if (end == -1) {
                end = cookie.length;
            }
            setStr = unescape(cookie.substring(offset, end));
        }
    }
    return(setStr);
}

Отключение кэширования HTML-страницы

<meta http-equiv="Cache-Control" content="no-cache, no-store, max-age=0, must-revalidate"/>
<meta http-equiv="Pragma" content="no-cache"/>
<meta http-equiv="Expires" content="Fri, 01 Jan 1990 00:00:00 GMT"/>

Выполнение JSONP-запросов в jQuery


JSONP - полезный подход для выполнения кроссдоменных асинхронных запросов, позволяющий обойти изместно ограницение XMLHTTPRequest. Смысл его заключается в добавлении на страницу тега <script>, загружающего данные формата JSON со стороннего домена:
<script src="/some/crossdomain/url/here" type="text/javascript"></script>

Полученный код должен содержать нечто вроде:
var data = {one : "12", two : "34"}
someCallback(data);

, где someCallback() - функция, которая должна обработать полученный JSON.

Чтобы получатель запроса знал, какую именно функцию написать вместо someCallback, имя функции должно передаваться в тексте запроса, например: URL_запроса?callback=myCallBack.

Но это всё теория, и если пользоваться jQuery, всё оказывается намного проще:

$.getJSON(crossdomainRequestUrl, function(data) { ... })


, где crossdomainRequestUrl должен заканчиваться на "&callback=?". Конечный знак вопроса укажет jQuery, что выполняется JSONP зарпос. При этом имя callback-функции указывать не нужно. Полученный JSON будет передан, как обычно, в обработчик, заданный вторым параметром $.getJSON. На серверной части значение параметра callback, которое будет сформировано jQuery самостоятельно, нужно исопльзовать как имя callback функции, вызов которой нужно вставить в выдаваемый в ответ JS-скрипт.

IE и Array.indexOf()

В IE, вплоть до 8 версии, нет метода indexOf для объектов Array. Чтож, пусть это будет на совести индусов из Microsoft, придется жить без него, ну или добавлять в свои скрипты такой фикс:
if(!Array.indexOf){
    Array.prototype.indexOf = function(obj){
    for(var i=0; i<this.length; i++){
        if(this[i]==obj){
            return i;
        }
    }
    return -1;
    }
}

Получение текстового содержимого узла в IE

Во всех "приличных" браузерах у узла есть свойство node.textContent. В ИЕ (вплоть до ИЕ8) это не работает, поэтому приходится делать так:
nextDiv.firstChild.nodeValue (если текстовый узел - первый, или вообще единственный). Иначе - можно использовать следующую функцию:

function getElemText(node){
    return node.text || node.textContent || (function(node){
        var _result = "";
        var childrens = node.childNodes;
        var i = 0;
        while (i < childrens.length) {
            var child = childrens.item(i);
            switch (child.nodeType) {
                case 1: // ELEMENT_NODE
                case 5: // ENTITY_REFERENCE_NODE
                    _result += arguments.callee(child);
                    break;
                case 3: // TEXT_NODE
                case 2: // ATTRIBUTE_NODE
                case 4: // CDATA_SECTION_NODE
                    _result += child.nodeValue;
                    break;
                case 6: // ENTITY_NODE
                case 7: // PROCESSING_INSTRUCTION_NODE
                case 8: // COMMENT_NODE
                case 9: // DOCUMENT_NODE
                case 10: // DOCUMENT_TYPE_NODE
                case 11: // DOCUMENT_FRAGMENT_NODE
                case 12: // NOTATION_NODE
                // skip
                break;
            }
            i++;
        }
        return _result;
    }(node));
}

В принципе, её можно порядком укоротить, убрав ненужные case. Ну или использовать $(node).text() из jQuery ;)

Отмена submit формы по нажатию Enter (работает везде, даже в Opera!)

Бывает нужно отменить submit формы по нажатию клавиши Enter, когда фокус находится, например, в текстовом поле (мне это понадобилось при реализации всплывающих подсказок ввода). Видел в интернете множество решений, некоторые из которых пугали своей сложностью или работали не во всех браузерах. В итоге остановился на таком варианте: добавить этому полю обработчики keyup, keydown и keypress следующего вида:
function(event){
    event = event || window.event;
    // если Enter - обработать
    if(event.keyCode==13)
      {
      // отменить действия по-умолчанию для Enter, остановить всплытие
      event.preventDefault ? event.preventDefault() : (event.returnValue=false);
      event.stopPropagation ? event.stopPropagation() : (event.cancelBubble = true);
      return false;
     }
   }

Возможно, немного избыточно, но точно работает в IE8, FF 3.6.8 и Opera 10.6, и, в отличие от других вариантов, не требует модифицировать html код формы, выносить кнопку submit за пределы формы, и делать прочие телодвижения, особенно противопоказанные, если Вы пишите библиотечное решение, а не одну единственную страницу.

Если добавить только один обработчик keydown, перестает работать в Опере.

Один минус - не работает при отключенном JavaScript, но это, по-моему, свойственно всем решениям - при отключенном JS либо остается работать submit по Enter, либо пропадает возможность submit`a вообще,что, на мой взгляд, куда опаснее.

Аналог php-функции trim на JavaScript

trimStr(s)
{
  s = s.replace( /^\s+/g, '');
  return s.replace( /\s+$/g, '');
}

Запуск NetBeans под Linux с английским языком


При установке NetBeans из репозиториев Ubuntu он встает с русским языком интерфейса, что лично мне не очень удобно, т.к. привык под виндой работать с английским, и от перевода немного коробит.

Для того, чтобы запустить NetBeans с английским языком интерфейса, нужно в командной строке задать:


/usr/bin/netbeans --locale en:US


(ну или создать Launcher c такой командной строкой)

Изменение положения и порядка кнопок Свернуть/Восстановить/Закрыть в Gnome


После обновления на Ubuntu 10.4 у многих кнопки управления окном съехали в левую часть заголовка окна (сделано это было разработчиками Ubuntu намеренно, не знаю правда, из каких соображений). У меня правда после обновления этого не произошло, однако недавно они туда уехали самопроизвольно. Работать стало дико не удобно (привыкнуть можно конечно, но хотелось сделать как было, а не привыкать), поэтому (спасибо MagicLover`у - http://magiclover.ru/ubuntu.html) я нашел как вернуть все на свои места. В командной строке надо набрать:

sudo apt-get install gconf-editor
gconf-editor

После этого выбрать apps ->metacity ->general ->button layout, где задать что-то вроде "menu:minimize,maximize,close". Здесь двоеточие разделяет левый и правый край заголовка окна. menu - это кнопка меню в левой част окна, ну а с остальными наверное понятно. Ещё можно написать в какои-либо месте "spacer", тогда в соотв. промежутке между кнопками появится расстояние.

Главное не запускать gconf-editor из-под sudo (как советует MagicLover), иначе настройки будут менятся для рута, а не для текущего пользователя.

Кроссбраузерное затемнение экрана на CSS+jQuery


Кроссбраузерно.

CSS:

#TB_overlay
 {
 position: fixed;
 z-index: 3; /* при необходимости можно поменять на другой */
 top: 0;
 left: 0;
 height: 100%;
 width: 100%;
 background-color: #000;
 filter:progid:DXImageTransform.Microsoft.Alpha(opacity=55);
 -moz-opacity: 0.55;
 -khtml-opacity: 0.55;
 opacity: 0.55;
 }
* html #TB_overlay
 {
 position: absolute;
 height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + "px");
 }

Java Script:

if(!jQuery("body").find("#TB_overlay").is("div")) /* если фон уже добавлен не добавляем повторно */
 {
 if(!jQuery.browser.msie) /* если браузер не ИЕ фоном будет div */
  jQuery("body").append("<div id='TB_overlay'></div>");
 else /* иначе добавляем iframe */
  jQuery("body").append("<div id='TB_overlay'><iframe scrolling='no' frameborder='0' style='position: absolute; top: 0; left: 0; width: 100%; height: 100%; filter:alpha(opacity=0)'></iframe></div>");
 }
$("#TB_overlay").fadeIn("fast");



Получение GET параметров запроса из JavaScript

function getParam(sParamName)
{
var Params = location.search.substring(1).split("&"); // отсекаем "?" и вносим переменные и их значения в массив
var variable = "";
for (var i = 0; i < Params.length; i++)
{ // пробегаем весь массив
if (Params[i].split("=")[0] == sParamName)
{ // если это искомая переменная
// если значение параметра задано, то возвращаем его
if (Params[i].split("=").length > 1) variable = Params[i].split("=")[1];
return variable;
}
}
return "";
}

Работа с iframe из JavaScript



Получить доступ к документу iframe`a можно следующим образом (работает в FF, Opera, IE7):

var frameDocument=document.getElementById("iframeID").contentWindow.document; 

К полученному frameDocument можно применять все методы документа, например, getElementById.

Для того, чтобы из родительской страницы отслеживать перезагрузку iframe`a, можно повесить на него onLoad:
<iframe onLoad="someFunc()" ... ></iframe> 

someFunc() будет вызываться при каждой новой загрузке содержимого фрейма.

Центрирование div-блоков


Центрирование div блоков во всех приличных браузерах делается следующим образом:

<div style="margin-left: auto; margin-right: auto; width: 50%;">


В ИЕ как всегда все через (_)(_), поэтом приходится делать так:

<div style="text-align:center;">
 <div style="width: 50%;">

 Содержимое блока DIV

 </div>
</div>

В итоге универсальный вариант центрирования div-блока выглядит вот так:

<div style="text-align: center;">
 <div style="width: 50%; margin-left: auto; margin-right: auto; ">  

 Содержимое блока DIV

 </div>
</div>