Codebits
that rock!

Jun 19, 2013

My next JAPH

posted by varnie • Tags: perlShow comments

Написал еще один незамысловатый JAPH. Сначала покажу итоговую версию:

use strict;
 use warnings;
  my$k='my@a=((-4
   ,26,10,-4,-104,-
    56,-61,-79,-94,-
     127,-152,-162,-
      268,-245,-250,-
       264,-298,-403,-
        361,-399,-429,-
         454,-494,-516),
          @_);join"",map{
           chr$a[$_]+$a[$_+
            $#a/2+1]}0..$#a/2
             ';foreach(reverse(
               12..35)){$k="sub
                {$k}->(\@_,int 
                 map{(int)x\$_}(
                  1..$_))"}print
                   eval $k;

Можно было бы даже сократить немного код, убрав прагмы strict и warnings, но я сторонник чистоты кода и отсутствия ошибок. Теперь то же самое, только в ужатом виде:

#!/usr/bin/perl

use strict;
use warnings;

my$k='my @a = ((-4, 26, 10, -4, -104, -56, -61, -79, -94, -127, -152, -162, -268, -245, -250, -264, -298, -403, -361, -399, -429, -454, -494, -516), @_);
join "", map{ chr $a[$_] + $a[$_+$#a/2+1] } 0..$#a/2';

foreach (reverse (12..35)) {
    $k = "sub{$k}->(\@_,int map{(int)x\$_}(1..$_))"
}

print eval $k;

Как работает код? Код генерит длиннющую строку с кодом, которой потом делается eval и print собственно результата. Весь финт в генерации этой строки-кода. О ней и поговорим ниже. Т.е. по сути в результате у нас будет такая вот красота:

use strict;
use warnings;

print sub{
    sub{
        sub{
            sub{
                sub{               
                    sub{                       
                        sub{                          
                            sub{
                                sub{
                                    sub{
                                        sub{
                                            sub{
                                                sub{
                                                    sub{
                                                        sub{
                                                            sub{
                                                                sub{
                                                                    sub{
                                                                        sub{    
                                                                            sub{ 
                                                                                 sub{ 
                                                                                    sub{ 
                                                                                        sub{ 
                                                                                           sub{ 

    my (@a) = ((-4, 26, 10, -4, -104, -56, -61, -79, -94, -127, -152, -162, -268, -245, -250, -264, -298, -403, -361, -399, -429, -454, -494, -516), @_);
    print join "", map{ chr $a[$_] + $a[$_+$#a/2+1] } 0..$#a/2
                                                                                            }->(@_, int map{(int) x$_} (1..35)) 
                                                                                        }->(@_, int map{(int) x$_} (1..34)) 
                                                                                    }->(@_, int map{(int) x$_} (1..33)) 
                                                                                }->(@_, int map{(int) x$_} (1..32)) 
                                                                            }->(@_, int map{(int) x$_} (1..31)) 
                                                                        }->(@_, int map{(int) x$_} (1..30)) 
                                                                    }->(@_, int map{(int) x$_} (1..29)) 
                                                                }->(@_, int map{(int) x$_} (1..28)) 
                                                            }->(@_, int map{(int) x$_} (1..27)) 
                                                        }->(@_, int map{(int) x$_} (1..26)) 
                                                    }->(@_, int map{(int) x$_} (1..25)) 
                                                }->(@_, int map{(int) x$_} (1..24)) 
                                            }->(@_, int map{(int) x$_} (1..23)) 
                                        }->(@_, int map{(int) x$_} (1..22)) 
                                    }->(@_, int map{(int) x$_} (1..21)) 
                                }->(@_, int map{(int) x$_} (1..20)) 
                            }->(@_, int map{(int) x$_} (1..19)) 
                        }->(@_, int map{(int) x$_} (1..18)) 
                    }->(@_, int map{(int) x$_} (1..17)) 
                }->(@_, int map{(int) x$_} (1..16)) 
            }->(@_, int map{(int) x$_} (1..15))
        }->(@_, int map{(int) x$_} (1..14))
    }->(@_, int map{(int) x$_} (1..13))
}->(int map{(int) x $_} (1..12))

Дальше уже проще, т.ч разбор полётов оставлю читателю.

Jun 15, 2013

WWW::Mechanize and keeping tracks of the performed requests

posted by varnie • Tags: perlShow comments

Столкнулся с проблемой при использовании WWW:Mechanize - после многократной отправки POST запросов с большими данными Perl падал с <p class="terminal">Out of memory</p>. Вот этот очень простой пример:

#!/usr/bin/perl

use strict;
use warnings;
use WWW::Mechanize;
use 5.010;

$| = 1;

my $mech = WWW::Mechanize->new(autocheck => 1);

foreach (1..1000) {
    $mech->post('http://SOME_URL_HERE', [some_action => 'SOME_ACTION_HERE',  some_data => join ('', map { int rand 2} (0..63)) x (16*1024*50)]);
    say $mech->response->decoded_content;
}

То бишь, 1000 раз шлем POST запрос со строчкой-мусором длиной в 50 мегабайт. Жирная строчка, да, но не в этом вся соль. К примеру, на моей машине программка падала ближе к 50-ой итерации.

Нелогично и непонятно - по-хорошему память должна подчищаться после каждой итерации.

Первая мысль - на каждой итерации создавать новый инстанс WWW::Mechanize, но зачем городить огород? Давайте разберемся. На помощь придет хорошо всем знакомый Data::Dumper. Итак, дебажный код:

#!/usr/bin/perl

use strict;
use warnings;
use WWW::Mechanize;
use 5.010;
use Data::Dumper;

$| = 1;

my $mech = WWW::Mechanize->new(autocheck => 1);

foreach (1..1000) {
    $mech->post('http://SOME_URL_HERE', [some_action => 'SOME_ACTION_HERE',  some_data => join ('', map { int rand 2} (0..63)) x (16*1024*50)]);
    say Dumper($mech);
    say $mech->response->decoded_content;
}

Запускаем в консоле и наблюдаем: чем дальше в лес - тем толще партизаны, т.е. чем больше прогнано итераций в цикле, тем длиннее вывод генерит дампер:). Узкое место - поле “page_stack” (массив хранящий инфу о предыдущих прогнанных запросах)!!! Оно растёт с каждой новой итерацией.

Для нашего случая хранить эти данные абсолютно не нужно, поэтому идём на сайт WWW::Mechanize и читаем:

stack_depth => $value Sets the depth of the page stack that keeps track of all the downloaded pages. Default is effectively infinite stack size. If the stack is eating up your memory, then set this to a smaller number, say 5 or 10. Setting this to zero means Mech will keep no history.

Итоговый, рабочий вариант, который не жрёт память аки конь:

#!/usr/bin/perl

use strict;
use warnings;
use WWW::Mechanize;
use 5.010;

$| = 1;

my $mech = WWW::Mechanize->new(autocheck => 1);
$mech->stack_depth(0); #do not keep track of the performed requests!

foreach (1..1000) {
    $mech->post('http://SOME_URL_HERE', [some_action => 'SOME_ACTION_HERE',  some_data => join ('', map { int rand 2} (0..63)) x (16*1024*50)]);
    say $mech->response->decoded_content;
}

Мораль - читать доки об используемых либах.

Feb 17, 2013

A Befunge interpreter written in Perl

posted by varnie • Tags: • Show comments

Написал простейший интерпретатор эзотерического языка программирования Befunge. Код доступен на github: https://github.com/varnie/befunge.pl, поддерживающий спецификацию “Befunge-93” (т.е без всяких расширений синтаксиса, обрабатываются первые 80x25 символов исходного кода программок, итд).

Запускается следующим образом: <pre class="terminal"> chmod +x befunge.pl befunge.pl ./my_befunge_program.bf </pre>

Внимание, емкость стека никак не ограничена, а потому, упирается лишь в динамическую память, доступную для перла. Действует Перловый принцип - “нет никаких лимитов” (если перефразировать;)

Feb 07, 2013

jCarousel: No width/height set for items. This will cause an infinite loop. Aborting...: fix

posted by varnie • Tags: jsShow comments

При использовании jQuery плагина jCarousel в IE8 (будь он проклят трижды) словил баг:

“Сообщение: jCarousel: No width/height set for items. This will cause an infinite loop. Aborting…”.

Несмотря на то, что закастомайзенный класс ul/li карусельки имел явно прописанные CSS-аттрибуты width и height, IE8 упорно делал вид что не видит их, отсюда и баг.

Кто натолкнулся на этот баг, вот готовое решение: наряду со своими кастом-стилями прописать дефолтный “.jcarousel-list li { height: 39px; width: 44px; }”, где значения, разумеется, должны быть вашими.

Надеюсь, кому-нибудь эта заметка пригодится.

Jan 18, 2013

Befunge: first steps

posted by varnie • Tags: • Show comments

Буду краток. Поковырялся с ужасным эзотерическим языком Befunge, в итоге разродился простой программкой, выводящей числа от 1 до 10 (да-да, это не так просто сделать, как кажется!). Фантастика, но это работает.

Программка:

1: v     : <

   5
   2
   *
   `
@  _ :.:1+ ^

Вывод: <p class="terminal"> 1 2 3 4 5 6 7 8 9 10 </p>

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

&11p  1: v   :   <
         1
         1
         g
         
         `       
      @  _ :.:1+ ^

Вывод: <p class="terminal"> Befunge-93 Interpreter/Debugger v2.23 20 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 </p>

Т.е запросили выводить до 20; вывод корректный.

Теперь затрону такую офигенную фишку Befunge как возможность самомодификации, которая встроена в сам язык(!). Это реализуется командами p и g. Первая пушит в код программы по указанным на стеке координатам x и y ASCII значение (пример использования: “101p” - пишет ASCII символ, соответствующий единице по координатам x=0, y=1.). Вторая инструкция получает значение по координатам и пушит его на вершину стека.

А вот простенький пример самомодификации на Befunge:

52*5*80p1.@

Несмотря на то что в коде явно прописано вывести на экран 1, выведется 50. Разберем подробнее:

Сначала на стек ложится 5 и 2. Берутся эти числа, перемножаются, и результат ложится на вершину стека. Имеем 10.

На вершину стека ложится 5. Далее опять перемножение (уже 10 и 5), что дает 50; результат опять ложится на вершину стека. Имеем 50.

Далее на стек ложатся последовательно 8 и затем 0. Имеем 50, 8, 0.

Далее команда p пишет ASCII значение 50 (т.е двойку) на место инструкции с координатами (0,8) затирая собой находящуюся там единичку:)

Далее значение лежащее на стеке выводится на экран и программа завершает свою работу. В итоге выводится 2, а не 1!

Начало положено, далее что-нибудь еще напишу в свободное время.

Fork me on GitHub