segunda-feira, 8 de fevereiro de 2010

Cálculo de fatorial através de redirecionamentos de páginas

Abaixo está uma aplicação absurdamente inútil e sem sentido usando awful: cálculo de fatorial através de redirecionamentos de páginas.

Para calcular o fatorial de 5, por exemplo, basta executar o servidor com a aplicação:

$ awful awful-fatorial.scm

e acessar http://localhost:8080/?n=5 (a entrada de dados é feita através da variável n).

O código está a seguir:

(use awful html-tags html-utils)

(root-path ".")

(define-page (main-page-path)
(lambda ()
(let* ((n ($ 'n 0 string->number))
(current ($ 'current n string->number))
(accum ($ 'accum 1 string->number))
(finished? (< current 2)))
(html-page
(if finished?
(<h1> n "! = " accum)
"")
headers: (if finished?
""
(<meta> http-equiv: "refresh"
content: (conc "0;url=?n=" n
"&accum=" (* current accum)
"&current=" (sub1 current)))))))
no-template: #t)

sábado, 6 de fevereiro de 2010

Suporte a múltiplos bancos de dados para Awful

A partir da versão 0.10, awful passa a oferecer suporte a múltiplos bancos de dados. Atualmente há suporte para PostgreSQL (através da extensão postgresql) e SQLite3 (através da extensão sqlite3 ou sql-de-lite).

Há uma extensão para cada tipo de base de dados: awful-postgresql, awful-sqlite3 e awful-sql-de-lite. No caso de SQLite3, pode-se optar por usar tanto a extensão sqlite3 ou sql-de-lite (duas extensões diferentes para acesso a bases SQLite3).

A forma de acesso a bases de dados continua praticamente a mesma: através do procedimento $db, o qual faz uso das facilidades oferecidas por awful (conexão transparente, fechamento automático). A única diferença é que agora é necessário carregar a extensão relativa ao tipo de base de dados que pretende-se acessar (e.g., (use awful awful-postgresql)) e usar enable-db como um procedimento sem argumentos, não um parâmetro com argumento booleano, como antes.

Abaixo está um exemplo completo de uma aplicação que gera uma página HTML com uma tabela contendo dados de nome e endereço da tabela users de uma base de dados PostgreSQL:

(use awful awful-sql-de-lite html-utils)

(enable-db)

(db-credentials "db.db")

(define-page (main-page-path)
(lambda ()
(tabularize ($db "select name, address from users"))))


Para publicar esta página, basta executar (supondo que o código acima está no arquivo users.scm):

$ awful users.scm


(ficará disponível em http://localhost:8080).

Se um dia for necessário migrar essa base de dados para PostgreSQL, basta usar (use awful-postgresl) em vez de (use awful-sql-de-lite) e ajustar a configuração de credenciais para acesso ao banco (no caso de SQLite3, a credencial é o caminho para o arquivo com a base de dados). Se a estrutura da base de dados não for modificada, e se forem usadas consultas SQL portáveis, o código Scheme não precisará ser alterado.

Opcionalmente, a página pode ser compilada:

$ csc -s users.scm
$ awful users.so



Simples assim. :-)

terça-feira, 26 de janeiro de 2010

Woof em Chicken

Há uns dias li sobre o woof, um programa para compartilhar arquivos via HTTP. A descrição do site é mais detalhada:


I guess everybody with a laptop has experienced this problem at some
point: You plug into a network and just want to exchange files with
other participants. It always is a pain until you can exchange
files with the person vis-a-vis.

Of course there are a lot of tools to tackle this problem. For large
scale communities there are dozens of filesharing networks. However,
they don't work for small local networks. Of course you could put your
stuff to exchange on a local web server, but who really wants to
maintain this? Tools like the ingenious
npush/npoll are
extremely helpful, provided that both parties have it installed,

SAFT/sendfile
also aims to solve this problem, but needs a permanently running daemon...

Woof (Web Offer One File) tries a different approach. It
assumes that everybody has a web-browser or a commandline web-client
installed. Woof is a small simple stupid webserver that can
easily be invoked on a single file. Your partner can access the file
with tools he trusts (e.g. wget). No need to enter
passwords on keyboards where you don't know about keyboard sniffers, no
need to start a huge lot of infrastructure, just do a

$ woof filename

and tell the recipient the URL woof spits out. When he got that
file, woof will quit and everything is done.


Abaixo está uma implementação em setenta e poucas linhas de código em Chicken Scheme, usando o servidor web Spiffy.

#! /usr/bin/csi -s
(use posix srfi-13 spiffy)

(define (woof file count ip-addr port)
(when port (server-port port))
(root-path (or (pathname-directory file) (current-directory)))
(let ((current-count 0)
(ip-addresses (and ip-addr (string-split ip-addr ",")))
(file (pathname-strip-directory file)))
(handle-file
(lambda (path)
(if (equal? (pathname-strip-directory path) file)
(if (or (not ip-addr) (member (remote-address) ip-addresses))
(let* ((ext (pathname-extension path))
(handler (alist-ref ext (file-extension-handlers)
string-ci=? send-static-file)))
(set! current-count (add1 current-count))
(print "Serving file " file
" to " (remote-address)
" (count=" current-count ").")
(handler path)
(when (>= current-count count)
(exit 0)))
(begin

(print "Denying access to host " (remote-address) ".")
(send-status 403 "Forbidden")))
(begin
(print "Denying access to file " path ".")
(send-status 403 "Forbidden")))))
(print "Sharing '" file "' with "

(if ip-addresses
(string-intersperse ip-addresses ", ")
"anybody")
".")
(print "URL: http://" (get-host-name) ":" port "/" file)
(start-server)))

(define (usage #!optional exit-code)
(display
(string-append
(pathname-strip-directory (program-name))
" [ --port=<port> ] [ --ip-addr=<ip address> ] [ --count=<count> ] file\n")
(if exit-code (current-error-port) (current-output-port)))
(when exit-code (exit exit-code)))

(define (cl-option-value option args #!optional (converter identity))
(let loop ((args args))
(and (not (null? args))
(let ((arg (car args)))
(if (string-prefix? option arg)
(cond ((string-match (string-append option "=(.*)") arg)
=> (lambda (m)
(converter (cadr m))))
(else (loop (cdr args))))
(loop (cdr args)))))))

(let ((args (command-line-arguments)))
(when (null? args)
(usage 1))
(when (or (member "-h" args) (member "--help" args))
(usage 0))
(let ((count (cl-option-value "--count" args string->number))
(ip-addr (cl-option-value "--ip-addr" args))
(port (cl-option-value "--port" args string->number))
(file (car (reverse args))))
(if (file-exists? file)
(woof file (or count 1) ip-addr port)
(begin

(display (string-append file " does not exist.\n")
(current-error-port))
(exit 1)))))


Nem todas as funcionalidades do woof original estão presentes, mas é possível especificar:

  • o arquivo a ser compartilhado

  • a porta a ser usada pelo servidor

  • o número IP da máquina que poderá pegar o arquivo (pode-se liberar o acesso para mais de uma máquina separando os números IP por vírgula)

  • o número de vezes que o arquivo pode ser acessado



Abaixo está a sintaxe para utilização do woof em Chicken na linha de comando:
$ woof --help                                  
woof [ --port=<port> ] [ --ip-addr=<ip address> ] [ --count=<count> ] file

sábado, 23 de janeiro de 2010

jsmin para Chicken Scheme

Há pouco fiz o commit no repositório de extensões do sistema Chicken de uma tradução para Scheme do código C do jsmin, de Douglas Crockford.

A extensão fornece apenas dois procedimentos: jsmin-string e jsmin-file, as quais compactam o código javascript considerando como entrada, respectivamente, uma string e um arquivo.

O código Scheme traduzido de código C (sem uso da FFI) não é dos mais bonitos :-), pois a tradução foi feita praticamente linha-a-linha (inclusive mantendo os returns, implementados através de call/cc).

Programação para a Web com Awful

Há uns dias comecei a desenvolver mais uma tentativa de tornar a programação para a Web mais "fácil". O resultado é uma extensão para o sistema Chicken (versão 4) que fornece as seguintes funcionalidades:

  • Interfaces simples para o uso de bases de dados Postgresql

  • Suporte a Ajax através da biblioteca JQuery

  • Acesso fácil às variáveis de requisições HTTP (tanto da query string (método GET) quando do corpo da requisição (e.g., método POST)

  • Flexibilidade: há vários parâmetros de configuração

  • A compilação de páginas para código nativo para a plataforma alvo é fácil

  • Disponibilidade de um visualizador de sessão

  • Disponibilidade de um REPL que pode ser acessado através do navegador (via HTTP) para a depuração de aplicações para a web



Tentei fazer uma documentação razoável, que cobrisse boa parte da implementação. Ela está em http://chicken.wiki.br/eggref/4/awful. Na documentação podem ser vistos exemplos de aplicações simples que demonstram algumas das funcionalidades.

Sobre o nome: é só um nome. :-) Em http://chicken.wiki.br/eggref/4/awful#the-name há algumas possíveis interpretações caso AWFUL fosse uma sigla.

quinta-feira, 10 de dezembro de 2009

Introspecção de módulos em Chicken Scheme

Abaixo está um pequeno procedimento para inspecionar símbolos de módulos importados no sistema Chicken (para a versão 4). É semelhante à função dir de Python.

(define (introspect #!optional symbol)
(if symbol
(let ((module-data (alist-ref symbol ##sys#module-table)))
(if module-data
(let-values (((_ module-symbols _) (##sys#module-exports module-data)))
(map car module-symbols))
(let loop ((syms (##sys#current-environment)))
(if (null? syms)
'()
(let* ((sym/sym+prefix (car syms))
(sym+prefix (symbol->string (cdr sym/sym+prefix)))
(tokens (string-split sym+prefix "#" #t))
(prefix (car tokens)))
(if (equal? (->string symbol) prefix)
(cons (string->symbol (string-intersperse (cdr tokens) ""))
(loop (cdr syms)))
(loop (cdr syms))))))))
(map car (##sys#current-environment))))



Exemplos de uso

$ csi -n

CHICKEN
(c)2008-2009 The Chicken Team
(c)2000-2007 Felix L. Winkelmann
Version 4.2.0 - SVN rev. 16023
linux-unix-gnu-x86 [ manyargs dload ptables applyhook ]
compiled 2009-10-20 on dellito (Linux)

#;1> ,l introspection.scm
; loading introspection.scm ...
#;1> (introspect)
()
#;2> (import html-utils)
; loading /usr/local/chicken-4.2.0/lib/chicken/4/html-utils.import.so ...
; loading /usr/local/chicken-4.2.0/lib/chicken/4/chicken.import.so ...
; loading /usr/local/chicken-4.2.0/lib/chicken/4/scheme.import.so ...
; loading /usr/local/chicken-4.2.0/lib/chicken/4/files.import.so ...
; loading /usr/local/chicken-4.2.0/lib/chicken/4/data-structures.import.so ...
; loading /usr/local/chicken-4.2.0/lib/chicken/4/srfi-13.import.so ...
; loading /usr/local/chicken-4.2.0/lib/chicken/4/posix.import.so ...
; loading /usr/local/chicken-4.2.0/lib/chicken/4/utils.import.so ...
; loading /usr/local/chicken-4.2.0/lib/chicken/4/html-tags.import.so ...
; loading /usr/local/chicken-4.2.0/lib/chicken/4/srfi-1.import.so ...
#;3> (introspect 'html-utils)
(tabularize itemize enumerate html-page combo-box hidden-input)
#;4> (introspect 'srfi-1)
(alist-cons alist-copy alist-delete alist-delete! any append! append-map append-map!
append-reverse append-reverse! assoc break break! car+cdr circular-list circular-list?
concatenate concatenate! cons* count delete delete! delete-duplicates delete-duplicates!
dotted-list? drop drop-right drop-right! drop-while eighth every fifth filter filter! filter-map
find find-tail first fold fold-right fourth iota last last-pair length+ list-copy list-index
list-tabulate list= lset-adjoin lset-diff+intersection lset-diff+intersection! lset-difference
lset-difference! lset-intersection lset-intersection! lset-union lset-union! lset-xor lset-xor!
lset<= lset= make-list map map! map-in-order member ninth not-pair? null-list? pair-fold
pair-fold-right pair-for-each partition partition! proper-list? reduce reduce-right remove
remove! reverse! second seventh sixth span span! split-at split-at! take take! take-right
take-while take-while! tenth third unfold unfold-right unzip1 unzip2 unzip3 unzip4 unzip5 xcons
zip)

terça-feira, 1 de dezembro de 2009

Opções utilizadas nos diferentes níveis de otimização do GCC

Hoje surgiu uma dica interessante na lista de discussão do GCC. Está reproduzida abaixo:


From: "John (Eljay) Love-Jensen"
Subject: Re: How can I find out which optimizing techniques were used for each function?
To: Byoungyoung Lee, GCC-help
Date: Tue, 1 Dec 2009 04:51:11 -0800

Hi Byoungyoung Lee,

> Is there anyway in gcc to log the information about which compiler
> options were actually used to optimize each function?
> For example, if I compile a program with option -O3, how could I
> figure out which specific options (such as -funroll-loops or something
> like that) were used to optimize function X ?

I use this technique:

echo '' | gcc -O3 -fverbose-asm -S -xc - -o O3.s
cat O3.s

In the created O3.s assembly source comment, it mentions which flags were
enabled by the -O3 switch.

If you want a detailed assembly line-by-line diagnostic of which particular
optimization was used for a given algorithm, you'll have to do some more
sleuthing.

Such as using -fno-<flag> to disable all the flags, and enable them
one-by-one.

Or perhaps by dumping the compiler state after each optimization pass (which
I think is usually only used as a diagnostic aid for making changes to GCC
itself).

Also, the majority of optimizations do not have a toggle-able flag to
enable/disable them. As I understand it... -O1 enables a whole lot of
optimizations that do not have toggle-able flags. -O2 enables a few more.
-O3 enables one-or-two more.

HTH,
--Eljay