Страницы

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

FireFox не любит рекурсий

Если писать много и сложно, то может случиться так, что fireFox вдруг решит выпендриться и написать too many recursions и скрипт дальше отказываеться работать вообще.. Ты начинаешь лихорадочно искать, где ж у меня рекурсия, может она и есть, но тут лучше скажу про другой нюанс. JavaScript использует механизм замыкания, через него мы любим создавать объекты. Так вот это тоже подпадает под это гениальное сообщение в консоли ошибок..

Например...

function Rect(x_,y_,x1_,y2_){
this.x=x_;
this.y=y_;
this.x1=x1_;
this.y1=y1_;
this.some_func(i){
////
this.x+=i;
this.y+=i;


///

}

};

function some_func(){

for(var f=0;f<10000;f++){
var r=new Rect(f,f,f+100,f+100);
r.some_func(f/199);


}
return true;

}
Если очень упорствовать, то можно в цикле нарваться на сообщение too many recursions.. То есть злоупотреблять с созданием объектов не стоит. Прям аналогии с С++ и выделением памяти.

Удаление всех элементов массива

Вроде нет ничего проще....Но гениальных вариантов дофига, как оказалось
можно например в цикле делать pop каждому...Страшно॥Да ;)
Ладно долго страдал вот такой формой

var ar=new Array();
ar.push(7);
ar=[]; //delete all


А потом вчитавшись в документацию начал делать так вот

var ar=new Array();
ar.push(7);
ar.length=0; //delete all
Последнее понравилось больше...

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

Использование алгоритма AES при помощи библиотеки openssl

Столкнулся с тем, что нет описания интерфейс к алгоритму AES в библиотеке OpenSSL, а несколько русскоязычных статей оказались мало пригодно, по тому простому поводу, что в примерах давали не работающий код. Хотя нельзя отрицать, что там была и полезная информация, которая помогла лучше понять англоязычную документацию на openssl.org .
Собственно функция фишрования :
unsigned long int do_crypt(unsigned char *infile,int inlen ,unsigned char * key)
{
// unsigned char key[32]; /* 256- битный ключ */
unsigned char *last_buf;//for last bytes that is
int sum_len=0;
int outlen=0;
EVP_CIPHER_CTX ctx;
const EVP_CIPHER * cipher;
/* Обнуляем структуру контекста */
EVP_CIPHER_CTX_init(&ctx);
/* Выбираем алгоритм шифрования */
cipher = EVP_aes_256_cbc();
/* Инициализируем контекст алгоритма */
EVP_EncryptInit(&ctx, cipher, key, NULL);
/* Шифруем данные */
last_buf=infile;
if(!EVP_EncryptUpdate(&ctx, last_buf, &outlen, infile,inlen ) ) return 0;
sum_len+=outlen;
last_buf=infile+outlen;
if(!EVP_EncryptFinal(&ctx, last_buf, &outlen)) return 0;
sum_len+=outlen;
EVP_CIPHER_CTX_cleanup(&ctx);
return sum_len;//возвращаем длину зашифрованых данных



};
Собственно функция принимает указатель на строку, которую надо зашифровать, длинну строки и ключ ( 256 бит в данном случае). Данная функция справляется нормально с шифрованием данных до 65 мегабайт, больше не тестировал. Возвращает длину зашифрованных данных, которая может отличаться от исходной длинны.
Функция дешифрования :

int do_decrypt(unsigned char *infile,int inlen,unsigned char * key)
{
unsigned char *last_buf;//for last bytes that is
int outlen,sum_len,temp_len,last;


EVP_CIPHER_CTX ctx;

const EVP_CIPHER * cipher;
/* Обнуляем структуру контекста */
EVP_CIPHER_CTX_init(&ctx);
/* Выбираем алгоритм шифрования */

cipher = EVP_aes_256_cbc();
/* Инициализируем контекст алгоритма */
EVP_DecryptInit(&ctx, cipher, key, NULL);
outlen=temp_len=0;
last_buf=infile;
if(!EVP_DecryptUpdate(&ctx, last_buf, &outlen,infile, inlen)) return 0;
memcpy(infile,last_buf,outlen);
last_buf=infile+outlen;
if(!EVP_DecryptFinal(&ctx, last_buf, &temp_len)) return 0;
memcpy(infile+outlen,last_buf,temp_len);

EVP_CIPHER_CTX_cleanup(&ctx);

return outlen+temp_len;
}


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

*(infile+outlen+temp_len)='\0';

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

Тестировщику на заметку

Недавно наткнулся на статью про тестирование на http://habrahabr.ru, там кроме
всего прочего был в комментариях тезис :

"Тестирование относительно новая область, теоретическая база отсутствует"
С которым категорически не согласен, во всех аспектах, тестирование появилось вместе с программированием. Дальше вы мне возразите "Но им не занимались профессионально". Ага как же?! Им занимались профессионалы почище нас с вами. Так как в далекие 80-е - 90-е годы программирование было уделом институтов с перфокартами, то соответственно сложным программированием занимались люди владеющие на нормальном уровне "Теорией Вероятности" а так же "Теорией Планирование Экспериментов", которая и по сути является прототипом нынешней теоретической базы тестирования. Разрабатывалось, в частности, данное направление академиком МГУ В.В Налимов.

P.S
Я не ботан- асспирант в университете, не преподователь университета, не был заучкой( у меня порядочно троек есть), хоть и магистр.

P.S.S
Все придумано до нас

вторник, 28 декабря 2010 г.

SSL, openssl и генерация сертификатов

Что бы не забывать
В состав дистрибутива openssl входят скрипты CA.sh и CA.pl (/usr/local/openssl/misc)
создаем корневой сертификат
./CA.sh -newca
генерируем личный ключ и сертификационный запрос сервера
./CA.sh -newreq
и подписываем его своим корневым сертификатом.
./CA.sh -sign
переписываем ключ и сертификат сервера в служебный каталог Apache
cp newreq.pem /usr/local/etc/apache/sslkey/server.key
cp newcert.pem /usr/local/etc/apache/ssl.crt/server.crt
Файл корневого сертификата ./demoCA/cacert.pem необходимо
распространить по клиентским компьютерам.

среда, 22 декабря 2010 г.

Где брать идеи

1. Идеи не появляются от просмотра телевизора.

2. Идеи иногда появляются после прослушивания лекции.

3. Идеи часто появляются во время чтения книги.

4. Хорошие идеи появляются из плохих идей, но только если последние есть в достаточном количестве.

5. Идеи ненавидят конференц-залы, особенно такие конференц-залы, где сохранился опыт критики, личных выпадов или занудства.

6. Идеи возникают, когда сталкиваются непохожие вселенные.

7. Идеи часто стремятся соответствовать ожиданиям. Если люди ожидают идею, то она появится.

8. Идеи боятся экспертов, но восхищаются умом начинающих. Немного осведомленности не помешает.

9. Идеи идут косяками, пока вы не испугаетесь. Уилли Нельсон написал три из своих главных хитов за одну неделю.

10. Идеи приходят благодаря неприятностям.

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

12. Идеи приходят из природы.

13. Иногда идеи приходят от страха (обычно это в кино), но часто – от уверенности.

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

15. Однако иногда идеи прокрадываются к нам, когда мы спим и слишком обмякли, чтобы бояться.

16. Идеи замечаешь краем глаза, а иногда – находясь в душе, когда не прилагаешь никаких усилий.

17. Посредственные идеи склонны копировать то, что, похоже, работает как раз в эту минуту.

18. Более крутые идеи перескакивают через посредственные.

19. Идеям не нужен паспорт, и они часто пересекают границы (всякого рода) безнаказанно.

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

Сет Годин...

четверг, 9 декабря 2010 г.

Оптимизация кода

Архитектурно правильный код - это хорошо. Он красиво выглядит, легко читается, все структурировано, а потом оказывается, что код работает долго, а все вроде бы красиво.
Так вот не всегда "правильный" с точки зрения стиля, архитектуры код самый быстрый.
Ну так получилось, так бывает, теория и практика знаете ли. А теперь идеи ускорения.

Идея 1. Назовем ее развертывание цикла.

Код :

my $ref = $dbh->selectall_arrayref(q[SELECT id FROM categories
WHERE c_status='active']);
my (@res);
my $count=10;
foreach my $tmp (@$ref){
my $ref=$dbh->selecall_hashref(qq[SELECT id,title,text,ts
FROM articles
WHERE category=$tmp
ORDER BY id DESC LIMIT $count],'id');
my @r;
push @r,$ref->{$_} foreach( key %$ref);
push @res,\@r;
}



То есть это простой пример вывода статей по 10 штук в каждой категорие. Он универсален, но его можно значительно ускорить потеряв при этом применимость нового алгоритма для некоторых частных случаев. "Развернув" внутренний цикл
мы получим ужасный код, но и более быстрый, избавившись в данном случае аж от 10 условных переходов (циклы это ничто иное как условные переходы) . Получим примерно следующее :
my $ref = $dbh->selectall_arrayref(q[SELECT id FROM categories
WHERE c_status='active']);
my @res;
my $count=10;
foreach my $tmp (@$ref){
my $ref=$dbh->selecall_arrayref(qq[SELECT id,title,text,ts
FROM articles
WHERE category=$tmp
ORDER BY id DESC LIMIT $count],'id');
my @r;
push @r,$ref->[0];
push @r,$ref->[1];
push @r,$ref->[2];
push @r,$ref->[3];
push @r,$ref->[4];
push @r,$ref->[5];
push @r,$ref->[6];
push @r,$ref->[7];
push @r,$ref->[8];
push @r,$ref->[9];
push @res,\@r;
}


Идея 2. Банальное кеширование

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

sub get_cache_connection
{

require Cache::Memcached::Fast;
require Storable;
my $ref=new Cache::Memcached::Fast(
{
servers =>[{ address => '127.0.0.1:11211',weight=>2.5}],
namespace => 'sessions:',
connect_timeout => 0.2,
io_timeout => 0.5,
close_on_error => 1,
compress_threshold =>-1,
ketama_points => 150,
nowait => 1,
hash_namespace => 1,
serialize_methods => [ \&Storable::freeze, \&Storable::thaw ]
}
);

return $ref;

}

my $tabs;
my $md=get_cache_connection();
my $ref=$md->get('categories')) ;
foreach(@$ref){
###some code there

}
Кеширование применимо для данных, которые не часто меняются, при другом подходе может возникнуть проблема, что накладные расходы на работу с кешированием превысят затраты на работу с базой данных. Не забывайте, что mysql тоже кеширует запросы, и в предыдущем примере запрос на выборку категорий по сути не имеет смысла, потому что с огромной вероятностью он будет закеширован mysql. Другое дело, если вы генерируете из категорий свой особый html код, вот его можно и за кешировать.


Идея 3. Развертывание функций.


Думаю вы уже догадались в чем фишка. Рассмотрим предыдущие примеры, только добавим внутрь цикла функцию форматирования даты - ts.
my $ref = $mem_cache->get('categories')) ;
my @res;
my $count=10; foreach my $tmp (@$ref){
my $ref=$dbh->selecall_arrayref(qq[SELECT id,title,text,ts
FROM articles
WHERE category=$tmp
ORDER BY id DESC LIMIT $count],'id');
my @r;
format_date(\$ref->[0]->[3]);
push @r,$ref->[0];
format_date(\$ref->[1]->[3]);
push @r,$ref->[1];
format_date(\$ref->[2]->[3]);
push @r,$ref->[2];
format_date(\$ref->[3]->[3]);
push @r,$ref->[3];
format_date(\$ref->[4]->[3]);
push @r,$ref->[4];
format_date(\$ref->[5]->[3]);
push @r,$ref->[5];
format_date(\$ref->[6]->[3]);
push @r,$ref->[6];
format_date(\$ref->[7]->[3]);
push @r,$ref->[7];
format_date(\$ref->[8]->[3]);
push @r,$ref->[8];
format_date(\$ref->[9]->[3]);
push @r,$ref->[9];

push @res,\@r;
}


Заметка кстати, профайлинг Perl показал, что быстрее передавать параметры в функцию по значению, а не по указателю( то есть не так как здесь ;) ). И заменяем все format_date на их код.

my $ref = $mem_cache->get('categories')) ;
my @res;
my $count=10;
foreach my $tmp (@$ref){
my $ref=$dbh->selecall_arrayref(qq[SELECT id,title,text,ts
FROM articles
WHERE category=$tmp
ORDER BY id DESC LIMIT $count],'id');
my @r;

$ref->[0]->[3]=~/(\d{1,4})-(\d{1,2})-(\d{1,2})/;
$ref->[0]->[3]="$3.$2.$1";
push @r,$ref->[0];
$ref->[1]->[3]=~/(\d{1,4})-(\d{1,2})-(\d{1,2})/;
$ref->[1]->[3]="$3.$2.$1";


push @r,$ref->[1];
$ref->[2]->[3]=~/(\d{1,4})-(\d{1,2})-(\d{1,2})/;
$ref->[2]->[3]="$3.$2.$1";
push @r,$ref->[2];
$ref->[3]->[3]=~/(\d{1,4})-(\d{1,2})-(\d{1,2})/;
$ref->[3]->[3]="$3.$2.$1";
push @r,$ref->[3];
$ref->[4]->[3]=~/(\d{1,4})-(\d{1,2})-(\d{1,2})/;
$ref->[4]->[3]="$3.$2.$1";
push @r,$ref->[4];
$ref->[5]->[3]=~/(\d{1,4})-(\d{1,2})-(\d{1,2})/;
$ref->[5]->[3]="$3.$2.$1";
push @r,$ref->[5];
$ref->[6]->[3]=~/(\d{1,4})-(\d{1,2})-(\d{1,2})/;
$ref->[6]->[3]="$3.$2.$1";
push @r,$ref->[6];
$ref->[7]->[3]=~/(\d{1,4})-(\d{1,2})-(\d{1,2})/;
$ref->[7]->[3]="$3.$2.$1";
push @r,$ref->[7];
$ref->[1]->[8]=~/(\d{1,4})-(\d{1,2})-(\d{1,2})/;
$ref->[1]->[8]="$3.$2.$1";
push @r,$ref->[8];
$ref->[1]->[9]=~/(\d{1,4})-(\d{1,2})-(\d{1,2})/;
$ref->[1]->[9]="$3.$2.$1";
push @r,$ref->[9];
push @res,\@r;
}

В итоге мы види ужасный неудобоворимый код, который вызывает рвотные рефлексы при одном своем виде. Дальше агрументов много
1) А что делать, если полей в таблице дофига, и все надо форматировать, это ж "каша"
2) А если надо увеличить/уменьшить количество статей, снова лезть в код!
И так далее.. И так далее...Все эти вопросы можно решить при помощи "админки". А админка есть у любого уважающего себя сайта статусом выше, персональная страничка.
На нужно при изменение нужных вам параметров сделать генерацию нужного вам кода.
Например добавить изменение количества выводимых статей с 10 на 5( вполне обычная функция для администраторского интерфейса). Помещаем функцию обработки вывода статей в отдельный модуль например "/lib/Article.pm". Даем права на работу с этим файлом пользователю от которого работает наш скрипт
( ну или обычные авось chmod 777 /lib/Artcle.pm).
ну и в функцию изменения количества статей пишем примерно следующее:
open(Fl,">document_root/lib/Article");

print FL, q{
package lib::Artcle;
use strict;
use base qw[Exporter];
use SiteDB;##connecting to the database $dbh
our @EXPORT = qw(
list
);





sub list{
my $ref = $mem_cache->get('categories')) ;
my @res;
my $count=}.$new_count_value.q{;

foreach my $tmp (@$ref){
my $ref=$dbh->selecall_arrayref(qq[SELECT id,title,text,ts
FROM articles
WHERE category=$tmp
ORDER BY id DESC LIMIT $count],'id');
my @r;

$ref->[0]->[3]=~/(\d{1,4})-(\d{1,2})-(\d{1,2})/;
$ref->[0]->[3]="$3.$2.$1";
push @r,$ref->[0];
$ref->[1]->[3]=~/(\d{1,4})-(\d{1,2})-(\d{1,2})/;
$ref->[1]->[3]="$3.$2.$1";


push @r,$ref->[1];
$ref->[2]->[3]=~/(\d{1,4})-(\d{1,2})-(\d{1,2})/;
$ref->[2]->[3]="$3.$2.$1";
push @r,$ref->[2];
$ref->[3]->[3]=~/(\d{1,4})-(\d{1,2})-(\d{1,2})/;
$ref->[3]->[3]="$3.$2.$1";
push @r,$ref->[3];
$ref->[4]->[3]=~/(\d{1,4})-(\d{1,2})-(\d{1,2})/;
$ref->[4]->[3]="$3.$2.$1";
push @r,$ref->[4];
$ref->[5]->[3]=~/(\d{1,4})-(\d{1,2})-(\d{1,2})/;
$ref->[5]->[3]="$3.$2.$1";
push @r,$ref->[5];
$ref->[6]->[3]=~/(\d{1,4})-(\d{1,2})-(\d{1,2})/;
$ref->[6]->[3]="$3.$2.$1";
push @r,$ref->[6];
$ref->[7]->[3]=~/(\d{1,4})-(\d{1,2})-(\d{1,2})/;
$ref->[7]->[3]="$3.$2.$1";
push @r,$ref->[7];
$ref->[1]->[8]=~/(\d{1,4})-(\d{1,2})-(\d{1,2})/;
$ref->[1]->[8]="$3.$2.$1";
push @r,$ref->[8];
$ref->[1]->[9]=~/(\d{1,4})-(\d{1,2})-(\d{1,2})/;
$ref->[1]->[9]="$3.$2.$1";
push @r,$ref->[9];
push @res,\@r;
\}

return \@res;
\}

1;
};
close(FL);
Ну и далее можем использовать этот модуль у себя в скрипте обычным способом :



sub some_sub{
my $self=shift;
require lib::Article;
my $ref=lib::Article::list();
###some code there
####
}


Всем удачи.

p.s
При помощи генерации кода можно избавиться вообще от последнего цикла обхода категорий.