Mais um blog inútil.

Julho 6, 2011

Ementalicious

Arquivado em: coding, serious-business — falco @ 21:22

Quando revi o post do falso sobre as ementas das cantinas da UNL, fiquei aborrecido com o entusiasmo do falso em relação ao BeautifulSoup.

É um facto que o Python é gay. E por isso resolvi mostrar ao falso, como é que se programa com linguagens de homem. Mas entretanto, resolvi que em vez de fazer o mesmo que o falso, iria antes criar um saite, que para além de disponibilizar as ementas em HTML, também iria disponibilizar em RSS e JSON.

O saite vai ser desenvolvido por fases… Nesta fase o saite apenas está a mostrar numa página o mesmo conteúdo que a página das cantinas da UNL.

O site está a ser feito em Perl com Mojo::Lite, que é uma versão aligeirada e simplificada da framework para web MojoLicious

O site são apenas dois ficheiros, como eu não tenho skills de Word Press e não consigo colocar aqui o código todo bonitinho meti tudo numa tarball, que vocês podem obter aqui.

Notas importantes:

  • O código está licenciado com a GNU General Public License version 3.
  • Para correr a aplicação é necessário ter Perl e Mojolicious instalado.
  • Ao contrário do que o falso pensa, usar expressões regulares, não é mau e não devemos ter problemas em utilizar quando úteis.

Querido falsinho se quiseres dar-te ao trabalho de meter aqui o código todo bonitinho, eu dava-te dois beijinhos e um abraço.

Eis o screenshot da página:

Imagem da página com os menus
Imagem da página com os menus das várias faculdades

Julho 4, 2011

BrainFucker

Arquivado em: arvorezinha, coding, osx, useless — falso @ 22:54

Ora viva!!!

Há uns tempos atrás vi nas internets um projecto verdadeiramente inutil, do calibre das coisas que vão aparecendo por aqui, chamado Brainfuck Developer, que é um IDE para programar e debugar Brainfuck.
Senti-me um pouco cabisbaixo ao ver que alguém tinha tentado chegar aos meus calcanhares em nível de inutilidade, portanto decidi por mãos à obra para me redimir. E então à boa maneira dos projectos open sores, decidi ripar a ideia, e comecei a desenvolver o BrainFucker, um IDE de Brainfuck para OSX!
Claro que isto não foi assim feito do pé-pra-mão, até porque não sabia nada de Objective-C nem de Cocoa, mas com o tempo, e pachorra aos fins de semana e tal, finalmente está disponível a versão 0.1.

Suporta correr programas de Brainfuck que só usem OUTPUT (.), o INPUT (,) ainda não está implementado, mas provavelmente vai ser uma DialogBox a pedir o valor.
Possibilidade de correr programas STEP-BY-STEP para ver as alterações dos valores e posição do apontador de memoria.

Espero que isto sirva para alguém aprender Brainfuck, ou mesmo para aprender como não programar em Objective-C.
O codigo está disponivel no github. E um build experimental está disponível: BrainFucker.zip - Apenas testado em OSX 10.4 e 10.5 POWERPC (só para quem ama). Agradeço a alguém que reporte se também funciona em Intels.

Cumprimentos, e um bem haja!

Fevereiro 22, 2011

Adeus AquaPC, olá PCDiga

Arquivado em: serious-business — mirage @ 19:07

Carta aberta à AquaPC

Resumindo a história, encomendei uma placa gráfica em Novembro, que ficou em espera sem darem qualquer acompanhamento, e foi cancelada a 31 de Janeiro por alegada falta de stock. Dias depois, o stock apareceu, 40 euros mais caro do que o valor quando fiz a encomenda. Pedi para reabrirem a encomenda. Não obtive resposta durante uma semana e eis que a placa deixou de estar em stock.

De notar que o stock terminou no dia seguinte a eu vos ter telefonado, como último recurso, e a única resposta que obtive foi “tem de ser o chefe a decidir”. E decidiu muitíssimo bem. Isto soma-se a mails anteriores que vos enviei a pedir informações (não relativas a esta encomenda) que também não foram respondidos.

É incrível como a AquaPC antigamente era uma referência na qualidade do serviço e atendimento, e hoje parece ir no caminho duma Chip7 ou semelhante em que os clientes deixam de ser pessoas e passam a ser números de encomenda.

É com tristeza que vos informo que perderam um cliente fiel desde 2005, que não tinha problemas em pagar um extra (sim, nunca tiveram os preços mais competitivos) para ter garantia de qualidade.

Adeus AquaPC, olá PCDiga.


Tiago Sousa

Dezembro 14, 2010

Árvorezinha 2.0

Arquivado em: arvorezinha, assembly, coding, drama, useless — falso @ 01:07

Ora viva amigos!

Há uns tempos no trabalho um colega meu começou a fazer pouco das minhas árvorezinhas, a dizer que só eram meia árvore, e que eu devia era de fazer uma árvore completa. Eu fiquei SENTIDO com tal AFRONTA, e fiquei a MATUTAR sobre isso, até que decidi por mãos à obra, e criar a Árvorezinha 2.0.

Primeiro decidi faze-la em C porque é a linguagem STANDARD!

[sourcecode language="c"]
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
        int altura;
        int i,x;
        int lul;

        if (argc < 2)
        {
                return(0);
        }
        altura = atoi(argv[1]);

        /* Ciclo da altura da Arvore */
        for(i = 1; i <= altura; i++)
        {

                /*
                        Numero de Espaços
                        Começa em 0 porque existem linhas com 0 espaços
                        Algoritmo: altura - linha
                */
                for(x = 0 ; x < (altura-i); x++)
                {
                        putchar(' ');
                }

                /*
                        Numero de Asteriscos
                        Começa em 1 porque não existem linhas sem *
                        Algoritmo: (2 * linha) - 1
                */
                for (x = 1; x <= (2*i)-1; x++)
                {
                        putchar('*');
                }

                putchar('\n');
        }

        /* Largura ultima linha */
        lul = (altura * 2) - 1;

        /*
                Ciclo da altura do tronco
                Algoritmo: altura / 2
        */
        for(i = 1; i <= (altura/2); i++)
        {
                /*
                        Por causa do ASCII nao permitir meio char
                        tive de fazer duas implementacoes diferentes,
                        uma para quando o  valor da altura do tronco
                        e' par, e outra para quando e' impar.
                */
                if (altura % 2)
                {
                        /* Impar */

                        /*
                                Numero de Espaços
                                Algoritmo: (lul / 4) - 1
                        */
                        for(x = 0; x <= (lul/4)-1; x++)
                        {
                                putchar(' ');
                        }


                        /*
                                Numero de # (tronco)
                                Algoritmo: lul / 2
                        */
                        for(x = 0; x <= (lul/2); x++)
                        {
                                putchar('#');
                        }

                        putchar('\n');
                }
                else
                {
                        /* Par */

                        /*
                                Numero de Espaços
                                Algoritmo: lul / 4
                        */
                        for(x = 0; x <= (lul/4); x++)
                        {
                                putchar(' ');
                        }


                        /*
                                Numero de # (tronco)
                                Algoritmo: (lul / 2) - 1
                        */
                        for(x = 0; x <= (lul/2)-1; x++)
                        {
                                putchar('#');
                        }

                        putchar('\n');
                }
        }

}

[/sourcecode]

A pedido de muitas famílias, foi me imposta a tarefa de fazer um RFC da nova árvorezinha, mas não tenho muito jeito para escrever algoritmos em pseudo-código. Então tal obra heróica fica para o caro leitor, façam me um baseado no código em C e enviem-me!

Segundo as próprias leis já pré-estabelecidas da Árvorezinha, tem de existir uma implementação em Assembly! Então não podia cá faltar a minha versão em x86 Assembly.

[sourcecode language="plain"]

;
; Arvorezinha 2.0
; x86 Assembly
; Copyright (C) 2010 Pedro de Oliveira
; //blol.org
;
; this assembly can never fail
;
        BITS            32
        GLOBAL          main

; Vou usar duas funcoes da libc para o codigo nao crescer gigantescamente
; com rotinas que nao interessam nada para aqui.
        EXTERN          atoi
        EXTERN          printf

; Definicao das Variaveis
SECTION         .data

        argc    dd      0
        argv    dd      0

        erro    db      "ERRO! Executar: %s <altura da arvore>",10,0

        card    db      '#'
        newl    db      0xa
        aste    db      '*'
        espa    db      ' '

        altura  dd      0
        i       dd      1
        x       dd      0
        lul     dd      0

; He cometh!
SECTION         .text

main:
        pop     eax                     ; Ignorar...

        pop     eax                     ; Saca o argc da Stack
        mov     dword [argc], eax       ; Guarda o valor na variavel argc

        pop     ebx                     ; Saca a posicao de memoria do
                                        ; argv[0] da Stack
        mov     eax, dword [ebx]        ; Mete a posicao em EAX
        mov     [argv], eax             ; Guarda-a em argv

        add     ebx,0x4                 ; Salta 4 bytes para a frente
                                        ; para o argv[1] ficar em EBX

        mov     eax, [argc]             ; Mete o argc em EAX
        cmp     eax, 0x2                ; Verifica se e' diferente de 2
        jne     jafoste                 ; Se for sai com erro

        push    dword [ebx]             ; Mete o valor de argv[1] na Stack
        call    atoi                    ; Corre o atoi com esse valor
        mov     [altura], eax           ; O resultado fica em EAX, guarda
                                        ; na variavel altura

ciclo_linhas:
        ; INICIO - CICLO DAS LINHAS DA ARVORE
        mov     eax, [i]                ; i em EAX
        mov     ebx, [altura]           ; altura em EBX

        cmp     ebx, eax                ; Compara
        jb      prepara_tronco          ; i > altura ? proximo passo
        mov     dword [x], 0            ; Mete x a 0

ciclo_espacos:
        ; INICIO - CICLO DE ESPAÇOS ANTES DOS ASTERISCOS
        mov     eax, [x]                ; x em EAX

        ; pretende-se (altura - i) em EBX
        mov     ebx, [altura]           ; altura em EBX
        mov     ecx, [i]                ; i em ECX
        sub     ebx, ecx                ; EBX - ECX

        cmp     ebx, eax                ; Compara
        jbe     prepara_asteriscos      ; x >= (altura - i) ? proximo passo

        push    espa                    ; Espaço
        call    print                   ; write()

        call    incrementa_x
        jmp     ciclo_espacos           ; Volta para o inicio do ciclo
        ; FIM - CICLO DE ESPAÇOS ANTES DOS ASTERISCOS

prepara_asteriscos:
        mov     dword [x], 1            ; Mete x a 1

ciclo_asteriscos:
        ; INICIO - CICLO DE ASTERISCOS (ARVORE)
        mov     ebx, [x]                ; x em EBX

        ; pretende-se (2 * i) - 1 em EAX
        mov     eax, 2                  ; 2 em EAX
        mov     ecx, [i]                ; i em ECX
        mul     ecx                     ; Multiplica EAX por ECX
        dec     eax                     ; Subtrai 1 a EAX

        cmp     eax, ebx                ; Compara
        jb      fim_ciclo_linhas        ; x > (2*i)-1 ? proximo passo

        push    aste                    ; Asterisco
        call    print                   ; write()

        call    incrementa_x
        jmp     ciclo_asteriscos        ; Volta para o inicio do ciclo
        ; FIM - CICLO DE ASTERISCOS (ARVORE)

fim_ciclo_linhas:
        push    newl                    ; Newline
        call    print                   ; write()

        call    incrementa_i
        jmp     ciclo_linhas            ; Volta para o inicio
        ; FIM - CICLO DAS LINHAS DA ARVORE

prepara_tronco:
        ; pretende-se (altura * 2) - 1 em EAX
        mov     eax, [altura]           ; altura em EAX
        mov     ecx, 2                  ; 2 em ECX
        mul     ecx                     ; Multiplica EAX por ECX
        dec     eax                     ; Subtrai 1 a EAX
        mov     dword [lul], eax        ; Guarda a largura da ultima linha
                                        ; em lul


        mov     dword [i], 1            ; Mete o i a 1

ciclo_linhas_tronco:
        ; BEGIN - CICLO DAS LINHAS DO TRONCO
        mov     ecx, [i]                ; i em ECX

        ; pretende-se (altura / 2)
        mov     eax, [altura]           ; altura em EAX
        shr     eax, 1                  ; divide por 2

        cmp     ecx, eax                ; Compara ECX com EAX
        jg      sair                    ; i > (altura / 2) ? Adeus!

        mov     eax, [altura]           ; altura em EAX
        test    eax, 1
        je      pc_tronco_par_espacos   ; e' par?

; --------------------------- IMPAR -------------------------------
pc_tronco_impar_espacos:
        mov     dword [x], 0            ; Mete-se x a 0

c_tronco_impar_espacos:
        ; INICIO - CICLO DOS ESPAÇOS ANTES DO TRONCO (IMPAR)
        mov     ecx, [x]                ; x em EAX

        ; pretende-se (lul / 4) - 1 em EAX
        mov     eax, [lul]              ; lul em EAX
        shr     eax, 2                  ; Divide por 4
        dec     eax                     ; Subtrai 1

        cmp     eax, ecx                ; Compara
        jb      pc_tronco_impar_cardinal; x > (lul/4)-1 ? Next!

        push    espa                    ; Espaço
        call    print                   ; write()

        call    incrementa_x
        jmp     c_tronco_impar_espacos  ; Volta para o inicio
        ; FIM - CICLO DOS ESPAÇOS ANTES DO TRONCO (IMPAR)

pc_tronco_impar_cardinal:
        mov     dword [x], 0            ; Mete x a 0

c_tronco_impar_cardinal:
        ; INICIO - CICLO DOS CARDINAIS DO TRONCO (IMPAR)
        mov     ecx, [x]                ; x em ECX

        ; pretende-se (lul / 2) em EAX
        mov     eax, [lul]              ; lul em EAX
        shr     eax, 1                  ; Divide por 2

        cmp     eax, ecx                ; Compara
        jb      fim_ciclo_linhas_tronco ; x > (lul/2) ? Next!

        push    card                    ; Cardinal
        call    print                   ; write()

        call    incrementa_x

        jmp     c_tronco_impar_cardinal ; Volta para o inico
        ; FIM - CICLO DOS CARDINAIS DO TRONCO (IMPAR)

; --------------------- FIM IMPAR --------------------------------


; ----------------------------- PAR ------------------------------
pc_tronco_par_espacos:
        mov     dword [x], 0            ; Mete x a 0

c_tronco_par_espacos:
        ; INICIO - CICLO DOS ESPAÇOS ANTES DO TRONCO (PAR)
        mov     ecx, [x]                ; x em ECX

        ; pretende-se (lul / 4) em EAX
        mov     eax, [lul]              ; lul em EAX
        shr     eax, 2                  ; divide por 4

        cmp     eax, ecx                ; Compara
        jb      pc_tronco_par_cardinal  ; x > (lul / 4) ? Next!

        push    espa                    ; Espaço
        call    print                   ; write()

        call    incrementa_x
        jmp     c_tronco_par_espacos    ; Volto para o inico do ciclo
        ; FIM - CICLO DOS ESPAÇOS ANTES DO TRONCO (PAR)

pc_tronco_par_cardinal:
        mov     dword [x], 0            ; Mete x a 0

c_tronco_par_cardinal:
        ; INICIO - CICLO DOS CARDINAIS DO TRONCO (PAR)
        mov     ecx, [x]                ; x em ECX

        ; pretende-se (lul / 2) - 1 em EAX
        mov     eax, [lul]              ; lul em EAX
        shr     eax, 1                  ; Divide por 2
        dec     eax                     ; Subtrai 1

        cmp     eax, ecx                ; Compara
        jb      fim_ciclo_linhas_tronco ; x > (lul / 2) - 1 ? uhuhuh

        push    card                    ; Cardinal
        call    print                   ; write()

        call    incrementa_x

        jmp     c_tronco_par_cardinal   ; Volta para o inicio do ciclo
        ; FIM - CICLO DOS CARDINAIS DO TRONCO (PAR)
; ----------------------- FIM PAR ----------------------------------

fim_ciclo_linhas_tronco:
        push    newl
        call    print

        call    incrementa_i
        jmp     ciclo_linhas_tronco     ; Volta para o inico do ciclo
        ; FIM - CICLO DAS LINHAS DO TRONCO

jafoste:
        mov     eax, [argv]             ; Mete o apontador de argv em EAX
        push    dword eax               ; Mete o endereço de argv na Stack
        push    dword erro              ; Mete o endereço da String na Stack
        call    printf                  ; Escreve no ecra!


sair:
        mov     ebx,0x0                 ; valor de saida
        mov     eax,0x1                 ; sys_exit
        int     0x80

print:
        mov     ecx,[esp+4]             ; Mete o argumento em ECX
        mov     edx,1                   ; Length
        mov     ebx,1                   ; stdout
        mov     eax,4                   ; sys_write
        int     0x80
        ret

incrementa_x:
        mov     eax, [x]
        inc     eax
        mov     dword [x], eax
        ret

incrementa_i:
        mov     eax, [i]
        inc     eax
        mov     dword [i], eax
        ret
[/sourcecode]

E aqui vai a prova dos nove:

[sourcecode language="plain"]
falso@lemonparty:~/src/zbr$ make
rm -f arvore2 arvore.o
nasm -f elf arvore.asm -o arvore.o
gcc -g -o arvore2 arvore.o
falso@lemonparty:~/src/zbr$ ./arvore2 4
   *
  ***
 *****
*******
  ###
  ###
falso@lemonparty:~/src/zbr$ ./arvore2 5
    *
   ***
  *****
 *******
*********
  #####
  #####
falso@lemonparty:~/src/zbr$
[/sourcecode]

Espero lançar futuramente um género de Unit Tests, para testar as varias implementações da Arvorezinha 2.0 que possam surgir, para ver se cumprem o standard ou não.

Espero que tenham gostado do post, até à proxima, fiquem bem e joguem muito! Chuuuuuuack!

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.

Novembro 4, 2010

Arvorezinha --- C++ Templates 2

Arquivado em: arvorezinha, coding, useless — dcoder @ 03:00

Viva. Há demasiado tempo que não são adicionadas novas entradas à nossa já lendária colecção de arvorezinhas em várias linguagens e dialectos de todo o mundo.

Assim sendo, hoje trago-vos uma arvorezinha feita com templates de C++. Sim, eu sei. Já temos uma. Mas isto não me impede de utilizar outras capacidades de C++ para cumprir o mesmo objectivo. Ora vejam lá:

#include <iostream>

using namespace std;

template<int i>
struct SemiArvorezinha : public SemiArvorezinha<i-1>
{
	SemiArvorezinha(){cout << "*";}
};

template<> struct SemiArvorezinha<0> {};

template<int i>
struct Arvorezinha : public Arvorezinha<i-1>, SemiArvorezinha<i>
{
	Arvorezinha(){ cout << endl; }
};

template<> struct Arvorezinha<0>{};

int main(int argc, char **argv)
{
	Arvorezinha<5> A;
	return 0;
}

Em vez de funções com templates, temos nesta encarnação classes e multiple inheritance. Bem haja a todos.

Outubro 28, 2010

Scam nos leilões do ClubeFashion

Arquivado em: drama, fail, serious-business, useless — falso @ 09:32

Ora viva amigos!

Hoje não venho aqui blogar de nada relativo a Informáticas, mas sim a um scam lindo que achei nas Internets portuguesas.

Então estava eu ontem muito bem no meu covil, a fazer a lida das coisas inúteis do dia-a-dia, quando a minha FC se vira para mim e diz-me que o site ClubeFashion (que já é conhecido por dar altas baldas de 1 e 2 meses para entregar as coisas que se compra la) agora tem leilões, e que haviam la pessoas a ganhar coisas mirabolantes por preços bues baratos.

Eu achei que isso cheirava a esturro, porque em Portugal, ninguém da nada a ninguém. Então decidi investigar melhor a coisa.

Então funciona desta maneira, para se licitar em algo, tem de se fazer um carregamento de “Bids” do site. 10 Bids = 5€, 20 Bids = 10€, etc.
Então basicamente sempre que se faz uma licitação, mesmo que não se ganhe, ou se alguém der um valor superior eles ganham logo 0.50€. Até aqui está MAIS ou MENOS bem, até que se entra na pagina de um leilão a decorrer actualmente…

Agora aqui é que parte a loiça toda. Pelos vistos (já tinha visto ontem à noite) os leilões arrancam sempre com o valor inicial de 1€. E depois temos a seguinte informação:

\* A sua licitação subirá o valor em 0.01€.
\* Abaixo de 2 MINUTOS, qualquer licitação reinicia o contador.

Então isto funciona mais ou menos assim, eles têm uma coisa para leiloar, mas com o dinheiro que vão ganhar com as licitações, vai chegar para pagar o que quer que estejam a leiloar, e ainda um lucro de mais de 100%. E claro que se o leilão estiver a acabar, sem terem sido feitas licitações suficientes, eles têm um script que faz automaticamente licitações com fake accounts, para o tempo nunca terminar até fazerem o dinheiro suficiente.

Vamos ver então um exemplo, a “Viagem Lufthansa para a Europa”, dizem que o PVP Loja é 358€ e quem ganhou o leilão, ganhou por 79.90€.
Então o leilão começa a 1€. 79.90€-1€ da 78.90, que dá 7890 licitações, então vamos ver, 7890 * 0.50€ = 3945€, então eles com este leilão da viagem que custava 358€ ganharam 3587€, está um belo negocio hein?

Bem, eu achei isto tanta roubalheira, que necessitei de vir blogar sobre isto, espero que gostem! E leiam tudo bem antes de serem enganados por estes sites malandros. Até à proxima, fiquem bem e joguem muito.

Outubro 17, 2010

FCT

Arquivado em: useless — amg @ 16:22

No outro dia ia pela escolinha e vi o fALSO. Fui falar com ele e ele pensava que eu era todo trve. Só que eu não sou