<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss1full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/" xmlns:cc="http://web.resource.org/cc/" xmlns="http://purl.org/rss/1.0/">

<channel rdf:about="http://www.perl.it/documenti/articoli/">
<title>Articoli</title>
<link>http://www.perl.it/documenti/articoli/</link>
<description />
<dc:language>en</dc:language>
<dc:creator />
<dc:date>2010-09-06T16:08:02+02:00</dc:date>
<admin:generatorAgent rdf:resource="http://www.movabletype.org/?v=4.2-en" />


<items>
<rdf:Seq>
<rdf:li rdf:resource="http://www.perl.it/documenti/articoli/2010/09/creare-un-parser.html" />

<rdf:li rdf:resource="http://www.perl.it/documenti/articoli/2010/04/anakryptfna.html" />

<rdf:li rdf:resource="http://www.perl.it/documenti/articoli/2010/03/async-howto.html" />

<rdf:li rdf:resource="http://www.perl.it/documenti/articoli/2009/07/autobox-un-po-d.html" />

<rdf:li rdf:resource="http://www.perl.it/documenti/articoli/2008/11/mettiamoli-a-co.html" />

<rdf:li rdf:resource="http://www.perl.it/documenti/articoli/2008/07/la-guida-di-bri.html" />

<rdf:li rdf:resource="http://www.perl.it/documenti/articoli/2008/06/redirezione.html" />

<rdf:li rdf:resource="http://www.perl.it/documenti/articoli/2008/06/dare-una-riordi.html" />

<rdf:li rdf:resource="http://www.perl.it/documenti/articoli/2008/02/dati-statici-di.html" />

<rdf:li rdf:resource="http://www.perl.it/documenti/articoli/2008/01/contextualretur-1.html" />

<rdf:li rdf:resource="http://www.perl.it/documenti/articoli/2008/01/graylister-prov.html" />

<rdf:li rdf:resource="http://www.perl.it/documenti/articoli/2007/11/matrici-in-perl.html" />

<rdf:li rdf:resource="http://www.perl.it/documenti/articoli/2007/09/gtk2-perl-e-dra.html" />

<rdf:li rdf:resource="http://www.perl.it/documenti/articoli/2007/02/perl-template-t.html" />

<rdf:li rdf:resource="http://www.perl.it/documenti/articoli/2007/01/introspezione.html" />
</rdf:Seq>
</items>

<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rdf+xml" href="http://feeds.feedburner.com/ArticoliPerlIt" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="articoliperlit" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /></channel>


<item rdf:about="http://www.perl.it/documenti/articoli/2010/09/creare-un-parser.html">
<title>Creare un parser con Parse::RecDescent</title>
<link>http://www.perl.it/documenti/articoli/2010/09/creare-un-parser.html</link>
<description>Grazie a Dio, i file di configurazione sono dappertutto, e non è più necessario inserire configurazioni direttamente nel codice. E se per caso continui a farlo... beh, almeno sai che non è una buona prassi, no?

In ogni caso, i file di configurazione devono essere interpretati per estrarre le informazioni che contengono. Se il formato del file è uno di quelli ben noti, troverai sicuramente una libreria già pronta. Se il formato non è poi così conosciuto, ma è orientato alla linea (cioè: ogni direttiva di configurazione si trova su una singola riga di testo) e semplice, allora scrivere un parser sarà facile. Se è un file XML, le cose si complicano un po' ma decodificare il file è sempre fattibile: basta usare una delle tante librerie per il parsing di XML, ispezionare gli elementi che ci interessano, e il gioco è fatto. Se poi siamo noi a dover scegliere il formato del file, possiamo usarne uno che sia fatto apposta per la nostra libreria preferita --nel mio caso il modulo &lt;a href="http://http://search.cpan.org/~abw/AppConfig-1.66/"&gt;AppConfig&lt;/a&gt;.

Ma... cosa fare nel caso in cui ci si trovi in un caso diverso? Io, per esempio, dovevo decodificare le informazioni di un file pseudo-INI di 350 chilobyte. Con "pseudo-ini" intendo che ha dei costrutti tipici dei file INI, come le dichiarazioni di sezione:

&lt;pre&gt;[nome_sezione]&lt;/pre&gt;

e associazioni chiave valore, come:

&lt;pre&gt;
    parametro=valore
    valori="possonno essere anche fra doppi apici"
&lt;/pre&gt;

linee di commento:

&lt;pre&gt;
    ; come questa
&lt;/pre&gt;

e sono permesse linee vuote.

Una differenza è che sono permesse assegnazioni multiple allo stesso parametro, che risultano nell'assegnazione di un array di valori al parametro stesso:

&lt;pre&gt;
    parametro=valore1
    parametro=valore2
    parametro=valore3
    ; il valore del parametro è (valore1, valore2, valore3)
&lt;/pre&gt;

E non è finita! La parte più difficile era che ad un parametro era possibile assegnare una struttura multivalore del linguaggio Pike, cioè un array:

&lt;pre&gt;
    parametro=({ valore1, valore2, valore3 })
&lt;/pre&gt;

o un mapping (associazioni chiave/valore):

&lt;pre&gt;
    parametro=([ "key1" : "value1", "key2" : "value2" ])
&lt;/pre&gt;

C'è di più: le strutture Pike possono essere multilinea e annidate! Ad esempio:

&lt;pre&gt;
	parameter=({
	            ([
	                "key1" : "value1",
	                "key2" : ([ "array", "value" ]),
	            ]),
	            "second element of this array",
	            ({
	                "and here is another array",
	                ({
	                    "with another one nested",
	                }),
	                ([
	                    "that" : "contains",
	                    "one"  : "more",
	                    "hash" : "value",
	                ]),
	            }),
	            "Hooray!",
	          })
&lt;/pre&gt;

Un incubo, vero?

Dovevo interpretare questo file. Il formato del file può essere descritto (è quello che ho appena fatto, giusto?), quindi ciò che mi serviva era una descrizione formale (ossia: una grammatica) da dare in pasto ad un generatore di parser. Mi sono ricordato di quel corso sul modulo Parse::RecDescent che seguii nel lontano 1999 alla Open Source Software Convention di Monterey, USA... bei ricordi!!!

Dopo 11 anni, era finalmente arrivato il momento di applicare ciò che avevo imparato durante il corso. Ma, come ho poi scoperto, Parse::RecDescent è un modulo molto potente, e usarlo correttamente può diventare altrettanto complicato. Ecco perché ho deciso di scrivere questo articolo come una guida passo-passo. Naturalmente &lt;strong&gt;è richiesta la conoscenza di Perl&lt;/strong&gt;, dato che parlerò diffusamente di strutture dati in Perl, reference ed altri costrutti senza spiegarli.

La prima parte è scrivere la grammatica. Il nostro file conterrà zero o più linee, fino alla fine del file. Possiamo esprimerlo in questo modo:

&lt;pre&gt;
AsIni: Line(s?) /\Z/
&lt;/pre&gt;

che significa che AsIni è composto da zero o più "Line", fino alla fine del file. So che il nome AsIni fa ridere in Italiano, ma il file si chiama proprio as.ini, quindi non avevo molta scelta...

Come è fatta una "Line"? Può essere un commento, una linea vuota, una dichiarazione di sezione, o una assegnazione a un parametro; nessun altro tipo di linea è consentito. Lo esprimeremo così:

&lt;pre&gt;
Line:   CommentLine
                | BlankLine
                | SectionDeclaration
                | AssignmentLine
                | &amp;lt;error&gt;
&lt;/pre&gt;

Abbiamo fatto un passo avanti, proseguiamo: com'è fatta una linea di commento? Abbiamo detto che inizia con un ";", eventualmente preceduto da spazi, e il commento è tutto il testo che segue quel carattere, fino alla fine della linea. Lo possiamo esprimere in questo modo:

&lt;pre&gt;
CommentLine:    &amp;lt;skip: q{}&gt; /^\s*/m ';' /.*$/m
&lt;/pre&gt;

Cosa significa il costrutto "skip"? Normalmente, Parse::RecDescent isola i "token" che compongono il file, scartando gli spazi eccedenti. Se vogliamo esprimere che la linea può avere spazi in testa, dobbiamo cambiare questo comportamento quando cerchiamo questo tipo di linea: è ciò che il costrutto skip fa. Per maggiori informazioni vi rimando alla documentazione del modulo.

Possiamo usare lo stesso trucco per esprimere BlankLine:

&lt;pre&gt;
BlankLine:      &amp;lt;skip: q{}&gt; /^\s+$/m
&lt;/pre&gt;

Cosa ci fa il modificatore "m" alla fine del pattern matching? È necessario usarlo perché &lt;strong&gt;il testo da elaborare viene passato al parser come un'unica stringa&lt;/strong&gt;, che quindi conterrà anche le sequenze di ritorno a capo. La "m" è un modificatore che, in un certo senso, indica a Perl di match-are l'inizio e la fine della linea all'interno della stringa.

Continuando ad esaminare le possibili linee, arriviamo alla dichiarazione di sezione:

&lt;pre&gt;
SectionDeclaration:     '[' /[^\]]+/ ']'
&lt;/pre&gt;

Che significa: una "[", una stringa non nulla che non contiene "]", e infine il carattaere "]. Era facile.

Siamo arrivati al dunque: le assegnazioni ai parametri. Com'è fatta una linea di assegnazione?

&lt;pre&gt;
AssignmentLine: Parameter '=' Value(?)
&lt;/pre&gt;

Questo significa: il nome del parametro, un segno di "=", ed un valore, o nessun valore (il che significa che il parametro è undef). "(?)" è una "repetition", che significa "0 o 1 ricorrenze di questo elemento".

Abbiamo espresso la AssignmentLine, ma com'è fatto un parametro?

&lt;pre&gt;
Parameter:      /\w[\w\s-]*/
&lt;/pre&gt;

Questo significa: un "word character" (potete pensarlo come un carattere alfanumerico, più il "_"), che può essere seguito da una seuqenza di altri word character, o "spazi" (cioè lo spazio vero e proprio, la tabulazione...), o "-".

Il valore, come detto, può essere una struttura Pike o una stringa:

&lt;pre&gt;
Value:          PikeStructure   | ValueString
&lt;/pre&gt;

Esaminiamo prima le stringhe, che sono più semplici. Abbiamo detto che possono essere stringhe normali o racchiuse fra doppi apici; questo concetto può essere espresso in questo modo:

&lt;pre&gt;
ValueString:    QuotedString    | UnquotedString

QuotedString:   '"' /[^"]+/ '"'

UnquotedString: /.+/
&lt;/pre&gt;

Ciò significa: una QuotedString è una stringa che inizia e finisce con i doppi apici, e contiene caratteri diversi dai doppi apici. Una UnquotedString è una stringa qualsiasi. Si noti che verifichiamo prima se si tratti di una QuotedString, e poi una UnquotedString, altrmenti la UnquotedString sarebbe verificata anche quando non vorremmo che lo fosse (gli apici verrebbero "catturati" come facenti parte della stringa). Questo mi dà anche l'opportunità di far notare che i parser generati da Parse::RecDescent sono di tipo "first match": fra tutte quelle possibili, viene utilizzata la prima regola che viene verificata. Quindi, &lt;strong&gt;è importante che le regole più specifiche vengano verificate per prime&lt;/strong&gt;.

E siamo arrivati alla PikeStructure. Se non lo avete già fatto da poco, procuratevi un caffè perché questa spiegazione sarà lunga e, a tratti, anche complessa. Andate a prenderlo, io vi aspetto qui.

Preso il caffè? Bene. Il primo livello di definizione della PikeStructure è abbastanza semplice, così come il secondo:

&lt;pre&gt;
PikeStructure:  PikeArray | PikeMapping

PikeArray:      '({' PikeArrayContent '})'

PikeMapping:    '([' PikeMappingContent '])'
&lt;/pre&gt;

Cominciamo a lavorare sugli array. Il contenuto di un array può essere:

&lt;ol&gt;
	&lt;li&gt;nessun contenuto (un array vuoto)&lt;/li&gt;
	&lt;li&gt;un elemento&lt;/li&gt;
	&lt;li&gt;due o più elementi, separati da virgole&lt;/li&gt;
&lt;/ol&gt;

Inoltre, è ammissibile che ci sia una virgola in coda all'ultimo valore. Chiameremo la virgola "PikeStructureSeparator", e la sequenza di valori contenuta nell'array la chiameremo "PikeArraySequence". Scriviamo le definizioni:

&lt;pre&gt;
PikeStructureSeparator: ','

PikeArrayContent:       PikeArraySequence(?) PikeStructureSeparator(?)
&lt;/pre&gt;

Quindi possiamo avere zero o una PikeArraySequence (perché zero o una??? Continua a leggere!!!), e zero o uno PikeStructureSeparator in coda. Incidentalmente, questo permette anche di avere una dichiarazione di array vuoto che contiene solo una virgola, ma faremo finta che va bene anche questo.

Ora, definiamo formalmente la sequenza a partire dalla definizione che ne abbiamo dato a parole poche righe più su:

&lt;pre&gt;
PikeArraySequence:      PikeValue PikeArrayFurtherValue(s?)
&lt;/pre&gt;

Questo significa: almeno un PikeValue, pià zero o uno ulteriori valori. Probabilmente cominci a vedere qual'era la strategia: la ripetizione zero/uno "PikeArraySequence(?)" si occupa del caso in cui l'array è vuoto, il singolo PikeValue tiene conto del caso in cui ci sia un singolo valore, e "PikeArrayFurtherValue(s?)" tiene conto del resto. Ma non abbiamo ancora finito.

Che cos'è un PikeValue?

&lt;pre&gt;
PikeValue:              PikeStructure | QuotedString | Number
&lt;/pre&gt;

Un PikeValue può essere: un'altra PikeStructure (che tiene conto del caso in cui vi siano più strutture annidate), o una QuotedString, o un numero... Number non lo avevamo ancora visto! Cos'è un numero?

&lt;pre&gt;
Number: /[+-]?\d*(\.\d+)?/ &amp;lt;reject: $item[1] eq ''&gt;
&lt;/pre&gt;
Questo significa che possiamo avere un segno, quindi potrebbero esserci cifre, dopo le quali potrebbero esserci anche un punto e ulteriori cifre. Putroppo però questo pattern è verificato anche dalla stringa nulla, che non vogliamo che sia verificata perché... non è un numero! Esprimiamo questa condizione con la direttiva reject, che significa: se la stringa che verifica il pattern è la stinga nulla, allora la regola non è verificata.

Questo completa la discussione sul PikeValue, ci manca PikeArrayFurtherValue. Che cos'è? Se ci pensi un attimo, si tratta di prevedere ulteriori valori dopo il primo, quindi:

&lt;pre&gt;
PikeArrayFurtherValue:  PikeStructureSeparator PikeValue
&lt;/pre&gt;

Abbiamo finito: se torni indietro alla PikeArraySequence vedrete che è un PikeValue seguito da zero o più ", PikeValue"!

Questo conclude la discussione sui PikeArray, e possiamo dedicarci ai mapping. Abbiamo già imparato parecchio dalla discussione precedente, quindi per PikeMapping avremo meno bisogno di spiegare:

&lt;pre&gt;
PikeMappingContent:     PikeMappingSequence(?) PikeStructureSeparator(?)

PikeMappingSequence:    PikeMappingPair PikeMappingFurtherPair(s?)

PikeMappingPair:        QuotedString ':' PikeValue

PikeMappingFurtherPair: PikeStructureSeparator PikeMappingPair
&lt;/pre&gt;

Essenzialmente, un PikeMapping è una sequenza di zero o più "QuotedString : PikeValue", che può avere una virgola in coda.

Montando tutti i pezzi assieme otteniamo la nostra grammatica:

&lt;pre&gt;
AsIni: Line(s?) /\Z/

Line:   CommentLine
                | BlankLine
                | SectionDeclaration
                | AssignmentLine
                | &lt;error&gt;
                
CommentLine:    &amp;lt;skip: q{}&gt; /^\s*/m ';' /.*$/m

BlankLine:      &amp;lt;skip: q{}&gt; /^\s+$/m

SectionDeclaration:     '[' /[^\]]+/ ']'

AssignmentLine: Parameter '=' Value(?)

Parameter:      /\w[\w\s-]*/

Value:          PikeStructure   | ValueString

ValueString:    QuotedString    | UnquotedString

QuotedString:   '"' /[^"]+/ '"'

UnquotedString: /.+/

PikeStructure:  PikeArray | PikeMapping

PikeArray:      '({' PikeArrayContent '})'

PikeMapping:    '([' PikeMappingContent '])'

PikeStructureSeparator: ','

PikeArrayContent:       PikeArraySequence(?) PikeStructureSeparator(?)

PikeArraySequence:      PikeValue PikeArrayFurtherValue(s?)

PikeValue:              PikeStructure | QuotedString | Number

Number: /[+-]?\d*(\.\d+)?/ &amp;lt;reject: $item[1] eq ''&gt;

PikeArrayFurtherValue:  PikeStructureSeparator PikeValue

PikeMappingContent:     PikeMappingSequence(?) PikeStructureSeparator(?)

PikeMappingSequence:    PikeMappingPair PikeMappingFurtherPair(s?)

PikeMappingPair:        QuotedString ':' PikeValue

PikeMappingFurtherPair: PikeStructureSeparator PikeMappingPair
&lt;/pre&gt;

I più attenti potrebbero aver intuito una struttura ad albero o un grafo sotto questa grammatica, ed è proprio così che Parse::RecDescent lavora: parte da una radice (nel nostro caso AsIni) e va sempre più in fondo nella struttura delle regole che compongono la grammatica, cercando di verificare ogni regola con le sue sottoregole, andando sempre più in profondità. Se un ramo non viene verificato, il parser torna alla biforcazione precedente e tenta di percorrerla verificando le sue regole, e così via.

Abbiamo quindi una grammatica, che se data in pasto a Parse::RecDescent produce un parser che elaborerà correttamente il nostro file pseudo-ini. Il problema è che non farà &lt;strong&gt;niente&lt;/strong&gt; a parte questo. Perché? Dovreste sapere che i computer sono macchine stupide, e se non gli chiedete di fare qualcosa, loro non fanno assolutamente niente! Dobbiamo istruire esplicitamente Parse::RecDescent su cosa fare quando una regola viene verificata, allegando delle &lt;strong&gt;azioni&lt;/strong&gt; alle regole della nostra grammatica: le azioni sono&lt;strong&gt; pezzi di codice Perl&lt;/strong&gt;.

Per quanto nelle azioni si possa fare qualunque cosa, ho scoperto che nel mio caso specifico la cosa migliore era lasciare che le sezioni di testo "match-ate" dalle regole della grammatica salissero su per l'albero come delle bolle, fino ad arrivare alla regola AssignmentLine. Arrivate lì, le informazioni verranno disposte in un hash annidato, con i nomi delle sezioni al primo livello, i parametri al secondo, e associati a questa coppia avremo un array di valori per quel parametro in quella sezione. Per indirizzare un certo valore useremo quindi un'espressione del tipo:

&lt;pre&gt;
  $AsIni::node{$section_name}{$parameter_name}[$value_index]
&lt;/pre&gt;

Per poterlo fare, è necessario conoscere alcune altre cose.

La prima: &lt;strong&gt;gli elementi che verificano una regola vengono disposti su un array che si chiama @item&lt;/strong&gt;, e su un hash che si chiama %item. Per ciò che riguarda questo articolo, faremo riferimento solo ad @item, rimandando alla documentazione per la descrizione del hash.

Accade quindi che se la stringa

&lt;pre&gt;
"ParseMe"
&lt;/pre&gt;

verifica la regola

&lt;pre&gt;
QuotedString:   '"' /[^"]+/ '"'
&lt;/pre&gt;

allora:

&lt;ul&gt;
	&lt;li&gt;$item[0] conterrà il nome della regola, cioè: QuotedString&lt;/li&gt;
	&lt;li&gt;$item[1] conterrà il valore della stringa '"', cioè... "&lt;/li&gt;
	&lt;li&gt;$item[2] conterrà la stringa che verifica il pattern, cioè: ParseMe&lt;/li&gt;
	&lt;li&gt;$item[3] conterrà ancora il valore della stringa '"'&lt;/li&gt;
&lt;/ul&gt;

&lt;strong&gt;Se invece la regola contiene anche ripetizioni --cioè le stringhe "(?)", "(s?)"... che seguono una sottoregola--, il funzionamento è leggermente diverso&lt;/strong&gt;. In questo caso, gli elementi di @item conterranno una reference all'array dei valori che la sottoregola ha verificato. Cioè, quando la linea:

&lt;pre&gt;
	cheese=pecorino
&lt;/pre&gt;

verifica AssignmentLine, allora:

&lt;ul&gt;
	&lt;li&gt;$item[0] conterrà il nome della regola, cioè: 'AssignmentLine'&lt;/li&gt;
	&lt;li&gt;$item[1] conterrà il valore di Parameter, cioè: "cheese"&lt;/li&gt;
	&lt;li&gt;$item[2] conterrà il valore di '=', cioè... =&lt;/li&gt;
	&lt;li&gt;$item[3] conterrà una reference ad array dei Value che sono stati verificati. In questo caso potremmo esprimere Value con l'espressione Perl [ "pecorino" ]&lt;/li&gt;
&lt;/ul&gt;

Infine, &lt;strong&gt;$return è una variabile speciale che contiene il valore che l'azione deve restuire se l'intera regola è verificata&lt;/strong&gt;. Se una sottoregola viene verificata, ma l'intera regola non lo è, il valore di $return viene scartato. È un comportamento decisamente conveniente, perché se invece conservassimo i risultati man mano che vengono verificati dalle sottoregole, ma la regola successivamente fallisse, dovremmo anche occuparci di eliminare i valori precedentemente salvati. E potrebbe non essere semplice!

Ora sappiamo abbastanza per poter far "salire" i valori, partendo dalle foglie dell'albero (cioè QuotedString, UnquotedString e Number) fino alla cima. È molto semplice:

&lt;pre&gt;
QuotedString:   '"' /[^"]+/ '"'
  {
    $return = $item[2] ;
  }

UnquotedString: /.+/
  {
    $return = $item[1] ;
  }

# This rule matches a number, but rejects null-length results
Number: /[+-]?\d*(\.\d+)?/ &amp;lt;reject: $item[1] eq ''&gt;
  {
    $return = $item[1] ;
  }
&lt;/pre&gt;

Nelle regole per la ripetizione "(?)", bisogna ricordarsi di "spacchettare" il valore contenuto nella reference:

&lt;pre&gt;
PikeMappingContent:     PikeMappingSequence(?) PikeStructureSeparator(?)
  {
    # Since we have a repetition here, $item[1] is a reference to an
    # array which may contain 0 or 1 PikeMappingSequence's.
    # In turn, PikeMappingSequence returns an hash reference.
    # So, if we want the hash reference to bubble up, we have to
    # unwrap it and return it as is.

    ( $return ) = @{ $item[1] } ;
  }
&lt;/pre&gt;

...e così via per gli altri casi simili.

Quando incontriamo una sezione, dobbiamo conservarne il nome in una package variable per poterlo usare successivamente:

&lt;pre&gt;
SectionDeclaration:     '[' /[^\]]+/ ']'
  {
    print STDERR qq{In section "$item[2]"\n} ;

    my $sectionname = $item[2] ;

    $AsIni::section = $sectionname ;
  }
&lt;/pre&gt;

E infine, quando arriviamo a verificare una AssignmentLine, dobbiamo salvare i valori ottenuti nel hash %AsIni::node:

&lt;pre&gt;
AssignmentLine: Parameter '=' Value(?)
  {
    my $distvalue = $item[3] ;
    my $parmname  = $item[1] ;
    my $paramvalue ;

    ( $paramvalue ) = @$distvalue ;

    if ( not exists $AsIni::node{$AsIni::section}{$parmname} ) {
      $AsIni::node{$AsIni::section}{$parmname} = [] ;
    }

    # Get a reference to the current array of values for this parameter
    # in $current
    my $current = $AsIni::node{$AsIni::section}{$parmname} ;

    # We can update this safely, since we are using the reference
    push @$current,$paramvalue ;

  }
&lt;/pre&gt;

La versione finale della grammatica è la seguente:

&lt;pre&gt;
# $Id: g3.txt,v 1.14 2010/07/23 12:41:24 bronto Exp bronto $

AsIni: Line(s?) /\Z/

Line:	CommentLine
		| BlankLine
		| SectionDeclaration
		| AssignmentLine
		| &lt;error&gt;


CommentLine:	&amp;lt;skip: q{}&gt; /^\s*/m ';' /.*$/m
  {
    print STDERR qq{\tSkipping comment: $item[4]\n} ;
  }

BlankLine:	&amp;lt;skip: q{}&gt; /^\s+$/m
  {
    print STDERR qq{\tSkipping blank line\n}
  }

SectionDeclaration:	'[' /[^\]]+/ ']'
  {
    print STDERR qq{In section "$item[2]"\n} ;

    my $sectionname = $item[2] ;

    $AsIni::section = $sectionname ;
  }

AssignmentLine:	Parameter '=' Value(?)
  {
    my $distvalue = $item[3] ;
    my $parmname  = $item[1] ;
    my $paramvalue ;

    ( $paramvalue ) = @$distvalue ;

    if ( not exists $AsIni::node{$AsIni::section}{$parmname} ) {
      $AsIni::node{$AsIni::section}{$parmname} = [] ;
    }

    # Get a reference to the current array of values for this parameter
    # in $current
    my $current = $AsIni::node{$AsIni::section}{$parmname} ;

    # We can update this safely, since we are using the reference
    push @$current,$paramvalue ;

  }

Parameter:	/\w[\w\s-]*/
  {
    $return = $item[1] ;
  }

Value:		PikeStructure	| ValueString
  {
    $return = $item[1] ;
  }

ValueString:	QuotedString	| UnquotedString
  {
    $return = $item[1] ;
  }

QuotedString:	'"' /[^"]+/ '"'
  {
    $return = $item[2] ;
  }

UnquotedString:	/.+/
  {
    $return = $item[1] ;
  }

# This rule matches a number, but rejects null-length results
Number:	/[+-]?\d*(\.\d+)?/ &amp;lt;reject: $item[1] eq ''&gt;
  {
    $return = $item[1] ;
  }

PikeStructure:	PikeArray	| PikeMapping
  {
    # $item[1] is a reference to an array (PikeArray) or hash
    # (PikeMapping). We bubble it up as is
    $return = $item[1] ;
  }

PikeArray:	'({' PikeArrayContent '})'
  {
    # $item[2] is a PikeArrayContent, and since PikeArrayContent
    # bubbles up a reference to an array of PikeValues, this should be
    # an array reference that we can safely bubble up as is.
    $return = $item[2] ;
  }

PikeMapping:	'([' PikeMappingContent '])'
  {
    # $item[2] is a PikeMappingContent, and since PikeMappingContent
    # bubbles up an hash reference, this should be an hash reference that we
    # can safely bubble up as is.
    $return = $item[2] ;
  }

PikeStructureSeparator:	','

PikeArrayContent:	PikeArraySequence(?) PikeStructureSeparator(?)
  {
    # $item[1] comes from a repetition of PikeArraySequence,
    # so it is a reference to an array of 0 or 1 PikeArraySequence.
    # In turn, PikeArraySequence is a reference to an array of
    # PikeValue's. We don't want to change the PikeValue's but we need
    # to unroll $item[1] before bubbling it up.
    ( $return ) = @{ $item[1] } ;
  }

PikeArraySequence:	PikeValue PikeArrayFurtherValue(s?)
  {
    # $item[1] is a PikeValue, hence:
    # - a reference to an array or hash (if PikeStructure)
    # - a scalar (if QuotedString or Number)
    #
    # $item[2] comes from a repetition of PikeArrayFurtherValue,
    # so it is a reference to an array of 0 or 1 PikeArrayFurtherValue.
    # In turn, PikeArrayFurtherValue just returns a PikeValue. So,
    # we actually don't want to change $item[1], but we need to
    # unroll $item[2] before returning it. Actually, we return an
    # array reference with the whole thing.
    $return = [ $item[1], @{ $item[2] } ] ;
  }

PikeArrayFurtherValue:	PikeStructureSeparator PikeValue
  {
    # $item[2] is a PikeValue, hence:
    # - a reference to an array or hash (if PikeStructure)
    # - a scalar (if QuotedString or Number)
    # We bubble it up as is.
    $return = $item[2] ;
  }

PikeMappingContent:	PikeMappingSequence(?) PikeStructureSeparator(?)
  {
    # Since we have a repetition here, $item[1] is a reference to an
    # array which may contain 0 or 1 PikeMappingSequence's.
    # In turn, PikeMappingSequence returns an hash reference.
    # So, if we want the hash reference to bubble up, we have to
    # unwrap it and return it as is.
    
    ( $return ) = @{ $item[1] } ;
  }

PikeMappingSequence:	PikeMappingPair PikeMappingFurtherPair(s?)
  {
    # $item[1] is a PikeMappingPair, hence a reference to an array
    # of two elements: a string and a PikeValue, that is:
    # - a reference to an array or hash (if Pikevalue ~ PikeStructure)
    # - a scalar (if PikeValue ~ QuotedString or Number)
    #
    # $item[2] has a repetition, so it is a reference to an array of
    # PikeMappingFurtherPair's. Since PikeMappingFurtherPair just
    # returns a PikeMappingPair (see $item[1]), then $item[2] is
    # a reference to an array where each element is, in turn, a
    # reference to an array of two elements.
    #
    # Since we are going to return an hash here, we create a reference
    # to an hash; to correctly unroll the values of $item[1] and
    # $item[2] we:
    # - simply dereference $item[1], hence unrolling the only hash
    #   pair the array contained
    # - we dereference $item[2], getting an array of arrays, and
    #   then we use map to further unroll the key/value pairs
    #
    # We then bubble up the outcome
    $return = { @{ $item[1] } , map( @$_ , @{ $item[2] } ) } ;
  }

PikeMappingPair:	QuotedString ':' PikeValue
  {
    # $item[1] is a scalar (QuotedString)
    # $item[3] is a PikeValue, hence:
    # - a reference to an array or hash (if Pikevalue ~ PikeStructure)
    # - a scalar (if PikeValue ~ QuotedString or Number)
    # We throw them up together as a single entity: a reference to an array
    $return = [ $item[1], $item[3] ] ;
  }

PikeMappingFurtherPair:	PikeStructureSeparator PikeMappingPair
  {
    # $item[2] is a PikeMappingPair, hence a reference to an array
    # containing a QuotedString (the first) and a PikeValue, hence:
    # - a reference to an array or hash (if Pikevalue ~ PikeStructure)
    # - a scalar (if PikeValue ~ QuotedString or Number)
    $return = $item[2] ;
  }

PikeValue:		PikeStructure | QuotedString | Number
  {
    # $item[1] is:
    # - a reference to an array or hash (if PikeStructure)
    # - a scalar (if QuotedString or Number)
    $return = $item[1] ;
  }
&lt;/pre&gt;

Potete provarla su uno dei vostri file, magari uno di grosse dimensioni... ma se non ne avete uno a portata di mano potete anche accontentarvi di questo piccolo esempio:

&lt;pre&gt;
[section1]
  onehash=([ "onekey" : "onevalue" ])
  hashtest=([ "key1" : "val1", "key2" : "val2" ])
  aohtest=({
    ([ "hash1key1": "hash1val1" ]),
    ([
      "hash2key1": "hash2val1",
      "hash2key2": "hash2val2",
    ]),
    })
  string=sample string
  onearray=({ "onevalue" })
&lt;/pre&gt;

E per testarlo avrete bisogno di uno script di test, giusto? Ve ne lascio uno molto sbrigativo, che legge la grammatica da un file che si chiama g3.txt e un file INI da mockup.ini, entrambi nella directory corrente --scrivere qualcosa di più serio è lasciato al lettore per esercizio.

&lt;pre&gt;
#!/usr/bin/perl

# $Id: test.pl,v 1.8 2010/07/23 13:00:09 bronto Exp bronto $

use strict ;
use warnings ;

use Parse::RecDescent ;
use Data::Dumper ;

########################################################################
package AsIni ;

our %node ;
our $section ;
our $parmname ;
our $content ;

########################################################################
package AsIni::Parser ;

push @ARGV,0 unless @ARGV &gt; 0 ;

eval { use constant DEBUG =&gt; $ARGV[0] } ;
die $@ if $@ ;

if (DEBUG &gt;= 1) {
  $::RD_HINT  = 'true' ;
  $::RD_WARN  = 'true' ;

  $Data::Dumper::Indent = 1 ;

  if (DEBUG &gt;= 2) {
    $::RD_TRACE  = 'true' ;
    $::RD_ERRORS = 'true' ;
  }
}

my $grammar = q{} ;
my $asini   = q{} ;
{
  local $/ ;
  undef $/ ;

  open my $grammarfh, '&amp;lt;', 'g3.txt' or die ;
  $grammar = &amp;lt;$grammarfh&gt; ;


  open my $asinifh, '&amp;lt;', 'mockup.ini' or die ;
  $asini   = &amp;lt;$asinifh&gt; ;
}

my $parser = Parse::RecDescent-&gt;new($grammar) ;
die if not defined $parser ;

my $parser_outcome = $parser-&gt;AsIni($asini) ;

print Dumper ( $parser_outcome ) if DEBUG &gt;= 3 ;

print Dumper ( \%AsIni::node  )  if DEBUG &gt;= 0 ;
&lt;/pre&gt;

&lt;p&gt;
Potete passare allo script un parametro, il debug level, da zero a tre per fargli emettere delle informazioni di debug sia dallo script stesso, sia da Parse::RecDescent. Il significato delle variabili RD_* è spiegato nel manuale.
&lt;br/&gt;
Buon divertimento!!!
&lt;/p&gt;

&lt;big&gt;&lt;strong&gt;Bibliografia:&lt;/strong&gt;&lt;/big&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://cpansearch.perl.org/src/DCONWAY/Parse-RecDescent-1.94/tutorial/tutorial.html"&gt;Parse::RecDescent tutorial by Damian Conway&lt;/a&gt; &lt;/li&gt;
	&lt;li&gt;&lt;a href="http://search.cpan.org/~dconway/Parse-RecDescent-1.965001/lib/Parse/RecDescent.pm"&gt;Documentation for Parse::RecDescent&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ArticoliPerlIt?a=zpftz5xgr0E:tLCEFxmrn0o:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ArticoliPerlIt?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ArticoliPerlIt?a=zpftz5xgr0E:tLCEFxmrn0o:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ArticoliPerlIt?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
<dc:subject>article</dc:subject>
<dc:creator>bronto</dc:creator>
<dc:date>2010-09-06T16:08:02+02:00</dc:date>
</item>

<item rdf:about="http://www.perl.it/documenti/articoli/2010/04/anakryptfna.html">
<title>Crypt::FNA</title>
<link>http://www.perl.it/documenti/articoli/2010/04/anakryptfna.html</link>
<description>&lt;img src="/img/icons/trophy.png" alt="Vincitore Contest2009" border="0" height="88" width="65" style="float:left;padding:0px 5px 0px 0px"&gt;

&lt;h2&gt;Anak's Fractal Numerical Algorithm for a new cryptography technology&lt;/h2&gt;

			&lt;br /&gt;&lt;br /&gt;
			&lt;b style="color:#ff0000"&gt;a. Una nuova crittografia frattale&lt;/b&gt;
			&lt;br /&gt;&lt;br /&gt;

			&lt;i&gt;
				"Le nuvole non sono sfere, le montagne non sono coni, le costiere non sono cerchi e la corteccia non &amp;egrave; liscia, n&amp;eacute; la luce viaggia su una linea retta"
			&lt;/i&gt;
			&lt;p align="right"&gt;
				cos&amp;igrave; Benoit Mandelbrot ne "Il Mondo dei frattali"
			&lt;/p&gt;

			Non potevo iniziare questo articolo senza citare l'incipit del bellissimo libro di Mandelbrot: in realt&amp;agrave; i frattali che incontreremo nascono ben prima degli anni '70 del  XX secolo ma procediamo per gradi...
			Chiariamo immediatamente che cosa &amp;egrave; FNA:
			&lt;br /&gt;
			&lt;br /&gt;
			Crypt::FNA &amp;egrave; l'implementazione, in linguaggio Perl, di due distinti algoritmi che ho elaborato:
			&lt;ul&gt;
				&lt;li&gt;per la costruzione dell'insieme di una famiglia di curve frattali&lt;/li&gt;
				&lt;li&gt;per una crittografia basata su queste curve&lt;/li&gt;
			&lt;/ul&gt;

&lt;!-- PAR B --&gt;

			&lt;br /&gt;&lt;br /&gt;
			&lt;b style="color:#ff0000"&gt;b. Definizione dell'insieme di curve frattali {F}&lt;/b&gt;
			&lt;br /&gt;&lt;br /&gt;

			&lt;i&gt;
				"Il caso favorisce solo la mente preparata"
			&lt;/i&gt;
			&lt;p align="right"&gt;
				Louis Pasteur
			&lt;/p&gt;

			Immaginate la complessit&amp;agrave;, a livello computazionale, di un algoritmo per la costruzione della curva di Koch che segua l'idea del suo creatore e cio&amp;egrave;:
			&lt;br /&gt;
			&lt;img src="07/fna_fig1.png" width="338" height="193" align="left" /&gt;
			&lt;br /&gt;
			&lt;ol&gt;
				&lt;li&gt;prendi un segmento... e fin qui
				&lt;li&gt;dividilo in tre... e fin qui
				&lt;li&gt;elimina il segmento mediano... mmmh...
				&lt;li&gt;congiungi i due punti mediani con un altro in modo da avere un triangolo equilatero... mmmmhh
				&lt;li&gt;itera il procedimento su ogni segmento.... Mumble... complesso, considerato poi che per ogni segmento occorre, dopo il disegno, rimuovere una parte, calcolare le coordinate dell'altro vertice e cos&amp;igrave; via...
			&lt;/ol&gt;

			Se avessi implementato questo algoritmo per la costruzione della curva di ordine &lt;i&gt;n&lt;/i&gt;, avrei dovuto, necessariamente, calcolare tutte le curve da 1 a n-1. Dovevo semplificare...&lt;br /&gt;&lt;br /&gt;
			La propriet&amp;agrave; fondamentale di questa curva, come pure di tante altre curve frattali, &amp;egrave; l'autosimilitudine.&lt;br /&gt;&lt;br /&gt;
			Ragioniamo inizialmente sulla curva di Koch per poi estendere i risultati.
			&lt;br /&gt;&lt;br /&gt;
			&lt;img src="07/fna_fig2.png" width="498" height="223" /&gt;
			&lt;br /&gt;&lt;br /&gt;

			Indicando quindi con:&lt;br /&gt;
			&lt;table style="width:565px;background:#f7f7f7;font-family:verdana,helvetica,sans-serif;font-size:12px;font-weight:normal;line-height:24px;color:#222"&gt;
				&lt;tr&gt;&lt;td valign="top"&gt;Ro:&lt;/td&gt;&lt;td&gt;il numero di parametri della base (4 nel caso della curva di Koch)&lt;/td&gt;&lt;/tr&gt;
				&lt;tr&gt;&lt;td valign="top"&gt;r:&lt;/td&gt;&lt;td&gt;l'ordine della curva&lt;/td&gt;&lt;/tr&gt;
				&lt;tr&gt;&lt;td valign="top"&gt;an&lt;sub&gt;n&lt;/sub&gt;:&lt;/td&gt;&lt;td&gt; numero angoli della curva di ordine &lt;i&gt;n&lt;/i&gt;&lt;/td&gt;&lt;/tr&gt;
			&lt;/table&gt;

			&lt;br /&gt;
			Possiamo stabilire che il numero di angoli (an) della curva di ordine n &amp;egrave;:

			&lt;p align="center"&gt;
				an&lt;sub&gt;n&lt;/sub&gt;=Ro&lt;sup&gt;r&lt;/sup&gt;
			&lt;/p&gt;

			Riportiamo ora gli angoli dei vari ordini in una costruzione a triangolo:
			&lt;pre&gt;
                                     0
                               0, 60, -60, 0
       0, 60, -60, 0, 60, 120, 0, 60, -60, 0, -120, -60, 0, 60, -60, 0
			&lt;/pre&gt;

			Vi ricorda qualcosa? Notiamo la somiglianza con la costruzione del Triangolo di Tartaglia:

			&lt;pre&gt;
                                     1
                                  1     1
                               1     2     1
                            1     3     3     1
                         1     4     6     4     1
			&lt;/pre&gt;

			Questo triangolo riporta la disposizione triangolare dei coefficienti binomiali, ossia dei coefficienti dello sviluppo del binomio &lt;i&gt;(a+b)&lt;/i&gt; elevato ad una qualsiasi potenza &lt;i&gt;n&lt;/i&gt;.
			&lt;br /&gt;&lt;br /&gt;
			La cosa che a noi interessa &amp;egrave; che ogni numero del triangolo &amp;egrave; ottenuto come somma delle due corrispondenti al rigo superiore: osserviamo che possiamo esprimere la propriet&amp;agrave; di auto-similitudine della curva di Koch grazie ad una costruzione simile, combinando tra loro i valori della base e poi con quelli derivati dalla combinazione e cos&amp;igrave; via iterando il procedimento.
			&lt;br /&gt;&lt;br /&gt;

			In questo caso, per Ro=4, abbiamo questa situazione:
			&lt;br /&gt;&lt;br /&gt;

			riga per r=0 -&gt; 0 + 0 = &lt;b&gt;0&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;

			riga per r=1 -&gt; 0 + 0 = &lt;b&gt;0&lt;/b&gt;; 0 + 60 = &lt;b&gt;60&lt;/b&gt;; 0 - 60 = &lt;b&gt;-60&lt;/b&gt;; 0 + 0 = &lt;b&gt;0&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;

			riga per r=2 -&gt;&lt;br /&gt;
			a.	0 + 0 = &lt;b&gt;0&lt;/b&gt;;		0 + 60 = &lt;b&gt;60&lt;/b&gt;;	0 - 60 = &lt;b&gt;-60&lt;/b&gt;;		0 + 0 = &lt;b&gt;0&lt;/b&gt;&lt;br /&gt;
			b.	60 + 0 = &lt;b&gt;60&lt;/b&gt;;	60 + 60 = &lt;b&gt;120&lt;/b&gt;;		60 - 60 = &lt;b&gt;0&lt;/b&gt;;	60 + 0 = &lt;b&gt;60&lt;/b&gt;&lt;br /&gt;
			c.	-60 + 0 = &lt;b&gt;-60&lt;/b&gt;;	-60 + 60 = &lt;b&gt;0&lt;/b&gt;;	-60 - 60 = &lt;b&gt;-120&lt;/b&gt;;	-60 + 0 = &lt;b&gt;-60&lt;/b&gt;&lt;br /&gt;
			d.	0 + 0 = &lt;b&gt;0&lt;/b&gt;;		0 + 60 = &lt;b&gt;60&lt;/b&gt;;	0 - 60 = &lt;b&gt;-60&lt;/b&gt;;		0 + 0 = &lt;b&gt;0&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;

			Iterando il procedimento, otteniamo proprio gli angoli della curva di ordine &lt;i&gt;n&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;

			Sembra per&amp;ograve; che per identificare gli angoli della curva di ordine &lt;i&gt;n&lt;/i&gt; sia ancora necessario procedere all'identificazione degli angoli di tutte quelle con ordine &lt;&lt;i&gt;n&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;
			Continuiamo ad osservare, scrivendo la successione degli angoli come gli elementi di un vettore:

			&lt;pre&gt;
             a(0)  =  a(0) + a(0)
             a(1)  =  a(0) + a(1)                I   GRUPPO
             a(2)  =  a(0) + a(2)
             a(3)  =  a(0) + a(3)
             ----------------------------------------------
             a(4)  =  a(1) + a(0)
             a(5)  =  a(1) + a(1)                II  GRUPPO
             a(6)  =  a(1) + a(2)
             a(7)  =  a(1) + a(3)
             ----------------------------------------------
             a(8)  =  a(2) + a(0)
             a(9)  =  a(2) + a(1)                III GRUPPO
             a(10) =  a(2) + a(2)
             a(11) =  a(2) + a(3)
             ----------------------------------------------
             a(12) =  a(3) + a(0)
             a(13) =  a(3) + a(1)                IV  GRUPPO
             a(14) =  a(3) + a(2)
             a(15) =  a(3) + a(3)
			&lt;/pre&gt;

			Abbiamo cos&amp;igrave; le somme per identificare i vari angoli di inclinazione dei segmenti approssimanti la curva...&lt;br /&gt;
			Scritte le relazioni in questo modo, possiamo osservare chiaramente la propriet&amp;agrave; dei due addendi che forniscono l'angolo &lt;i&gt;n&lt;/i&gt;-esimo:&lt;br /&gt;&lt;br /&gt;

			il primo addendo &amp;egrave; il gruppo o ramo su cui si itera il procedimento di costruzione.&lt;br /&gt;&lt;br /&gt;

			Il secondo addendo &amp;egrave; la posizione dell'angolo che stiamo calcolando nell'ambito di quel ramo.&lt;br /&gt;&lt;br /&gt;

			Il gruppo cui appartiene l'angolo k-esimo possiamo indicarlo cos&amp;igrave; nel formalismo del Perl:

			&lt;p align="center"&gt;
				G(k) = int(k/Ro)
			&lt;/p&gt;

			La posizione dell'angolo k-esimo nel gruppo &amp;egrave; invece:

			&lt;p align="center"&gt;
				P(k) = k-int(k/Ro) = k-G(k)
			&lt;/p&gt;

			In definitiva, il valore della direzione k-esima sar&amp;agrave;:

			&lt;p align="center"&gt;
				&lt;b&gt;
					a(k)=a(G(k)) + a(P(k))
				&lt;/b&gt;
				&lt;sup&gt;(1)&lt;/sup&gt;
			&lt;/p&gt;

			Notiamo che questa relazione &amp;egrave; generale, indipendente dal numero di parametri base della curva. In quella di Koch abbiamo una base di cardinalit&amp;agrave; pari a 4 ma non &amp;egrave; necessariamente cos&amp;igrave;.&lt;br /&gt;&lt;br /&gt;

			Con questa relazione diventa semplice ricavare il grafico della curva, potendone calcolare le direzioni dei segmenti approssimanti ad un certo ordine ed implementando poi un sistema di turtle graphics per il tracciamento:&lt;br /&gt;&lt;br /&gt;

			&lt;pre&gt;
            while ($k&lt;$Ro**$r) {
                 $a[$k]=$a[int($k/$Ro)]+$a[$k-int($k/$Ro)];
                 $k++
            }
            &lt;/pre&gt;

			Indichiamo quindi con {F} l'insieme delle curve le cui direzioni dei segmenti approssimanti sono ottenute mediante la relazione (1). {F} ha una dimensione di Hausdorff compresa tra 1 e 2 (con piccole varianti possono calcolarsi anche quelle con dimensione minore di 1, come la polvere di Cantor) e cardinalit&amp;agrave; infinita, come facilmente rilevabile osservando il numero di parametri genitore possibili.
			&lt;br /&gt;&lt;br/&gt;

&lt;!-- PAR C --&gt;

			&lt;br /&gt;
			&lt;b style="color:#ff0000"&gt;c. Grafico di alcune curve di {F}&lt;/b&gt;
			&lt;br /&gt;&lt;br /&gt;

			Di seguito alcuni grafici realizzati tramite il metodo make_fract di Crypt::FNA che implementa l'algoritmo appena descritto.
			&lt;br /&gt;&lt;br /&gt;
			&lt;p align="center"&gt;
				&lt;img src="07/fna_fig3.png" width="516" height="398" /&gt;
				&lt;br /&gt;
				(56,-187, 215, 64)

				&lt;br /&gt;&lt;br /&gt;

				&lt;img src="07/fna_fig4.png" width="452" height="361" /&gt;
				&lt;br /&gt;
				(0,90,-60,-90,60)

				&lt;br /&gt;&lt;br /&gt;

				&lt;img src="07/fna_fig5.png" width="505" height="427" /&gt;
				&lt;br /&gt;
				(56,-77,215,-64,60)

				&lt;br /&gt;&lt;br /&gt;

				&lt;img src="07/fna_fig6.png" width="463" height="456" /&gt;
				&lt;br /&gt;
				(56,-177,225,-164)
			&lt;/p&gt;

&lt;!-- PAR D --&gt;

			&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;
			&lt;b style="color:#ff0000"&gt;d. Algoritmo di crittografia basato su una curva dell'insieme {F}&lt;/b&gt;
			&lt;br /&gt;&lt;br /&gt;
			&lt;i&gt;
				"Il pi&amp;ugrave; nobile dei piaceri &amp;egrave; la gioia di capire"
			&lt;/i&gt;
			&lt;p align="right"&gt;
				Leonardo da Vinci
			&lt;/p&gt;

			Abbiamo quindi incontrato, spero piacevolmente, questi strani enti autosimili ma il mio desiderio &amp;egrave; di applicarli, creando nel contempo, tecnologia.&lt;br /&gt;&lt;br /&gt;

			Anni addietro mi sono interessato di crittografia, sviluppando un sistema adatto a cifrare stringhe ASCII. Adesso volevo usare le curve {F} in modo da criptare i files pi&amp;ugrave; disparati.&lt;br /&gt;&lt;br /&gt;

			Il ragionamento seguito per giungere a questo scopo &amp;egrave; il seguente.&lt;br /&gt;&lt;br /&gt;

			I dati sono memorizzati in byte: qualunque tipo di file vada ad aprire, il suo contenuto &amp;egrave; certamente una sequenza ben precisa di byte. Un byte &amp;egrave; costituito da 8 bit, per cui il suo valore deve appartenere all'insieme degli interi compresi tra 0 e 255 (256 elementi complessivamente). Seguo quindi la curva frattale scelta, dell'insieme {F}, per un numero di vertici uguale a quella del valore del byte da criptare. Le coordinate cartesiane di quel vertice rappresentano il crittogramma di quel ben preciso byte.&lt;br /&gt;&lt;br /&gt;

			Qualcuno potrebbe domandarsi perch&amp;eacute; non una funzione &lt;i&gt;y=f(x)&lt;/i&gt; qualsiasi? La risposta &amp;egrave; che i grafici delle funzioni &lt;i&gt;y=f(x)&lt;/i&gt; non hanno un andamento notevolmente irregolare come nel caso dei frattali ed &amp;egrave; proprio questa irregolarit&amp;agrave; a rendere maggiormente complessa la crittoanalisi. In altre parole, i frattali appartenenti ad {F} non essendo frutto di una funzione matematica, bens&amp;igrave; di un algoritmo, non sono dotati di UNA relazione "singola" che permetta di calcolarne le coordinate di ogni punto. Ho calcolato che la "visibilit&amp;agrave; diretta", dati &lt;i&gt;k&lt;/i&gt; angoli e base di cardinalit&amp;agrave; ro &amp;egrave;: &lt;i&gt;ro^2+(k-int(k/ro))&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;

			Le curve {F} hanno quindi un andamento che, in generale, si conosce solo calcolandolo ma lo si pu&amp;ograve; calcolare solo se sono noti i parametri Ro genitori che sono parti fondamentali della chiave: &amp;egrave; proprio in questo il cuore del sistema crittografico. Come altri sistemi di cifratura simmetrici, ad esempio il DES ed AES, FNA ha chiave segreta ma a differenza dei predetti Data Encryption Standard (che ha una chiave di 56 bit) ed Advanced Encryption Standard (che ha una chiave compresa tra i 128 ed i 256 bit), Fractal Numerical Algorithm ha una chiave in bit lunga quanto si vuole: non ci sono restrizioni sul numero e valore delle direzioni della base Ro.&lt;br /&gt;&lt;br /&gt;

			L'attento lettore avr&amp;agrave; forse notato che il byte "0" produce, nel crittogramma, ripetizione nei valori (avanzando di 0 vertici sulla curva): alla crittoanalisi, ove ci fossero coppie di coordinate uguali e consecutive, identificherei tutti i bytes di valore "0". Ho evitato questo comportamento, procedendo sempre e comunque in avanti sulla curva: crittografato il valore di un byte nelle cartesiane del vertice k-esimo, si riparte dal successivo k+1-esimo. Ho poi ulteriormente modificato l'algoritmo, introducendo il cosiddetto "magic number", un altro parametro, segreto, che istruisce il sistema a saltare un certo numero di vertici della curva frattale, in modo da far perdere le tracce del percorso seguito...&lt;br /&gt;&lt;br /&gt;

			In definitiva:&lt;br /&gt;&lt;br /&gt;

			&lt;i&gt;
				criptare&lt;br /&gt;&lt;br /&gt;
				Ogni byte viene  crittografato mediante le coordinate del vertice della curva frattale, ottenuto partendo dal successivo a quello precedentemente valutato, saltando di un numero ulteriore di vertici uguale al magic number pi&amp;ugrave; il valore del byte da crittografare.
				&lt;br /&gt;&lt;br /&gt;
				decriptare&lt;br /&gt;&lt;br /&gt;
				Si segue la curva frattale verificando, di vertice in vertice, che le coordinate corrispondano a quelle del crittogramma. Il valore del byte originale viene ricostruito avendo contato quanti vertici si sono succeduti per arrivare all'uguaglianza dei due valori, dall'ultima uguaglianza incontrata. Il numero di vertici, ridotto del magic number sommato all'unit&amp;agrave;, rappresenta  il valore del byte n-esimo.
			&lt;/i&gt;
			&lt;br /&gt;&lt;br /&gt;

&lt;!-- PAR E --&gt;

			&lt;br /&gt;
			&lt;b style="color:#ff0000"&gt;e. Crypt::FNA i metodi della classe&lt;/b&gt;
			&lt;br /&gt;&lt;br /&gt;

			La libreria Crypt::FNA &amp;egrave; costituita da una classe principale ed una accessoria per la validazione dell'istanza. La classe principale, in Anakrypt/FNA.pm, contiene il codice per l'istanziazione dell'oggetto frattale oltre i metodi per la crittografia ed il disegno della particolare approssimazione alla curva dell'insieme {F}. L'altra classe, in Anakrypt/FNA/Validation.pm, riporta: i valori di default per una istanziazione veloce dell'oggetto; i controlli di coerenza sui valori degli attributi in fase di istanziazione; la cattura degli errori in scrittura e lettura sui files di lavoro coinvolti.&lt;br /&gt;&lt;br /&gt;

			Crypt::FNA comprende quattro metodi:
			&lt;ul&gt;
				&lt;li&gt;
					new
					&lt;ul&gt;
						&lt;li&gt;per  l'istanziazione di un nuovo oggetto FNA&lt;/li&gt;
					&lt;/ul&gt;
				&lt;/li&gt;
				&lt;li&gt;
					make_fract
					&lt;ul&gt;
						&lt;li&gt;per il disegno della curva frattale utilizzata da FNA&lt;/li&gt;
					&lt;/ul&gt;
				&lt;/li&gt;
				&lt;li&gt;
					encrypt_file
					&lt;ul&gt;
						&lt;li&gt;per calcolare il crittogramma, secondo la curva scelta, di un file&lt;/li&gt;
					&lt;/ul&gt;
				&lt;/li&gt;
				&lt;li&gt;
					decrypt_file
					&lt;ul&gt;
						&lt;li&gt;per ricostruire il file partendo dal crittogramma&lt;/li&gt;
					&lt;/ul&gt;
				&lt;/li&gt;
				&lt;li&gt;
					encrypt_scalar
					&lt;ul&gt;
						&lt;li&gt;per calcolare il crittogramma di un testo&lt;/li&gt;
					&lt;/ul&gt;
				&lt;/li&gt;
			&lt;/ul&gt;

			Vediamo ora nel dettaglio i metodi e relativa sintassi
			&lt;br /&gt;&lt;br /&gt;

&lt;!-- PAR E.1 --&gt;

			&lt;br /&gt;
			&lt;b style="color:#ff0000"&gt;e.1 Il metodo "new"&lt;/b&gt;
			&lt;br /&gt;&lt;br /&gt;

			Questo metodo ha due diverse modalit&amp;agrave; per l'istanziazione dell'oggetto:
			&lt;br /&gt;&lt;br /&gt;

			&lt;pre&gt;
            1.	my $krypto=FNA-&gt;new();
            2.	my $krypto=FNA-&gt;new(
                     {
                           r=&gt; 7,
                           angle =&gt;  [56,-187, 215,-64],
                           square =&gt; 4096,
                           background =&gt; [255,255,255],
                           foreground =&gt; [0,0,0],
                           magic =&gt; 3
                     }
                );
			&lt;/pre&gt;

			&lt;br /&gt;

			Con la prima modalit&amp;agrave;, l'oggetto viene creato con i valori standard, fissati nella classe "Crypt::FNA::Validation". Nella seconda modalit&amp;agrave;, si specificano tutti o parte dei parametri dell'oggetto che ora vedremo in dettaglio.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;

&lt;!-- PAR E.1.1 --&gt;

			&lt;br /&gt;&lt;b style="color:#ff0000"&gt;e.1.1 Il parametro "r": ordine della curva di {F}&lt;/b&gt;
			&lt;br /&gt;&lt;br /&gt;

			Indica il livello di approfondimento nel calcolo della curva. E' un numero maggiore di zero, non necessariamente intero. Indicato con Ro il numero di angoli base della struttura autosimile, il numero di segmenti costituenti la curva &amp;egrave; dato da &lt;i&gt;Ro**r&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;

			Valore di default: 7&lt;br /&gt;&lt;br /&gt;

&lt;!-- PAR E.1.2 --&gt;

			&lt;br /&gt;&lt;b style="color:#ff0000"&gt;e.1.2 I parametri "angle": direzioni dei segmenti base della curva di {F}&lt;/b&gt;
			&lt;br /&gt;&lt;br /&gt;

			Sono gli angoli cui si applica l'algoritmo di ricorsione: su questi angoli si determina la struttura base autosimile della curva di {F}. Gli angoli sono espressi nel sistema sessadecimale, con valori compresi tra -360  e 360 (ovvero da 0 a 360).&lt;br /&gt;&lt;br /&gt;

			Valore di default: (56,-187, 215,-64)&lt;br /&gt;&lt;br /&gt;

&lt;!-- PAR E.1.3 --&gt;

			&lt;br /&gt;&lt;b style="color:#ff0000"&gt;e.1.3 Il parametro "square": lato del quadrato dove verr&amp;agrave; disegnata/calcolata la curva di {F}&lt;/b&gt;
			&lt;br /&gt;&lt;br /&gt;

			E' la lunghezza del lato del quadrato contenitore della curva. Square non solo ha importanza per la (eventuale) rappresentazione grafica, ma anche per la crittografia, poich&amp;eacute; viene utilizzato per calcolare la lunghezza del lato di della curva (&lt;i&gt;di&lt;/i&gt; &amp;egrave; proporzionale a &lt;i&gt;square/Ro**r&lt;/i&gt;)&lt;br /&gt;&lt;br /&gt;

			Valore di default: 4096
			&lt;br /&gt;&lt;br /&gt;

&lt;!-- PAR E.1.4 --&gt;

			&lt;br /&gt;&lt;b style="color:#ff0000"&gt;e.1.4 Il parametro "background": colore di fondo per il disegno della curva di {F}&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;

			E' il colore RGB di fondo del file PNG contenente il disegno della curva. La notazione &amp;egrave; decimale, quindi con valori che vanno da 0 a 255.&lt;br /&gt;&lt;br /&gt;

			Valore di default: (255,255,255)&lt;br /&gt;&lt;br /&gt;

&lt;!-- PAR E.1.5 --&gt;

			&lt;br /&gt;&lt;b style="color:#ff0000"&gt;e.1.5 Il parametro "foreground": colore di primo piano per il disegno della curva di {F}&lt;/b&gt;
			&lt;br /&gt;&lt;br /&gt;

			E' il colore RGB del tratto nel file PNG contenente il disegno della curva. La notazione &amp;egrave; decimale, quindi con valori che vanno da 0 a 255.&lt;br /&gt;&lt;br /&gt;

			Valore di default: (0,0,0)&lt;br /&gt;&lt;br /&gt;

&lt;!-- PAR E.1.6 --&gt;

			&lt;br /&gt;&lt;b style="color:#ff0000"&gt;e.1.6 Il parametro "magic number": per la crittografia discreta&lt;/b&gt;
			&lt;br /&gt;&lt;br /&gt;

			Indica il numero di vertici della curva da saltare in fase di cifratura e decifratura: essendo l'algoritmo, una funzione continua sui vertici, saltandone alcuni questa resta continua su punti isolati dell'insieme dei vertici (da cui "discreta").&lt;br /&gt;&lt;br /&gt;

			Valore di default: 3&lt;br /&gt;&lt;br /&gt;

&lt;!-- PAR E.2 --&gt;

			&lt;br /&gt;&lt;b style="color:#ff0000"&gt;e.2 Il metodo "encrypt_file"&lt;/b&gt;
			&lt;br /&gt;&lt;br /&gt;

			I metodi &lt;i&gt;encrypt_file&lt;/i&gt; e &lt;i&gt;decrypt_file&lt;/i&gt;, sono la summa: rendono utile mediante applicazione, la matematica delle curve di {F}. Questo metodo realizza un'operazione ben precisa: cripta il file di input in quello di output.&lt;br /&gt;&lt;br /&gt;

			La sintassi &amp;egrave;:&lt;br /&gt;

			&lt;pre&gt;
        $krypto-&gt;encrypt_file($name_plain_file,$name_encrypted_file)
            &lt;/pre&gt;

			Il file di input di qualsivoglia formato sar&amp;agrave; letto e cifrato, tramite la curva {F}.&lt;br /&gt;&lt;br /&gt;

 &lt;!-- PAR E.3 --&gt;

			&lt;br /&gt;&lt;br /&gt;&lt;b style="color:#ff0000"&gt;e.3 Il metodo "decrypt_file"&lt;/b&gt;

			I metodi &lt;i&gt;decrypt_file&lt;/i&gt; ed &lt;i&gt;encrypt_file&lt;/i&gt;, sono la summa: rendono utile mediante applicazione, la matematica delle curve di {F}. Questo metodo realizza un'operazione ben precisa: decripta il file di input (che &amp;egrave; quello di output del metodo encrypt_file) in quello di output (che &amp;egrave; quello di input del metodo encrypt_file).&lt;br /&gt;&lt;br /&gt;

			La sintassi &amp;egrave;:&lt;br /&gt;

			&lt;pre&gt;
       $krypto-&gt;decrypt_file($name_encrypted_file,$name_decrypted_file)
			&lt;/pre&gt;

			Il file di input sar&amp;agrave; letto e decodificato, tramite la curva {F}, nel file di output.&lt;br /&gt;&lt;br /&gt;

&lt;!-- PAR E.4 --&gt;

			&lt;br /&gt;&lt;b style="color:#ff0000"&gt;e.4 Il metodo "encrypt_scalar"&lt;/b&gt;
			&lt;br /&gt;&lt;br /&gt;

			Il metodo encrypt_scalar cifra stringhe: il risultato dell'operazione di cifratura &amp;egrave; un vettore contenente il crittogramma.&lt;br /&gt;&lt;br /&gt;

			La sintassi &amp;egrave;:&lt;br /&gt;

			&lt;pre&gt;
           @encrypted_scalar=$krypto-&gt;encrypt_scalar($this_string)
			&lt;/pre&gt;

			Questo metodo &amp;egrave; particolarmente utile per il salvataggio delle password in un'applicazione. Come metodologia operativa, supponiamo di avere un database utenti di un'applicazione web. Salvando nel database le password criptate, l'eventuale violazione della tabella non porter&amp;agrave; alla violazione delle password. Il sistema, in fase di login utente, prender&amp;agrave; la password digitata e la cripter&amp;agrave;, mediante il metodo encrypt_scalar, verificando la corrispondenza con il valore criptato e non con quello in chiaro (che non sar&amp;agrave; stato salvato).&lt;br /&gt;&lt;br /&gt;

			Il programmatore che implementi un salvataggio password far&amp;agrave; bene a implementare quello che viene definito "salt", ovvero un "sale" per la password. Ricordo brevemente che il "salt" &amp;egrave; una stringa random che viene aggiunta al dato da criptare, in modo che un brute force a dizionario non produca risultati.&lt;br /&gt;&lt;br /&gt;

			Crypt::FNA non implementa, allo stato attuale, un metodo per decifrare gli scalari criptati poich&amp;eacute; ho ritenuto che la sola cifratura, per usi mirati al salvataggio password, fosse sufficiente. In ogni caso, con un piccolo artificio, &amp;egrave; possibile decifrare anche gli scalari utilizzando il metodo decrypt_file e scrivendo lo scalare in un file in memoria volatile (possiamo evitare di sollecitare il file system per questa operazione :)).&lt;br /&gt;&lt;br /&gt;

			Di sequito il codice (inserito nel file di test della lib):&lt;br /&gt;

			&lt;div style="overflow-x:auto"&gt;
				&lt;pre&gt;
# hack ricostruzione stringa
     my $stringa_in_chiaro='questa &amp;egrave; una prova';
     my @encrypted_scalar=$krypto-&gt;encrypt_scalar($stringa_in_chiaro);
     for(@encrypted_scalar) {print $_."\n"}
     # ricostruzione stringa
          my ($fh_testo_criptato,$file_criptato);
          open $fh_testo_criptato, '&gt;',\$file_criptato or die "err. scrittura file in memoria\n";
               for (@encrypted_scalar) {print $fh_testo_criptato $_."\n"}
          close $fh_testo_criptato;
          my ($fh_testo_decriptato,$stringa_decriptata);
          $krypto-&gt;decrypt_file(\$file_criptato,\$stringa_decriptata);
     # end ricostruzione stringa
# end hack
				&lt;/pre&gt;
			&lt;/div&gt;

			&lt;br /&gt;&lt;i&gt;$stringa_decriptata&lt;/i&gt; contiene il valore della stringa in chiaro.&lt;br /&gt;&lt;br /&gt;

&lt;!-- PAR E.5 --&gt;

			&lt;br /&gt;&lt;b style="color:#ff0000"&gt;e.5 Il metodo "make_fract"&lt;/b&gt;
			&lt;br /&gt;&lt;br /&gt;

			Questo metodo &amp;egrave; senz'altro il pi&amp;ugrave; suggestivo e permette di "toccare" le curve che verranno poi applicate negli algoritmi crittografici. Per il programmatore pu&amp;ograve; essere utile, nella propria applicazione, mostrare la curva, ad esempio in un ipotetico pannello di controllo per la gestione delle password o file criptati in attachment a moduli inviati per posta elettronica e salvati sul server.&lt;br /&gt;&lt;br /&gt;

			Il file grafico di output &amp;egrave; in formato PNG (Portable Network Graphic), fruibile da un qualunque browser come dai pi&amp;ugrave; diversi software di grafica.&lt;br /&gt;&lt;br /&gt;

			La sintassi &amp;egrave;:&lt;br /&gt;&lt;br /&gt;

			&lt;pre&gt;
			$krypto-&gt;make_fract($pngfile,$zoom)
			&lt;/pre&gt;

			&lt;ul&gt;
				&lt;li&gt;&lt;i&gt;$pngfile&lt;/i&gt; &amp;egrave; il nome del file png - senza estensione "png" che viene inserita automaticamente&lt;/li&gt;
				&lt;li&gt;&lt;i&gt;$zoom&lt;/i&gt; &amp;egrave; la scala del disegno - maggiore di zero. Valore di default: 1&lt;/li&gt;
				&lt;li&gt;L'immagine prodotta &amp;egrave; contenuta nel quadrato di lato square&lt;/li&gt;
			&lt;/ul&gt;

 &lt;!-- PAR F --&gt;

			&lt;br /&gt;&lt;br /&gt;&lt;b style="color:#ff0000"&gt;f. Il codice di esempio: fnatest.pl&lt;/b&gt;
			&lt;br /&gt;&lt;br /&gt;
			&lt;i&gt;(Per motivi di spazio ho rimosso l'hack per la ricostruzione stringa, gi&amp;agrave; illustrato nel par. e.4)&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;

			&lt;pre&gt;
# package: Anak Cryptography with Fractal Numeric Algorithm
# autore: Mario Rossano aka Anak
# www.netlogicalab.com, www.netlogica.it
# software@netlogicalab.com; software@netlogica.it
# FILE DI ESEMPIO

# caricamento moduli moduli
    use strict;
    use warnings;
    use Crypt::FNA;
# fine caricamento moduli

    # fractals examples
        #angle =&gt; [0,90,-60,-90,60]    # chiave
        #angle =&gt; [0,90,60,-90,120]    # scorpione
        #angle =&gt; [0,60,-60,0]         # von Koch
        #angle =&gt; [56,-187,215,64]     # nebulosa gassosa
        #angle =&gt; [66,-177,205,64]     # ramo sulla spiaggia
        #angle =&gt; [0,80,60,-90,120]    # maschera
   # end fractals examples

   # METODI

        # ISTANZA DI UN OGGETTO FNA
             my $krypto=FNA-&gt;new(
                  {
                       r=&gt; "6a",
                       angle =&gt;  [0,90,-60,-90,60],
                       square =&gt; 4096,
                       background =&gt; ["b",0,0],
                       foreground =&gt; ["a255",255,255],
                       magic =&gt; 2
                  }
             );
             my $krypto2=FNA-&gt;new();

        # GRAFICO DI UN FRATTALE
             $krypto-&gt;make_fract("fractal1","1a"); # nome file png e zoom
             $krypto2-&gt;make_fract("fractal2",1);   # nome file png e zoom

        # CIFRATURA DI FILE
             $krypto-&gt;encrypt_file("test.txt","test.fna");

        # DECIFRATURA DI FILE
             $krypto-&gt;decrypt_file("test.fna","test_rebuild.txt");

        # UNIONE DEI METODI (IPERCRITTOGRAFIA)
             $krypto-&gt;encrypt_file("test.txt","test2.fna");
                  $krypto2-&gt;encrypt_file("test2.fna","test3.fna");
                  $krypto2-&gt;decrypt_file("test3.fna","test2_rebuild.fna");
             $krypto-&gt;decrypt_file("test2_rebuild.fna","test3_rebuild.txt");

        # CIFRATURA DI STRINGHE
             my @encrypted_scalar=$krypto-&gt;encrypt_scalar("questa &amp;egrave; una prova");
             foreach my $encrypted_scalar(@encrypted_scalar) {
                  print $encrypted_scalar."\n"
             }

        # INTERCETTAZIONE ERRORI (SALVATI NEL VETTORE  $krypto-&gt;message)
             $krypto-&gt;make_fract("fractal1","3a"); # nome file png e zoom
             my @errors=@{$krypto-&gt;message};
                  foreach my $errors(@errors) {
                       print "&gt; 1-".$errors."\n"
             }
             @errors=@{$krypto2-&gt;message};
                  foreach my $errors(@errors) {
                       print "&gt; 2-".$errors."\n"
             }
exit
			&lt;/pre&gt;

			Sono volutamente riportati errori di inizializzazione nel file di test, per popolare il vettore @errors.
			&lt;br /&gt;&lt;br /&gt;

&lt;!-- PAR G --&gt;

			&lt;br /&gt;&lt;b style="color:#ff0000"&gt;g. Il codice del package FNA.pm&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;

			&lt;i&gt;"La filosofia &amp;egrave; scritta in questo grandissimo libro che continuamente ci sta aperto innanzi agli occhi, ma non si pu&amp;ograve; intendere se prima non s'impara a intender la lingua, e conoscere i caratteri, ne' quali &amp;egrave; scritto. Egli &amp;egrave; scritto in lingua matematica, e i caratteri son triangoli, cerchi, ed altre figure geometriche, senza i quali mezi &amp;egrave; impossibile a intenderne umanamente parola; senza questi &amp;egrave; un aggirarsi vanamente per un oscuro laberinto"&lt;/i&gt;
			&lt;p align="right"&gt;
				cos&amp;igrave; Galileo Galilei nel "Saggiatore"
			&lt;/p&gt;

			Il package nelle prime righe riporta le indicazioni di rito, con l'indicazione del titolo, autore e numero di versione.

			&lt;pre&gt;
# package: Anak Cryptography with Fractal Numeric Algorithm
# author: Mario Rossano aka Anak
# www.netlogicalab.com, www.netlogica.it
# software@netlogicalab.com, software@netlogica.it
# LIBRERIA

package FNA;

# caricamento lib
    use strict;
    use warnings;
    use Crypt::FNA::Validation;
# fine caricamento lib

our $VERSION = '0.01';
use constant pi =&gt; 3.141592;
			&lt;/pre&gt;

			Una piccola nota: il valore di &lt;i&gt;pi greco&lt;/i&gt; &amp;egrave; stato impostato come valore costante, approssimato indipendentemente dalla piattaforma utilizzata, poich&amp;eacute; viene utilizzato per il calcolo della curva su cui poggia il processo crittografico. E' necessario che il numero, fino all'ultimo decimale che si &amp;egrave; scelto di utilizzare, sia quindi sempre lo stesso, pena l'impossibilit&amp;agrave; di reversibilit&amp;agrave; dell'operazione crittografica.&lt;br /&gt;&lt;br /&gt;

			Di seguito il codice che implementa i metodi disponibili nella classe. Il primo &amp;egrave; "new", che serve a creare l'oggetto con cui si andr&amp;agrave; ad operare.  Vediamo che, dopo le chiamate per l'impostazione degli attributi cos&amp;igrave; come da script  parent (r, angle, square, background, foreground, magic), viene creato l'oggetto "$validate" come istanza di Crypt::FNA::Validation. Su $validate viene applicato il metodo "control_new_fna" (cui si passa l'oggetto $self, ovvero l'istanza di Crypt::FNA creata nel parent), in modo da verificare la coerenza di tutti i valori di inizializzazione. Vedremo in seguito qualche dettaglio su FNA::Validation. "control_new_fna" effettua la verifica dei valori, mediante regular expression come argomento di istruzioni condizionali e, in caso di assegnazione non coerente, come ad esempio potrebbe essere assegnare "-34" o "pippo" all'ordine della curva "r" (che invece &amp;egrave; un numero positivo), carica, se possibile, il valore di default del parametro, procedendo comunque con l'elaborazione.&lt;br /&gt;&lt;br /&gt;

			Vediamo che in caso di errore, dallo script parent &amp;egrave; accessibile il valore dell'attributo "message", un array contenente i codici restituiti da Crypt::FNA::Validation, ad uso del programmatore per una eventuale gestione.&lt;br /&gt;&lt;br /&gt;

			&lt;pre&gt;
# metodi ed attributi

sub new {
	my $class = shift;
	my $init  = shift;
	my $self={};

	bless $self,$class;

	$self-&gt;r($init-&gt;{r});
	$self-&gt;angle($init-&gt;{angle});
	$self-&gt;square($init-&gt;{square});
	$self-&gt;binary_mode($init-&gt;{binary_mode});
	$self-&gt;background($init-&gt;{background});
	$self-&gt;foreground($init-&gt;{foreground});
	$self-&gt;magic($init-&gt;{magic});
	$self-&gt;message($init-&gt;{message});

	my $validate=Crypt::FNA::Validation-&gt;new({intercept =&gt; $self});
	$validate-&gt;method_new_fna($self);

	return $self
}
			&lt;/pre&gt;

			Tralascio qui il codice degli &lt;i&gt;accessor&lt;/i&gt; in modo da riservare maggiore spazio ai metodi.&lt;br /&gt;&lt;br /&gt;

			La subroutine per la cifratura di un file &amp;egrave; quella riportata di seguito. Qui trovano compimento gli algoritmi descritti di calcolo della curva frattale unitamente a quello di crittografia.&lt;br /&gt;&lt;br /&gt;

			Oltre all'oggetto, sono passati al metodo il nome del file da criptare: &lt;i&gt;$name_plain_file&lt;/i&gt; ed il nome del file dove sar&amp;agrave; stampato il crittogramma: &lt;i&gt;$name_encrypted_file&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;

			La chiamata al metodo &lt;i&gt;init_geometry&lt;/i&gt; effettua le operazioni di calcolo delle coordinate di partenza per il tracciamento della curva e della lunghezza del segmento in relazione al quadrato contenitore.  Questo dato &amp;egrave; importante ai fini del processo di crittografia poich&amp;eacute;, come sopra riportato, verte sulla trasformazione del byte nel numero complesso delle coordinate del vertice &lt;i&gt;n-esimo&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;

			Al metodo &lt;i&gt;init_geometry&lt;/i&gt; viene passato, oltre l'oggetto, il parametro &lt;i&gt;$ro&lt;/i&gt; che, come sappiamo, &amp;egrave; la lunghezza del segmento di curva.&lt;br /&gt;&lt;br /&gt;
			&lt;i&gt;$ro&lt;/i&gt; viene assegnato mediante calcolo effettuato tramite applicazione del metodo set_starting_angle.
			&lt;i&gt;set_starting_angle&lt;/i&gt; restituisce, oltre che &lt;i&gt;$ro&lt;/i&gt;, anche &lt;i&gt;@initial_angle&lt;/i&gt; contenente gli angoli di inizializzazione convertiti in radianti (necessari come argomento alle funzioni seno e coseno).&lt;br /&gt;&lt;br /&gt;

			Si invoca il metodo &lt;i&gt;set_starting_angle&lt;/i&gt;, assegnando &lt;i&gt;$ro&lt;/i&gt; e &lt;/i&gt;@initial_angle&lt;/i&gt;  per poi passare ad init_geometry.&lt;br /&gt;&lt;br /&gt;

			Per rendere maggiormente complessa la crittoanalisi, &lt;i&gt;di&lt;/i&gt;, calcolato sulla base dell'attributo square , viene incrementato del &lt;i&gt;magic_number&lt;/i&gt;. Per analogo motivo, le coordinate iniziali per il tracciamento e calcolo sono rapportate al &lt;i&gt;magic_number&lt;/i&gt; che fa parte della chiave a pieno titolo, unitamente alla base &lt;i&gt;Ro&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;

			Sono poi inizializzate tre variabili locali: &lt;i&gt;$this_byte&lt;/i&gt;, &lt;i&gt;$byte_dec&lt;/i&gt; e &lt;i&gt;$byte_pos&lt;/i&gt;:&lt;br /&gt;
			&lt;ul&gt;
				&lt;li&gt;&lt;i&gt;$this_byte&lt;/i&gt; &amp;egrave; utilizzato nel ciclo di lettura del file da cifrare&lt;/li&gt;
				&lt;li&gt;&lt;i&gt;$byte_dec&lt;/i&gt; &amp;egrave; il valore decimale di &lt;i&gt;$this_byte&lt;/i&gt;&lt;/li&gt;
				&lt;li&gt;&lt;i&gt;$byte_pos&lt;/i&gt; &amp;egrave; la posizione di &lt;i&gt;$this_byte&lt;/i&gt; nel file da criptare&lt;/li&gt;
			&lt;/ul&gt;

			&lt;pre&gt;
sub encrypt_file {
    my $self=shift;
    my $name_plain_file=shift;
    my $name_encrypted_file=shift;

    (my $ro,my @initial_angle)=$self-&gt;set_starting_angle();
    (my $nx,my $ny,my $di)=$self-&gt;init_geometry($ro);

    $di+=$self-&gt;magic;
    $nx=$nx/$self-&gt;magic; # ascissa iniziale
    $ny=$ny/$self-&gt;magic; # ordinata iniziale;

    my ($this_byte,$byte_dec);
    my $byte_pos=0;

    my ($fh_plain,$fh_encrypted);
    open $fh_plain,'&lt;',$name_plain_file or do {
        push(@{$self-&gt;{message}},7);
        return
    };
        binmode $fh_plain;
        open $fh_encrypted,'&gt;',$name_encrypted_file or do {
            push(@{$self-&gt;{message}},8);
            return
        };
			&lt;/pre&gt;

			Qualora l'apertura del file di input e/o output non abbia successo, viene eseguito il codice alternativo (&lt;i&gt;or do&lt;/i&gt;) per cui il contenitore dei codici di errore, il valore dell'attributo &lt;i&gt;message&lt;/i&gt;, viene aggiornato e l'elaborazione attinente l'apertura non viene eseguita.&lt;br /&gt;&lt;br /&gt;

			Definiti quindi gli attori della sub, inizia l'iterazione, mediante ciclo &lt;i&gt;while&lt;/i&gt; dal primo byte all'ultimo, byte a byte.&lt;br /&gt;&lt;br /&gt;

			Dopo aver letto (&lt;i&gt;read&lt;/i&gt;) il byte corrente ed assegnatone il valore decimale alla variabile &lt;i&gt;$byte_dec&lt;/i&gt;, si aggiunge a questo il valore definito dal &lt;i&gt;magic_number&lt;/i&gt; per un motivo che sar&amp;agrave; chiaro tra poco...&lt;br /&gt;&lt;br /&gt;

			Con la chiamata alla funzione successiva, &lt;i&gt;crypt_fract&lt;/i&gt;, non facciamo altro che seguire la curva frattale, partendo dal vertice successivo all'ultimo processato e saltando un numero di vertici pari al valore del byte aumentato del &lt;i&gt;magic number&lt;/i&gt;. Le coordinate di questo vertice sono il crittogramma di quel ben preciso byte.&lt;br /&gt;&lt;br /&gt;

			I crittogrammi sono riportati, man mano che vengono assegnati, nel file &lt;i&gt;$fh_encrypted&lt;/i&gt;: una riga per ogni singola coordinata in modo da avere, alla fine del processo, una sequenza di numeri incolonnati.&lt;br /&gt;&lt;br /&gt;

			&lt;div style="overflow-x:auto"&gt;
				&lt;pre&gt;
        while (!eof($fh_plain)) {
            read($fh_plain,$this_byte,1);

            $byte_dec=unpack('C',$this_byte);
            $byte_dec+=$self-&gt;magic+1;

            ($nx,$ny,$byte_pos)=$self-&gt;crypt_fract($ro,1,$di,$nx,$ny,$byte_dec,$byte_pos);
            print $fh_encrypted $nx."\n".$ny."\n"
        }
        close ($fh_encrypted);
    close ($fh_plain);
    @{$self-&gt;angle}=@initial_angle
}
				&lt;/pre&gt;
			&lt;/div&gt;

			L'ultima operazione &amp;egrave; la riassegnazione all'oggetto degli angoli di inizializzazione nel sistema sessadecimale. Questo &amp;egrave; necessario poich&amp;eacute; il vettore, durante l'applicazione del metodo, &amp;egrave; stato popolato con gli angoli di inclinazione per il tracciamento, tutti espressi in radianti e la mancata riassegnazione produrrebbe un comportamento anomalo da parte degli altri metodi, eventualmente invocati da parte dello script parent.&lt;br /&gt;&lt;br /&gt;

			La subroutine successiva, &lt;i&gt;encrypt_scalar&lt;/i&gt;, effettua la stessa operazione della subroutine &lt;i&gt;encrypt_file&lt;/i&gt;, restituendo in uscita un array (e non un file) che &amp;egrave; il crittogramma del testo. Abbiamo quindi:

			&lt;ul&gt;
				&lt;li&gt;in luogo del &lt;i&gt;READ&lt;/i&gt;, un &lt;i&gt;SUBSTRing&lt;/i&gt; per la lettura del singolo carattere&lt;/li&gt;
				&lt;li&gt;un ciclo sulla lunghezza della stringa, anzich&amp;eacute; sulla fine del file&lt;/li&gt;
				&lt;li&gt;un push nell'array &lt;i&gt;@encrypted&lt;/i&gt; contenente le coordinate del vertice calcolato (restituito allo script parent a fine ciclo insieme a tutti gli altri) in luogo del print nel file criptato&lt;/li&gt;
			&lt;/ul&gt;

			Le chiamate alla &lt;i&gt;init_geometry&lt;/i&gt; e &lt;i&gt;set_starting_angle&lt;/i&gt;  effettuano, chiaramente, le identiche operazioni di calcolo in modo da avere le coordinate iniziali per il calcolo/tracciamento e la lunghezza del segmento di curva.&lt;br /&gt;&lt;br /&gt;

			Come nel caso della subroutine &lt;i&gt;encrypt_file&lt;/i&gt;, un'ulteriore complicazione per i crittoanalisti eventualmente impegnati a decrittare le informazioni, &amp;egrave; che la lunghezza del segmento &lt;i&gt;di&lt;/i&gt; viene incrementata del valore del &lt;i&gt;magic number&lt;/i&gt;. Inoltre le coordinate iniziali per il tracciamento della curva vengono anch'esse legate al &lt;i&gt;magic number&lt;/i&gt;.

			&lt;div style="overflow-x:auto"&gt;
				&lt;pre&gt;
sub encrypt_scalar {
    my $self=shift;
    my $string=shift;

    (my $ro,my @initial_angle)=$self-&gt;set_starting_angle();
    (my $nx,my $ny,my $di)=$self-&gt;init_geometry($ro);

    # incremento del magic_number in modo da rendere maggiormente complessa
    # l'individuazione della parte di chiave "di" alla crittoanalisi
    $di+=$self-&gt;magic;
    $nx=$nx/$self-&gt;magic; # ascissa iniziale
    $ny=$ny/$self-&gt;magic; # ordinata iniziale;

    my $char_code;
    my $char_pos=0;
    my @encrypted;

    for (split(//,$string)) {
        $char_code=unpack('C',$_);
        $char_code+=$self-&gt;magic+1; # maschero il codice carattere

        # chiamata ricorsiva
        ($nx,$ny,$char_pos)=$self-&gt;crypt_fract($ro,1,$di,$nx,$ny,$char_code,$char_pos);
        push(@encrypted,($nx,$ny))
    }
    @{$self-&gt;angle}=@initial_angle;
    return (@encrypted)
}
				&lt;/pre&gt;
			&lt;/div&gt;

			La subroutine &lt;i&gt;decrypt_file&lt;/i&gt; fa esattamente cosa ci si aspetta: ricostruisce il file originale del crittogramma.&lt;br /&gt;&lt;br /&gt;

			Vediamo quali variabili sono coinvolte nel processo:

			&lt;ul&gt;
				&lt;li&gt;il primo parametro &amp;egrave;, come sempre, l'oggetto cui afferisce la particolare istanza nello script parent&lt;/li&gt;
				&lt;li&gt;il successivo &amp;egrave; il nome del file criptato: &lt;i&gt;$name_encrypted_file&lt;/i&gt;&lt;/li&gt;
				&lt;li&gt;infine vi &amp;egrave; l'impostazione del filename che conterr&amp;agrave; la ricostruzione del file originale: &lt;i&gt;$name_decrypted_file&lt;/i&gt;&lt;/li&gt;
			&lt;/ul&gt;

			Effettuate le chiamate alle ormai note subroutines &lt;i&gt;init_geometry&lt;/i&gt;  e &lt;i&gt;set_starting_angle&lt;/i&gt;,  vengono inizializzate le altre variabili locali che corrispondono alle omonime delle subroutines &lt;i&gt;encrypt_file&lt;/i&gt; ed &lt;i&gt;encrypt_scalar&lt;/i&gt;, utilizzate nel processo di percorso sulla curva e calcolo delle coordinate dei vertici successivi.&lt;br /&gt;&lt;br /&gt;

			Come nelle subroutine &lt;i&gt;encrypt_file&lt;/i&gt; ed &lt;i&gt;encrypt_scalar&lt;/i&gt;, per ovvi motivi di reversibilit&amp;agrave;, la lunghezza del segmento &lt;i&gt;di&lt;/i&gt; viene incrementata del valore del &lt;i&gt;magic number&lt;/i&gt;. Inoltre le coordinate iniziali per il tracciamento della curva vengono anch'esse legate al &lt;i&gt;magic number&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;

			Per ricostruire il file originale, si scandisce il file criptato, leggendo le coordinate l&amp;igrave; salvate, quindi si segue la curva {F} calcolando le coordinate cartesiane dei vertici, verificando, nel contempo, l'uguaglianza con le coordinate lette dal crittogramma.  Abbiamo quindi due cicli annidati: uno esterno sul crittogramma ed uno interno sulla curva. Nel ciclo esterno leggiamo due righe alla volta poich&amp;eacute; nel file criptato le coordinate dei vertici occupano ognuna una riga (quindi leggiamo ascissa ed ordinata). Nel ciclo interno, una volta verificata l'uguaglianza delle coordinate del vertice processato con quelle del crittogramma, il valore del byte corrisponder&amp;agrave; al numero di vertici processati, rispetto all'ultima uguaglianza, diminuito del magic number (&lt;i&gt;$self-&gt;magic&lt;/i&gt;) e diminuito dell'unit&amp;agrave; (poich&amp;eacute; quando si cripta, si riparte sempre dal vertice successivo): &lt;i&gt;$this_byte_dec=$this_vertex-$from_vertex-1-$self-&gt;magic&lt;/i&gt;. Come si evince, &lt;i&gt;$from_vertex&lt;/i&gt; &amp;egrave; il vertice corrispondente alle ultime coordinate trovate.&lt;br /&gt;&lt;br /&gt;

			Tanto premesso, le variabili (locali) coinvolte sono:

			&lt;ul&gt;
				&lt;li&gt;&lt;i&gt;$from_vertex&lt;/i&gt;  contiene il valore del posizionale dell'ultimo vertice processato per il quale si &amp;egrave; verificata un'uguaglianza&lt;/li&gt;
				&lt;li&gt;&lt;i&gt;$vertex&lt;/i&gt; &amp;egrave; il contatore del ciclo interno, punto di partenza per il calcolo delle coordinate dei vertici di rispetto all'ultima uguaglianza trovata {F}&lt;/li&gt;
				&lt;li&gt;&lt;i&gt;$this_vertex&lt;/i&gt; &amp;egrave; il posizionale del vertice di {F} di cui si sono calcolate le coordinate da verificare per l'uguaglianza&lt;/li&gt;
				&lt;li&gt;&lt;i&gt;$this_byte_dec&lt;/i&gt;  il valore del byte nel sistema decimale, calcolato come differenza del posizionale del vertice di {F} valutato attualmente, rispetto all'ultimo posizionale per cui ci sia stata uguaglianza di coordinate tra crittogramma e coordinate del vertice della curva&lt;/li&gt;
				&lt;li&gt;&lt;i&gt;$this_byte&lt;/i&gt;  &amp;egrave; il valore del byte da scrivere nel file originale&lt;/li&gt;
				&lt;li&gt;&lt;i&gt;$x_coord&lt;/i&gt; &amp;egrave; l'ascissa del vertice della curva {F}&lt;/li&gt;
				&lt;li&gt;&lt;i&gt;$y_coord&lt;/i&gt; &amp;egrave; l'ordinata del vertice della curva {F}&lt;/li&gt;
			&lt;/ul&gt;

			Una volta verificata l'uguaglianza e calcolato il valore del byte, lo si scrive nel file di output &lt;i&gt;$fh_decrypted&lt;/i&gt; dopo aver salvato in &lt;i&gt;$from_vertex&lt;/i&gt; il valore di &lt;i&gt;$this_vertex&lt;/i&gt;, come sopra indicato.&lt;br /&gt;&lt;br /&gt;

			In caso di errore in apertura dei files coinvolti, come nel caso del metodo &lt;i&gt;encrypt_file&lt;/i&gt;, verr&amp;agrave; inserito in coda all'array &lt;i&gt;$self-&gt;message&lt;/i&gt;  il codice di errore riscontrato.

			&lt;div style="overflow-x:auto"&gt;
				&lt;pre&gt;
sub decrypt_file {
    my $self=shift;
    my $encrypted_filename=shift;
    my $decrypted_filename=shift;

    (my $ro,my @initial_angle)=$self-&gt;set_starting_angle();
    (my $nx,my $ny,my $di)=$self-&gt;init_geometry($ro);

    # incremento del magic_number in modo da rendere complessa la crittoanalisi
    # basandosi sulla lunghezza di
    $di+=$self-&gt;magic;
    $nx=$nx/$self-&gt;magic; # ascissa iniziale
    $ny=$ny/$self-&gt;magic; # ordinata iniziale;

    my $from_vertex=0;
    my ($this_byte,$this_byte_dec,$this_vertex,$x_coord,$y_coord);

    my ($fh_encrypted,$fh_decrypted);
    open $fh_encrypted,'&lt;',$encrypted_filename or do {
        push(@{$self-&gt;{message}},9);
        return
    };
        open $fh_decrypted,'&gt;',$decrypted_filename or do {
            push(@{$self-&gt;{message}},10);
            return
        };
            binmode $fh_decrypted;

             while (!eof($fh_encrypted)) {
                $x_coord=&lt;$fh_encrypted&gt;;$y_coord=&lt;$fh_encrypted&gt;;
                chop($x_coord,$y_coord);
                # ho usato chop perch&amp;egrave; l'ultimo carattere &amp;egrave; certamente \n e chop &amp;egrave; pi&amp;ugrave; veloce di chomp

                for (my $vertex=$from_vertex;$vertex&lt;256+$from_vertex+$self-&gt;magic+1;$vertex++){
                    ($nx,$ny,$this_vertex)=$self-&gt;crypt_fract($ro,1,$di,$nx,$ny,1,$vertex);
                    if ($nx eq $x_coord &amp;&amp; $ny eq $y_coord) {
                        # qui ricavo il byte come posizione rispetto
                        # alla posizione trovata precedentemente
                        $this_byte_dec =$this_vertex-$from_vertex-$self-&gt;magic-1;

                        $this_byte=pack('C',$this_byte_dec);
                        print $fh_decrypted $this_byte;

                        #imposto il from per ripartire il ciclo for dal punto giusto alla
                        # prossima iterazione del while, quando ripartir&amp;agrave; il for

                        $from_vertex=$this_vertex;
                        last
                    }
                } # fine for
            } # fine ciclo while
        close $fh_decrypted;
    close $fh_encrypted;
    @{$self-&gt;angle}=@initial_angle
}
				&lt;/pre&gt;
			&lt;/div&gt;

			Il metodo seguente, &lt;i&gt;make_fract&lt;/i&gt;, non &amp;egrave; strutturale alle funzionalit&amp;agrave; crittografiche ma non potevo esimermi dal realizzarlo, poich&amp;eacute; &amp;egrave; dal desiderio di ottenere il grafico di queste bellissime curve che &amp;egrave; nata la sfida e l'algoritmo. Tramite &lt;i&gt;make_fract&lt;/i&gt; si stampa il grafico di {F} in un file PNG (Portable Network Graphics), formato fruibile da tutti i browser (non testuali) e dai pi&amp;ugrave; disparati software di grafica nei diversi sistemi operativi.&lt;br /&gt;&lt;br /&gt;

			Qualora dallo script parent non venga invocato questo metodo, non sar&amp;agrave; necessario caricare &lt;i&gt;GD::Simple&lt;/i&gt; (ed implicitamente &lt;i&gt;GD&lt;/i&gt;), quindi, per fruire delle funzionalit&amp;agrave; crittografiche, &lt;i&gt;Crypt::FNA&lt;/i&gt; non ha dipendenze: &amp;egrave; eseguibile anche su macchine dotate del solo interprete/compilatore Perl.&lt;br /&gt;&lt;br /&gt;

			Le prime operazioni effettuate sono, come sempre, la lettura dei parametri, nella fattispecie: l'oggetto (&lt;i&gt;$self&lt;/i&gt;), il nome del file di output (&lt;i&gt;$png_filename&lt;/i&gt; nome del PNG destinatario del grafico di {F} di ordine &lt;i&gt;n&lt;/i&gt;) ed infine il fattore di &lt;i&gt;zoom&lt;/i&gt; della curva.&lt;br /&gt;&lt;br /&gt;

			Una volta completata la prima serie di istruzioni, viene impostato l'oggetto e la geometria iniziale di disegno (&lt;i&gt;init_geometry&lt;/i&gt; e &lt;i&gt;set_starting_angle&lt;/i&gt; ormai ben noti).&lt;br /&gt;&lt;br /&gt;

			Si controlla quindi la presenza della libreria &lt;i&gt;GD::Simple&lt;/i&gt; nel calcolatore in uso, mediante &lt;i&gt;eval&lt;/i&gt; che viene poi verificata tramite l'istruzione condizionale &lt;i&gt;if&lt;/i&gt; che, in caso di errore di caricamento, provvede a inserire in &lt;i&gt;$self-&gt;message&lt;/i&gt; il codice di errore e a tornare allo script parent, consentendo il prosieguo dell'elaborazione residua.&lt;br /&gt;&lt;br /&gt;

			Un'ulteriore verifica &amp;egrave; quella sul fattore di &lt;i&gt;zoom&lt;/i&gt;: nel caso in cui il valore sia non congruo (diverso da un numero positivo), viene assegnato il valore di default  dalla classe &lt;i&gt;Crypt::FNA::Validation&lt;/i&gt;. Per fare questo si istanzia &lt;i&gt;$validate&lt;/i&gt; come oggetto &lt;i&gt;Crypt::FNA::Validation&lt;/i&gt; e impostando, tramite il suo metodo &lt;i&gt;new&lt;/i&gt;, nell'attributo &lt;i&gt;intercept&lt;/i&gt;, il fattore di &lt;i&gt;zoom&lt;/i&gt; passato dallo script parent. Una descrizione della classe &lt;i&gt;Crypt::FNA::Validation&lt;/i&gt; esula dai limiti imposti all'articolo ma nulla vieta al lettore di aprire il source code :)

			&lt;pre&gt;
sub make_fract {
    my $self=shift;
    my $png_filename=shift;
    my $zoom=shift;

    # assegno coordinate iniziali del calcolo.
    # init_geometry usa set_starting_angle perch&amp;egrave; "ro" e "angle"
    # iniziali vengono fuori da l&amp;igrave;
    # posso quindi passarli direttamente, risparmiando un passaggio

    (my $ro,my @initial_angle)=$self-&gt;set_starting_angle();
    (my $nx,my $ny,my $di)=$self-&gt;init_geometry($ro);

    my $load_this_package=eval("require GD::Simple;");
    $load_this_package.='';
    if ($load_this_package eq '') {
        push(@{$self-&gt;{message}},16);
        return
    }

    #controllo zoom, solo valori numerici e &gt; 0
      my $validate=Crypt::FNA::Validation-&gt;new({intercept =&gt; [$zoom,$self]});
      ($zoom,@{$self-&gt;message})=$validate-&gt;param_zoom_fna($self);
    #fine controllo zoom
			&lt;/pre&gt;

			Tramite il metodo new di &lt;i&gt;GD::Simple&lt;/i&gt;, viene creata l'istanza &lt;i&gt;$img&lt;/i&gt;.&lt;br /&gt;
			L'immagine, contenuta in un quadrato di lato &lt;i&gt;$self-&gt;square&lt;/i&gt;, &amp;egrave; il nostro foglio da disegno.&lt;br /&gt;
			Vengono inoltre impostati i colori di &lt;i&gt;background&lt;/i&gt; e &lt;i&gt;foreground&lt;/i&gt;, cos&amp;igrave; come stabilito nell'istanza dell'oggetto &lt;i&gt;Crypt::FNA&lt;/i&gt; nello script parent.&lt;br /&gt;&lt;br /&gt;

			In un ciclo &lt;i&gt;for&lt;/i&gt; sul numero degli angoli, vengono quindi calcolate le coordinate di ogni singolo vertice della curva, in modo tale che, tramite il metodo &lt;i&gt;lineTo&lt;/i&gt; di &lt;i&gt;GD::Simple&lt;/i&gt;, sar&amp;agrave; possibile tracciarla.&lt;br /&gt;&lt;br /&gt;

			Gli angoli sono in numero uguale al numero dei parametri genitore della curva, elevato all'ordine desiderato: maggiore &amp;egrave; l'ordine, maggiore sar&amp;agrave; l'accuratezza del grafico del frattale.&lt;br /&gt;&lt;br /&gt;

			Questi sono calcolati mediante la function &lt;i&gt;evaluate_this_angle&lt;/i&gt;, popolando man mano il vettore &lt;i&gt;$self-&gt;angle&lt;/i&gt; e poi utilizzati per il disegno calcolando, in cascata, le coordinate dei vertici successivi. A questo metodo  vengono passati l'indice &lt;i&gt;$k&lt;/i&gt; corrispondente all'indice del vettore &lt;i&gt;$self-&gt;angle&lt;/i&gt; da popolare in quel ciclo ed il numero di angoli base del frattale, &lt;i&gt;$ro&lt;/i&gt;. Il metodo restituisce il valore dell'angolo &lt;i&gt;k-esimo&lt;/i&gt; che va a popolare l'elemento di eguale indice del vettore &lt;i&gt;$self-&gt;angle&lt;/i&gt;.&lt;br /&gt;
			Inserito il valore dell'angolo nel vettore, viene passato l'indice &lt;i&gt;$k&lt;/i&gt; al metodo &lt;i&gt;evaluate_this_coords&lt;/i&gt; che restituisce le coordinate del prossimo punto della curva, unitamente al fattore di zoom (&lt;i&gt;$zoom&lt;/i&gt;), alle coordinate dell'ultimo vertice processato (&lt;i&gt;$nx,$ny&lt;/i&gt;) e alla lunghezza del segmento di curva (&lt;i&gt;$di&lt;/i&gt;).&lt;br /&gt;
			Calcolate le coordinate, queste vengono passate al metodo &lt;i&gt;lineTo&lt;/i&gt; di &lt;i&gt;GD::Simple&lt;/i&gt; per il tracciamento.&lt;br /&gt;&lt;br /&gt;

			Le successive istruzioni, si occupano di tracciare il disegno di {F} nel file PNG. Tra i parametri passati ci sono infatti il nomefile: &lt;i&gt;$png_filename&lt;/i&gt; (l'estensione ".png" &amp;egrave; automaticamente inserita in fase di salvataggio) ed il fattore di zoom: &lt;i&gt;$zoom&lt;/i&gt; gi&amp;agrave; verificato.&lt;br /&gt;&lt;br /&gt;

			Una volta completato il ciclo, si salva l'elaborazione nel file grafico.&lt;br /&gt;
			Come in altre occasioni, qualora non sia possibile aprire il file in scrittura, viene aggiornato il contenuto di &lt;i&gt;$self-&gt;message&lt;/i&gt;.
			In caso affermativo viene salvato il file png per gli usi previsti dallo script parent.

			&lt;pre&gt;
    my $img = GD::Simple-&gt;new($self-&gt;square,$self-&gt;square);
        $img-&gt;fgcolor(@{$self-&gt;background});              # foreground
        $img-&gt;bgcolor(@{$self-&gt;background});              # background
        $img-&gt;rectangle(0,0,$self-&gt;square,$self-&gt;square); # campisce il quadrato
        $img-&gt;fgcolor(@{$self-&gt;foreground});              # foreground

    $img-&gt;move($nx,$ny);

    for (my $k=0;$k&lt;$ro**($self-&gt;r);$k++) {
        ${$self-&gt;angle}[$k]=$self-&gt;evaluate_this_angle($k,$ro) if $k&gt;=$ro;
        ($nx,$ny)=$self-&gt;evaluate_this_coords($k,$zoom,$nx,$ny,$di);
        $img-&gt;lineTo($nx,$ny)
    }

    my $fh_pngfile;
    open $fh_pngfile,'&gt;',$png_filename.'.png' or do {
        push(@{$self-&gt;{message}},11);
        return
    };
        binmode $fh_pngfile;
        print $fh_pngfile $img-&gt;png;
    close $fh_pngfile;
    @{$self-&gt;angle}=@initial_angle
}
			&lt;/pre&gt;

			Abbiamo fin qui esaminato i metodi principali della classe &lt;i&gt;Crypt::FNA&lt;/i&gt;, vediamo ora quelli di "di servizio".&lt;br /&gt;&lt;br /&gt;

			Il primo che incontriamo &amp;egrave; &lt;i&gt;set_starting_angle&lt;/i&gt; che, come gi&amp;agrave; brevemente indicato, converte nel sistema radiante gli angoli passati dallo script parent, in fase di inizializzazione dell'oggetto (metodo &lt;i&gt;new&lt;/i&gt;). Oltre a questo il metodo restituisce il numero di angoli base della curva {F}, &lt;i&gt;$ro&lt;/i&gt;, dato necessario al calcolo che diversamente si perderebbe durante la popolazione di &lt;i&gt;$self-&gt;angle&lt;/i&gt; oltre al vettore &lt;i&gt;@initial_angle&lt;/i&gt; che re-inizializza &lt;i&gt;$self-&gt;angle&lt;/i&gt; a fine elaborazione.

			&lt;pre&gt;
sub set_starting_angle {
    my $self=shift;
    my $ro=scalar(@{$self-&gt;angle});

    my @initial_angle;

    #conversione in radianti
    for (my $k=0;$k&lt;$ro;$k++) {
        push(@initial_angle,${$self-&gt;angle}[$k]);
        ${$self-&gt;angle}[$k]=${$self-&gt;angle}[$k]*pi/180
    }
    return ($ro,@initial_angle)
}
			&lt;/pre&gt;

			Incontriamo poi il metodo &lt;i&gt;init_geometry&lt;/i&gt; che calcola la lunghezza del lato &lt;i&gt;di&lt;/i&gt; della curva {F}. Questa distanza &amp;egrave; utilizzata sia nei processi di crittografia (&lt;i&gt;encrypt_file&lt;/i&gt; ed &lt;i&gt;encrypt_scalar&lt;/i&gt;) che di ricostruzione del dato (&lt;i&gt;decrypt_file&lt;/i&gt;), come pure dal metodo di disegno (&lt;i&gt;make_fract&lt;/i&gt;). Il lato della curva, inteso anche come distanza percorsa dalla tartaruga in fase di disegno (il turtle graphics), &amp;egrave; un dato fondamentale e strutturale, poich&amp;eacute; influenza direttamente le coordinate dei vertici utilizzate dai vari metodi della classe FNA.&lt;br /&gt;
			Osserviamo come il valore di sia funzione dell'ampiezza del quadrato contenitore (di lato &lt;i&gt;$self-&gt;square&lt;/i&gt;), del numero di parametri (angoli) genitori della curva (&lt;i&gt;$ro&lt;/i&gt;) e dell'ordine (profondit&amp;agrave; di calcolo) della stessa (&lt;i&gt;$self-&gt;r&lt;/i&gt;). Dopo il calcolo di &lt;i&gt;di&lt;/i&gt; (&lt;i&gt;$di&lt;/i&gt;) viene effettuata una verifica, implementata mediante ciclo &lt;i&gt;while&lt;/i&gt;: se &lt;i&gt;di&lt;/i&gt; risulta essere inferiore all'intero "5", &lt;i&gt;di&lt;/i&gt; viene incrementato moltiplicandolo per s&amp;eacute; stesso aumentato dell'unit&amp;agrave;. Si aggiunge 1 prima del prodotto (che diversamente consisterebbe in un'elevazione al quadrato di &lt;i&gt;di&lt;/i&gt;) poich&amp;eacute; se &lt;i&gt;di&lt;/i&gt; fosse inferiore od uguale ad 1, lo script entrerebbe in un loop infinito.
			Una volta impostato il valore di, vengono fissate le coordinate di partenza per il disegno/calcolo della curva, ponendo l'origine al centro del quadrato contenitore. Questi valori vengono restituiti al metodo invocante.
			&lt;pre&gt;
sub init_geometry {
    my $self=shift;
    my $ro=shift;

    my $di=int(($self-&gt;square/$ro**$self-&gt;r)*10000)/5000;
    while ($di&lt;5) {
        $di=$di*(1+$di)
    }
    my $nx=$self-&gt;square/2; # ascissa iniziale
    my $ny=$self-&gt;square/2; # ordinata iniziale
    return ($nx,$ny,$di)
}
			&lt;/pre&gt;

			Arriviamo quindi ad uno dei metodi di servizio pi&amp;ugrave; importanti del package: &lt;i&gt;crypt_fract&lt;/i&gt; che viene invocato da tutti i metodi (escluso &lt;i&gt;new&lt;/i&gt;) e chiama il fondamentale &lt;i&gt;evaluate_this_angle&lt;/i&gt; come pure &lt;i&gt;evaluate_this_coords&lt;/i&gt;, per il calcolo degli angoli della curva e coordinate dei relativi vertici. E' un vero e proprio anello di giunzione nel processo ricorsivo.&lt;br /&gt;&lt;br /&gt;

			Tra i parametri passati al metodo (oltre allo "starting"  - &lt;i&gt;ro, zoom, di, nx, ny&lt;/i&gt; con i significati ormai noti) ci sono &lt;/i&gt;$value_dec&lt;/i&gt; e &lt;i&gt;$pos&lt;/i&gt;: questi sono il valore decimale del byte (o l'ordinale del carattere) da crittografare e il vertice della curva da cui partire per il calcolo. Vengono restituiti al metodo invocante:
			&lt;ul&gt;
				&lt;li&gt;le coordinate del vertice corrispondente al byte o carattere (come gi&amp;agrave; indicato, vengono "saltati" un numero di vertici pari al valore del byte o all'ordinale del carattere oltre ad un altro vertice pi&amp;ugrave; un numero di ulteriori vertici pari al &lt;i&gt;magic number&lt;/i&gt;)&lt;/li&gt;
				&lt;li&gt;il vertice da cui ripartire per la successiva operazione di cifratura o decifratura, pari chiaramente al valore del &lt;i&gt;$pos&lt;/i&gt; di ingresso e del "salto" effettuato lungo la curva {F}&lt;/li&gt;
			&lt;/ul&gt;

			Vedremo subito dopo la descrizione puntuale di &lt;i&gt;evaluate_this_angle&lt;/i&gt; ed &lt;i&gt;evaluate_this_coords&lt;/i&gt;.

			&lt;pre&gt;
sub crypt_fract {
    my $self=shift;
    my $ro=shift;
    my $zoom=shift;
    my $di=shift;
    my $nx=shift;
    my $ny=shift;
    my $value_dec=shift;
    my $pos=shift;

    for (my $k=$ pos;$k&lt;($pos+$value_dec);$k++) {
        ${$self-&gt;angle}[$k]=$self-&gt;evaluate_this_angle($k,$ro) if $k&gt;=$ro;
        ($nx,$ny)=$self-&gt;evaluate_this_coords($k,$zoom,$nx,$ny,$di)
    }
    return($nx,$ny,$pos+$value_dec)
}
			&lt;/pre&gt;


			Giungiamo infine al fondamentale metodo &lt;i&gt;evaluate_this_angle&lt;/i&gt;, il cui cuore, la relazione:&lt;br /&gt;

			&lt;p align="center"&gt;
				$angle[$k]=$angle[int($k/$ro)]+$angle[$k-$ro*int($k/$ro)]
			&lt;/p&gt;

			&amp;egrave; ben descritta nel paragrafo b.&lt;br /&gt;&lt;br /&gt;

			Il parametro fondamentale passato al metodo &amp;egrave; l'indice &lt;i&gt;$k&lt;/i&gt;, riferito al vettore &lt;i&gt;$self-&gt;angle&lt;/i&gt;, in cui verr&amp;agrave; inserito il valore dell'angolo &lt;i&gt;k-esimo&lt;/i&gt;. Il calcolo &amp;egrave; basato inizialmente sui parametri genitore (gli &lt;i&gt;angle&lt;/i&gt; impostati nel metodo &lt;i&gt;new&lt;/i&gt;) e l'indice della curva (&lt;i&gt;r&lt;/i&gt; impostato nello stesso metodo &lt;i&gt;new&lt;/i&gt;) su cui poi si va ad iterare.&lt;br /&gt;
			&lt;i&gt;g&lt;/i&gt; ed &lt;i&gt;p&lt;/i&gt; sono le funzioni &lt;i&gt;G(k)&lt;/i&gt; e &lt;i&gt;P(k)&lt;/i&gt; pure descritte al paragrafo b.

			&lt;pre&gt;
# calcolo direzione segmento e coordinate del vertice finale corrispondente

    sub evaluate_this_angle {
        my $self=shift;
        my $k=shift;
        my $ro=shift;

        return ${$self-&gt;angle}[g($k,$ro)]+${$self-&gt;angle}[p($k,$ro)]
    }

    sub g {
        my $k=shift;
        my $ro=shift;

        my $n=int($k/$ro);
        return $n
    }

    sub p {
        my $k=shift;
        my $ro=shift;

        my $n=$k-$ro*g($k,$ro);
        return $n
    }
			&lt;/pre&gt;

			&lt;i&gt;evaluate_this_coords&lt;/i&gt; calcola le coordinate del vertice &lt;i&gt;k-esimo&lt;/i&gt; della curva e le restituisce al metodo chiamante. Le coordinate sono utilizzate per il disegno (metodo &lt;i&gt;make_fract&lt;/i&gt;) oppure per le funzionalit&amp;agrave; crittografiche (metodi &lt;i&gt;encrypt_file&lt;/i&gt;, &lt;i&gt;decrypt_file&lt;/i&gt;, &lt;i&gt;encrypt_scalar&lt;/i&gt;).&lt;br /&gt;
			I parametri passati alla function sono l'indice dell'angolo nel vettore &lt;i&gt;$self-&gt;angle($k)&lt;/i&gt; ed il fattore di &lt;i&gt;zoom&lt;/i&gt;.&lt;br /&gt;
			Il calcolo delle coordinate viene effettuato tramite le precedenti e spostandosi sul successivo vertice, considerando il lato della curva come l'ipotenusa del triangolo rettangolo che ha come estremi i due vertici della curva. Applicando le note propriet&amp;agrave; di seno e coseno, siamo in grado di calcolare facilmente le nuove coordinate.&lt;br /&gt;
			Per rendere cross-platform il software e rendere agevoli le operazioni di crittografia, si &amp;egrave; scelto di approssimare per difetto ad 8 decimali il calcolo delle coordinate.

			&lt;pre&gt;
sub evaluate_this_coords {
    my $self=shift;
    my $k=shift;
    my $zoom=shift;
    my $nx=shift;
    my $ny=shift;
    my $di=shift;

    if (!$zoom) {$zoom=1};
    $nx=int(10**8*($nx-$di*$zoom*cos(${$self-&gt;angle}[$k])))/10**8;
    $ny=int(10**8*($ny-$di*$zoom*sin(${$self-&gt;angle}[$k])))/10**8;

    return ($nx,$ny)
}
			&lt;/pre&gt;

			Completa Crypt::FNA la classe &lt;i&gt;Crypt::FNA::Validation&lt;/i&gt;, i cui metodi implementano i controlli di coerenza nei dati di inizializzazione e del fattore di zoom oltre all'aggiornamento del contenitore dei codici di errore restituiti nell'array &lt;i&gt;$self-&gt;message&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ArticoliPerlIt?a=D3qOjn1GUVY:NIfDtliGjx4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ArticoliPerlIt?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ArticoliPerlIt?a=D3qOjn1GUVY:NIfDtliGjx4:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ArticoliPerlIt?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
<dc:subject>article</dc:subject>
<dc:creator>dakkar</dc:creator>
<dc:date>2010-04-07T23:35:30+02:00</dc:date>
</item>

<item rdf:about="http://www.perl.it/documenti/articoli/2010/03/async-howto.html">
<title>Async Howto</title>
<link>http://www.perl.it/documenti/articoli/2010/03/async-howto.html</link>
<description>&lt;img src="/img/icons/trophy.png" alt="Vincitore Contest2009" border="0" height="88" width="65" style="float:left;padding:0px 5px 0px 0px"&gt;
&lt;h2&gt;&lt;a name="prefazione"&gt;Prefazione&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Immaginiamo di avere una lista molto lunga di oggetti da elaborare: questa lista omogena richiede per ogni elemento una serie di operazioni su sistemi esterni, che pero' impiegano un po di tempo a rispondere.&lt;/p&gt;
&lt;p&gt;Sebbene questo problema sembri altamente scalabile, nella pratica potrebbe risultare difficile da parallelizzare per via di limiti &lt;strong&gt;ambientali&lt;/strong&gt;, tipo un limite sulle risorse usabili; se per esempio dovessimo fare una serie di chiamate http e registrarne gli esiti su un db, allora potremmo aprire anche molte connessioni http ma poche sul db o addirittura solo 1.&lt;/p&gt;
&lt;p&gt;In questi casi puo' venir comodo un &lt;strong&gt;pool&lt;/strong&gt; per le risorse limitate dove ogni singolo &lt;strong&gt;thread&lt;/strong&gt; puo' ottenere temporaneamente un &lt;strong&gt;handler&lt;/strong&gt; e permettere cosi' di avere tanti processi che condividono poche risorse. (Nell'esempio sopra avremmo tanti thread quante connessioni vogliamo aprire, che a termine dell'operazione chiedono &lt;strong&gt;in prestito&lt;/strong&gt; una connessione a db per registrarne l'esito, quindi restituirla)&lt;/p&gt;
&lt;p&gt;Sfortunatamente questo e' possibile solo usando appunto i &lt;strong&gt;thread&lt;/strong&gt;s; in &lt;strong&gt;multi-tasking &lt;/strong&gt;&amp;gt; non e' possibile condividere le risorse visto che i task sono isolati fra loro.&lt;/p&gt;
&lt;p&gt;E' possibile usare un'altro approccio, su un unico task posso operare su piu' connessioni in maniera &lt;em&gt;asincrona&lt;/em&gt;...&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;h2&gt;&lt;a name="sincrono_vs_asincrono"&gt;Sincrono vs asincrono&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;h3&gt;&lt;a name="sincrono"&gt;Sincrono&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Per prima cosa, vediamo cosa significano questi due termini, il modo migliore e' con un esempio.&lt;/p&gt;
&lt;pre&gt;

        sub sync {
          my ($request) = @_;

          my $conn = openConn();
          $conn-&amp;gt;send($request);

          my $response = $conn-&amp;gt;recv();
          $conn-&amp;gt;close();
          return $response;
        }&lt;/pre&gt;
&lt;p&gt;In questo esempio si apre una connessione e si inviano dati, quindi si aspetta di ricevere una risposta.
E' possibile (in certi casi) migliorare le prestazioni aprendo una connessione una volta sola e usandola piu' volte:&lt;/p&gt;
&lt;pre&gt;
        sub sync {
          my ($request, $conn) = @_;

          $conn-&amp;gt;send($request);
          my $response = $conn-&amp;gt;recv();
          return $response;
        }&lt;/pre&gt;
&lt;p&gt;Ci possiamo anche aspettare un meccanismo piu' complicato, dove le operazioni sono piu' d'una:&lt;/p&gt;
&lt;pre&gt;
        sub sync {
          my ($request, $conn) = @_;

          $conn-&amp;gt;send($request-&amp;gt;head);
          my $ack = $conn-&amp;gt;recv();
          $ack-&amp;gt;is_ok or die;

          $conn-&amp;gt;send($request-&amp;gt;body);
          my $response = $conn-&amp;gt;recv();
          return $response;
        }&lt;/pre&gt;
&lt;p&gt;A questo punto scriviamo il corpo del programma:&lt;/p&gt;
&lt;pre&gt;
        my @list = fetchList();
        my $conn = openConn();
        my $db = openDB();

        foreach my @item (@list) {
          my $response = sync($item, $conn);
          $db-&amp;gt;storeResult($item, $response);
        }&lt;/pre&gt;
&lt;p&gt;Se volessimo parallelizzare usando piu' task&lt;/p&gt;
&lt;pre&gt;
        my $NTASK = 4;
        my @list = fetchList();

        # prepariamo delle partizioni in round-robin, una per ogni figlio
        my @partitions = map { []; } (1..$NTASK);
        for(my $i=0; $i &amp;lt; scalar @list; $i++) {
                my $tid = $i % $NTASK;
                push @{$partitions[$tid]}, $list[$i];
        }

        # fork di ogni child
        my @childs;
        foreach my $tid (1..$NTASK) {
                my $pid = fork();
                defined $pid or die;
                if($pid) {
                        # sono il padre, mi registro il pid
                        push @childs, $pid;
                } else {
                        # sono il figlio, iniziamo a lavorare
                        work($partitions[$tid]);
                        exit;
                }
        }
        # e aspettiamo che finiscano
        map { waitpid($_); } @childs;
        
        # ogni figlio lavorera' sulla sua partizione di dati
        sub work
        {
                my ($list) = @_;
                my $conn = openConn();
                my $db = openDB();
                foreach my $item ( @$list ) {
                        my $response = sync($item);
                        $db-&amp;gt;storeResult($item, $response);
                }
        }&lt;/pre&gt;
&lt;p&gt;E' evidente che cosi' per ogni child dovro' fare una chiamata a &lt;code&gt;openConn()&lt;/code&gt;
e una a &lt;code&gt;openDB()&lt;/code&gt;. E' gia' un bel passo avanti certo, ma il numero di child
non puo' esser elevato perche' il numero di &lt;code&gt;openDB&lt;/code&gt; non puo' esserlo.&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;h2&gt;&lt;a name="asincrono"&gt;Asincrono&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Se il tempo che impiega il metodo &lt;code&gt;sync()&lt;/code&gt; e' molto elevato, finiremmo con avere un pugno di task che aspettano una risposta nel 99% del tempo e non possiamo aumentare il numero di child perche' -- come abbiamo detto -- sul db non possiamo fare molte connessioni.&lt;/p&gt;
&lt;p&gt;In questo caso possiamo &lt;strong&gt;rompere&lt;/strong&gt; il metodo sync in due parti, una prima che invia i dati e una seconda che li elabora. Il nostro programma quindi iniviera' i dati a tante connessioni senza &lt;strong&gt;bloccarsi&lt;/strong&gt; aspettando una risposta, per poi raccogliere le risposte in seguito.&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;h3&gt;&lt;a name="wrapper_della_connessione"&gt;Wrapper della connessione&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Creiamo quindi un oggetto di connessione nostro che useremo come involucro attorno alla connessione vera. Iniziamo immaginando un caso semplice, dove si fa solo una richiesta e si ottiene solo una risposta:&lt;/p&gt;
&lt;pre&gt;
        package Conn;
        
        sub new
        {
                my ($class, $conn)
                bless [
                        $conn,  # la connessione
                        undef,  # spazio per la closure INTERNA di lettura
                ], $class;
        }

        sub async
        {
                my ($self, $request, $on_success) = @_;
                die &amp;quot;already in use&amp;quot; if $self-&amp;gt;[1]; # morte agli stacanovisti

                $self-&amp;gt;[0]-&amp;gt;send($request); # invio i dati

                $self-&amp;gt;[1] = sub { # registro la closure INTERNA di lettura
                        my $response = $self-&amp;gt;[0]-&amp;gt;recv();
                        $on_success-&amp;gt;($response);
                        return undef;
                };
        }

        sub dispose
        {
                my ($self) = @_;
                return unless $self-&amp;gt;[1]; # se non c'e' nulla da fare...
                $self-&amp;gt;[1] = $self-&amp;gt;[1]-&amp;gt;();
        }

        sub is_working
        {
                my ($self) = @_;
                return defined $self-&amp;gt;[1];
        }&lt;/pre&gt;
&lt;p&gt;Il &lt;strong&gt;wrapper&lt;/strong&gt; sopra puo' esser costruito partendo da una connessione, e espone 2 metodi: &lt;code&gt;async&lt;/code&gt; e &lt;code&gt;dispose&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Il suo uso e' piuttosto semplice:&lt;/p&gt;
&lt;pre&gt;
        my $conn = Conn-&amp;gt;new(openConn());
        my $db = openDB();
        # ...
        $conn-&amp;gt;async(
                $request, # la richiesta
                sub {     # la callback
                    my $result = @_;
                    $db-&amp;gt;storeResult($request, $result);
                }
        );
        # ...
        $conn-&amp;gt;dispose();&lt;/pre&gt;
&lt;p&gt;Vediamo meglio cosa succede in questo disegno dove il tempo scorre verso il basso:&lt;/p&gt;


&lt;span class="mt-enclosure mt-enclosure-image" style="display: inline;"&gt;&lt;img alt="diagramma_oha.png" src="http://www.perl.it/documenti/articoli/diagramma_oha.png" width="505" height="547" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /&gt;&lt;/span&gt;


        Note: ---&amp;gt; chiama o ritorna      ...&amp;gt; definisce&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;1&lt;/strong&gt; - Alla chiamata &lt;code&gt;async()&lt;/code&gt; si passa la &lt;code&gt;$request&lt;/code&gt; e una closure in grado di registrare sul db il risultato, che chiameremo &lt;code&gt;callback&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2&lt;/strong&gt; - &lt;code&gt;async()&lt;/code&gt; invia la richiesta e registra la closure &lt;code&gt;INTERNAL&lt;/code&gt; nel wrapper, che &lt;strong&gt;chiude&lt;/strong&gt; la &lt;code&gt;callback&lt;/code&gt; al suo interno.&lt;/p&gt;
&lt;p&gt;a questo punto, il codice puo' fare altro...&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3&lt;/strong&gt; - dopo un po di tempo, si chiama il metodo &lt;code&gt;dispose()&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4&lt;/strong&gt; - &lt;code&gt;dispose()&lt;/code&gt; invoca la closure registrata nel wrapper: &lt;code&gt;INTERNAL&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5&lt;/strong&gt; - &lt;code&gt;INTERNAL&lt;/code&gt; blocca finche' non arriva la risposta.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;6&lt;/strong&gt; - la closure &lt;code&gt;callback&lt;/code&gt; viene quindi invocata e registrera' l'esito sul DB.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;7&lt;/strong&gt; - &lt;code&gt;dispose()&lt;/code&gt; imposta come closure interna il valore da lei stessa ritornato, cioe' &lt;code&gt;undef&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;h3&gt;&lt;a name="tanti_wrapper_per_1_solo_task"&gt;Tanti Wrapper per 1 solo task&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Dobbiamo pero' riempire i &lt;code&gt;#...&lt;/code&gt; del codice sopra, e' cioe' vedere come far funzionare tutto questo:&lt;/p&gt;
&lt;pre&gt;
        # apro NTASK connessioni ma solo 1 a db
        my @conns = map { Conn-&amp;gt;new(openConn()); } (1..$NTASK);
        my $db = openDB();

        # ottengo tutti i dati
        my @list = fetchList();
        my $cid = 0;

        foreach my $item (@list)
        {
                # prendo una connessione in round-robin
                my $conn = $conns[$cid++ % $NTASK];

                # chiamo dispose cosi' da sbrigare il lavoro arretrato
                $conn-&amp;gt;dispose;

                $conn-&amp;gt;async($request, sub { # callback
                        my $result = @_;
                        $db-&amp;gt;storeResult($request, $result);
                });
        }

        # finiamo le cose ancora in sospeso
        map { $_-&amp;gt;dispose(); } grep { $_-&amp;gt;[1] } @conns;&lt;/pre&gt;
&lt;p&gt;Ecco che gia' si vede un netto miglioramento: si puo' assegnare a &lt;code&gt;$NTASK&lt;/code&gt; un numero anche molto grande, visto che cmq useremo solo una connessione a db!
E non solo, non abbiamo piu' tanti task e una fork da gestire, ma tutto in un unico processo, ancora meglio!&lt;/p&gt;
&lt;p&gt;Inoltre si vede che per ogni elemento della lista ci si sposta di 1 nella lista di connessioni, quindi si chiamera' &lt;code&gt;dispose()&lt;/code&gt; sullo stesso &lt;strong&gt;wrapper&lt;/strong&gt; solo dopo che verra' fatto un giro completo.&lt;/p&gt;
&lt;p&gt;Se per esempio ogni risposta richiedesse 10 secondi e usassimo 100 connessioni allora le prime 100 richieste verranno inviate quasi istantaneamente.
Alla 101-esima la dispose blocchera' per 10 secondi, per poi registrare la prima risposta sul db.
Alla 102-esima la dispose non blocchera', visto che sono gia' passati 10 secondi!&lt;/p&gt;
&lt;p&gt;Idealmente se le risposte richiedessero esattamente 10 secondi l'una avremmo un atteggiamento a &lt;strong&gt;ondate&lt;/strong&gt; dove partono 100 richieste e poi si blocca, poi altre 100 e poi di nuovo si blocca.&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;h3&gt;&lt;a name="richieste_a_piu__fasi"&gt;Richieste a piu' fasi&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Prima abbiamo immaginato una richiesta a due fasi, dove in pratica si deve prima inviare una richiesta e dopo una seconda... ma come farlo usando il wrapper?&lt;/p&gt;
&lt;p&gt;In realta' abbiamo gia' quasi tutto pronto, basta che la prima closure &lt;code&gt;INTERNAL&lt;/code&gt; anziche' ritornare undef ritorni la seconda fase:&lt;/p&gt;
&lt;pre&gt;
        sub async
        {
                my ($self, $request, $on_success, $on_error) = @_;
                die &amp;quot;already in use&amp;quot; if $self-&amp;gt;[1]; # morte agli stacanovisti

                $self-&amp;gt;[2] = $on_error;
                $self-&amp;gt;[0]-&amp;gt;send($request-&amp;gt;head);

                $self-&amp;gt;[1] = sub { # &amp;lt;-------------------------- INTERNAL prima fase
                        my $ack = $self-&amp;gt;[0]-&amp;gt;recv();

                        # se NAK, cancelliamo l'operazione
                        unless($ac-&amp;gt;is_ok()) {
                                $ack-&amp;gt;is_ok() or $on_error(&amp;quot;NAK&amp;quot;, $request, $ack);
                                return undef;
                        }

                        $self-&amp;gt;[0]-&amp;gt;send($request-&amp;gt;body);
                        return sub { # &amp;lt;------------------------ INTERNAL seconda fase
                                my response = $self-&amp;gt;[0]-&amp;gt;recv();

                                if($response-&amp;gt;is_ok()) { $on_success-&amp;gt;($response); }
                                else { $on_error-&amp;gt;(&amp;quot;RESPONSE KO&amp;quot;, $request, $response);

                                return undef;
                        };
                }
        }&lt;/pre&gt;
&lt;p&gt;Vediamo meglio cosa abbiamo aggiunto:&lt;/p&gt;
&lt;p&gt;La close &lt;code&gt;INTERNAL&lt;/code&gt;, come gia' detto, ora ritorna una seconda closure. In questo modo la prima chiamata a &lt;code&gt;dispose&lt;/code&gt; non finira' il lavoro subito ma registrera' una seconda fase.&lt;/p&gt;
&lt;p&gt;Abbiamo aggiunto anche una seconda callback &lt;code&gt;on_error&lt;/code&gt; che verra' chiamata se qualcosa va storto sia nella prima fase che nella seconda.&lt;/p&gt;
&lt;p&gt;Dobbiamo inoltre modificare l'uso, visto che una dispose potrebbe non esser abbastanza:&lt;/p&gt;
&lt;pre&gt;
        my @conns = map { Conn-&amp;gt;new(openConn()); } (1..$NTASK);
        my $db = openDB();
        my @list = fetchList();
        my $cid = 0;
        foreach my $item (@list)
        {
                my $conn;
                while(1) {
                        # prendo una connessione in round-robin
                        $conn = $conns[$cid++ % $NTASK];
        
                        # chiamo dispose cosi' da sbrigare il lavoro arretrato
                        $conn-&amp;gt;dispose;

                        # se ha finito... altrimenti avanti il prossimo
                        last unless $conn-&amp;gt;is_working;
                }

                $conn-&amp;gt;async($request, sub { # callback
                        my $result = @_;
                        $db-&amp;gt;storeResult($request, $result);
                });
        }

        # finiamo le cose ancora in sospeso
        map { $_-&amp;gt;dispose() while $_-&amp;gt;is_working(); } @conns;
&lt;/pre&gt;
&lt;p&gt;        
Qui le cose si complicano un pochino, ma ormai avete raggiunto la meta' di questo articolo, tanto vale finire no?&lt;/p&gt;
&lt;p&gt;Immaginiamo sempre il nostro caso teorico dove ogni richiesta richiede 10 secondi e abbiamo 100 connessioni.
Per le prima 100 richieste, come gia' succedeva', invieremo la prima parte della richiesta quasi istantaneamente.&lt;/p&gt;
&lt;p&gt;Arrivati alla 101-esima richiesta, pero', le cose cambiano: Infatti si chiamera' la dispose sulla prima connessione che blocchera' fino ad ottenere la risposta della prima fase, e inviera' la richiesta per la seconda fase.&lt;/p&gt;
&lt;p&gt;Purtroppo pero' la connessione NON e' ancora disponibile, si dovra' dunque iterare nel ciclo e tentare con la seconda, che non blocchera' piu' per 10 secondi ma si spostera' anch'essa alla seconda fase e via dicendo, fino a tornare alla prima.&lt;/p&gt;
&lt;p&gt;La prima nuovamente blocchera' per 10 secondi, terminera' dunque il lavoro e ritornera' disponibile all'uso, procendendo dunque all'effettivo invio della 101-esima richiesta, 20 secondi dopo.&lt;/p&gt;
&lt;p&gt;Le successive richieste non blocceranno (come per la 101-esima): esattamente come volevamo.&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;h2&gt;&lt;a name="io__select"&gt;IO::Select&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Il sistema sopra funziona egregiamente quando i tempi di risposta sono abbastanza costanti, ma quando alcune risposte impiegano molto piu' di altre allora possono sorgere problemi di efficienza.&lt;/p&gt;
&lt;p&gt;Immaginiamo di avere solo 2 istanze di &lt;strong&gt;wrapper&lt;/strong&gt;, al primo e' stata fatta una richiesta che richiedera' 10 secondi mentre al secondo una richiesta che richiedera' 1 secondo.&lt;/p&gt;
&lt;p&gt;Quando arrivera' la terza richiesta, questa blocchera' per 10 secondi sul primo slot anche se avrebbe potuto aspettare solo 1 secondo se avesse usato il secondo.&lt;/p&gt;
&lt;p&gt;Se il nostro &lt;strong&gt;wrapper&lt;/strong&gt; usa direttamente degli handler per comunicare, e' possibile usare la syscall &lt;code&gt;select&lt;/code&gt; per sapere, data una lista di handlers, quale di questi &lt;code&gt;handlers&lt;/code&gt; ha dati disponibili per la lettura.&lt;/p&gt;
&lt;p&gt;Per semplificare la gestione useremo il modulo &lt;a href="/IO/Select.html"&gt;the IO::Select manpage&lt;/a&gt;, ecco un esempio:&lt;/p&gt;
&lt;pre&gt;
        use IO::Select;

        my $sel = IO::Select-&amp;gt;new();
        map { $sel-&amp;gt;add($_); } @handlers;
        # ....
        my @ready = $sel-&amp;gt;can_read($timeout);&lt;/pre&gt;
&lt;p&gt;Nell'array &lt;code&gt;@ready&lt;/code&gt; otteniamo alcuni degli handlers aggiungi a &lt;code&gt;$sel&lt;/code&gt;, vale a dire quelli che hanno dati disponibili per la lettura.&lt;/p&gt;
&lt;p&gt;Il parametro &lt;code&gt;$timeout&lt;/code&gt; indica quanto tempo aspettare per avere almeno 1 filehandle. Cio' significa che se uno o piu'
handler e' gia' pronto ritornera' subito, oppure aspettera fino ad un massimo di &lt;code&gt;$timeout&lt;/code&gt; secondi prima di arrendersi
e tornare una lista vuota.&lt;/p&gt;
&lt;p&gt;Modifichiamo quindi radicalmente il nostro &lt;strong&gt;wrapper&lt;/strong&gt; e rendiamolo un vero pool di connessioni wrapped:&lt;/p&gt;
&lt;pre&gt;
        package Pool;
        use IO::Select;
        use IO::Socket;

        sub new {
                my ($class, %args) = @_;
                bless { 
                        %args,
                        _slots = {},
                        _sel = IO::Select-&amp;gt;new();
                }, $class;
        }

        sub _create {
                my ($self) = @_;
                my $slot = [
                        IO::Socket::INET-&amp;gt;new($self-&amp;gt;{host}),
                        undef, # INTERNAL
                        undef, # ON_ERROR
                ];
                my $fd = $slot-&amp;gt;[0]-&amp;gt;fileno or die;
                $slot-&amp;gt;[0]-&amp;gt;autoflush(1);
                $self-&amp;gt;{_slots}-&amp;gt;{$fd} = $slot;
                $self-&amp;gt;{_sel}-&amp;gt;add($slot-&amp;gt;[0]);
                return $slot;
        }

        sub _find {
                my ($self) = @_;
                $self-&amp;gt;dispose(0);
                while(1) {
                        my $ct = 0;
                        foreach my $slot (values %{$self-&amp;gt;{_slots}})
                        {
                                $ct++;
                                return $slot unless $slot-&amp;gt;is_working();
                        }
                        return $self-&amp;gt;_create() if $ct &amp;lt; $self-&amp;gt;{size};
                        $self-&amp;gt;dispose(0.5);
                }
        }

        sub close {
                my ($self) = @_;

                OUTER: while(1) {
                        foreach my $slot (values %{$self-&amp;gt;{_slots}})
                        {
                                if($slot-&amp;gt;[1]) {
                                        $self-&amp;gt;dispose(0.5);
                                        continue OUTER;
                                }
                        }
                        break;
                }
        }

        sub dispose {
                my ($self, $timeout) = @_;

                # get what is ready for data
                my @ready = $self-&amp;gt;{_sel}-&amp;gt;can_read($timeout);

                foreach my $fh (@ready) {
                        # get the slot
                        my $fd = $fh-&amp;gt;fileno;
                        my $slot = $self-&amp;gt;{_slot}-&amp;gt;{$fd};

                        # invoke che INTERNAL
                        eval { $slot-&amp;gt;[1] = $slot-&amp;gt;[1]-&amp;gt;(); };
                        next unless $@;
                        my $err = $@;

                        # remove the slot
                        delete $self-&amp;gt;{_slot}-&amp;gt;{$fd};
                        $self-&amp;gt;{_sel}-&amp;gt;remove($slot-&amp;gt;[0]);

                        # call the on_error
                        eval { $slot-&amp;gt;[2]-&amp;gt;($err); };
                }
        }

        sub async {
                my ($self, $req, $on_success, $on_error) = @_;

                # find a slot
                my $slot = $self-&amp;gt;_find();
                my $fh = $slot-&amp;gt;[0];

                # register the on_error
                $slot-&amp;gt;[2] = $on_error;

                # send first part of request
                $fh-&amp;gt;print($req-&amp;gt;head);

                # register the response handler 
                $slot-&amp;gt;[1] = sub {
                        my $ack = &amp;lt;$fh&amp;gt;;

                        # die, the dispose() will fire the on_error
                        die &amp;quot;NAK&amp;quot; unless $ack =~ /^OK/;

                        # send the second part of the request
                        $fh-&amp;gt;print($req-&amp;gt;body);

                        # register the new handler
                        return sub {
                                my $res = &amp;lt;$fh&amp;gt;;
                                die &amp;quot;KO&amp;quot; unless $res =~ /^200/;

                                # all went fine, call on_success
                                $on_success-&amp;gt;($res);

                                # free the slot
                                return undef;
                        };
                };
        }&lt;/pre&gt;
&lt;p&gt;Molte cose nuove, per prima cosa abbiamo un oggetto unico che conterra' tutte le connessioni aperte, definito con un massimo di connessioni disponibili.&lt;/p&gt;
&lt;p&gt;Il metodo &lt;code&gt;dispose()&lt;/code&gt; deve ora gestire il gruppo intero di connessioni, usando il selettore &lt;code&gt;IO::Select&lt;/code&gt; creato nel costruttore.&lt;/p&gt;
&lt;p&gt;Accetta anche un parametro di &lt;code&gt;$timeout&lt;/code&gt; che indica quanto tempo aspettare al massimo.&lt;/p&gt;
&lt;p&gt;Il metodo &lt;code&gt;async()&lt;/code&gt; e' simile al precedente, ma chiamera' il metodo interno &lt;code&gt;_find()&lt;/code&gt; per scoprire quale slot usare
invece di fare round-robin.&lt;/p&gt;
&lt;p&gt;Il vantaggio, oltre che l'efficienza, e' una piu' semplice usabilita' all'esterno:&lt;/p&gt;
&lt;pre&gt;
        my $pool = Pool-&amp;gt;new(
                host =&amp;gt; '1.2.3.4:1234',
                size =&amp;gt; 100,
        );
        my $db = openDB();

        foreach my $req (@list) 
        {
                $pool-&amp;gt;async( $req, 
                  sub {
                      my ($result) = @_;
                      $db-&amp;gt;storeResult($req, $result);
                  }, 
                  sub {
                      warn &amp;quot;error while $req:  @_&amp;quot;;
                });
        }
        $pool-&amp;gt;close();&lt;/pre&gt;
&lt;p&gt;Il metodo &lt;code&gt;_find()&lt;/code&gt; per prima cosa vede di chiamare la &lt;code&gt;dispose()&lt;/code&gt;, quindi se non trova slot liberi verifica quanti sono aperti, se sono meno del limite crea una nuova connessione, altrimenti richiama la &lt;code&gt;dispose()&lt;/code&gt; passando un timeout e aspetta che qualcuno si liberi.&lt;/p&gt;
&lt;p&gt;Visto che &lt;code&gt;_find()&lt;/code&gt; viene chiamato ad ogni chiamata a &lt;code&gt;async()&lt;/code&gt; possiamo evitare di chiamare il metodo &lt;code&gt;dispose()&lt;/code&gt;
direttamente, a meno che non serva &lt;strong&gt;controllare&lt;/strong&gt; la coda senza aggiunger nulla.&lt;/p&gt;
&lt;p&gt;Usando &lt;a href="/IO/Select.html"&gt;the IO::Select manpage&lt;/a&gt; abbiamo inoltre risolto il problema delle richieste a tempo non costante: 
se avessimo come prima massimo 2 connessioni impegnate dove la prima rispondera' fra 10 secondi e la seconda solo dopo 1 secondo, 
la chiamata a &lt;code&gt;async()&lt;/code&gt; iniziera' a chiamare &lt;code&gt;_find()&lt;/code&gt; che non potendo creare una connessione nuova
chiamera' la &lt;code&gt;dispose()&lt;/code&gt; anche piu' volte, 
dopo qualche tentativo finalmente otterremo la risposta sul secondo slot rendendolo disponibile e 
&lt;code&gt;_find()&lt;/code&gt; ritornera' questo slot permettendo cosi' l'invio del terzo messaggio dopo 1 secondo.&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;h2&gt;&lt;a name="cosa_aggiungere_ora"&gt;Cosa aggiungere ora?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Il sistema usato sopra non fa piu' round-robin ma gestisce le connessioni in ordine sparso.&lt;/p&gt;
&lt;p&gt;E' possibile quindi aggiungere altri parametri allo slot, come un timeout per la lettura e un idle_time oltre il quale chiudere la connessione.&lt;/p&gt;
&lt;p&gt;In questo modo le connessioni oltre ad aprirsi quando richiesto possono anche chiudersi dopo un tempo di &lt;code&gt;idle&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;E' possibile inoltre distruggere le connessioni dopo qualche migliaio di usi, cosi' da liberare eventuali risorse
allocate lato server.&lt;/p&gt;
&lt;p&gt;Per fare questo aggiungiamo a &lt;code&gt;$self-&amp;gt;{_next_expire_check}&lt;/code&gt; e aggiungiamo allo slot un quarto parametro &lt;code&gt;last_use&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;
        sub dispose {
                my ($self, $timeout) = @_;

                # get what is ready for data
                my @ready = $self-&amp;gt;{_sel}-&amp;gt;can_read($timeout);
                my %closing;

                foreach my $fh (@ready) {
                        # get the slot
                        my $fd = $fh-&amp;gt;fileno;
                        my $slot = $self-&amp;gt;{_slot}-&amp;gt;{$fd};

                        # invoke che INTERNAL
                        eval { 
                                $slot-&amp;gt;[1] = $slot-&amp;gt;[1]-&amp;gt;(); 
                                $slot-&amp;gt;[3] = time(); # aggiorno last_use
                        };
                        next unless $@;

                        # mark for closing
                        $closing{$fd} = $@;
                }

                next unless time() &amp;gt; $self-&amp;gt;{_next_expire_check};
                $self-&amp;gt;{_next_expire_check} = time();
                
                foreach my $slot ( values %{ $self-&amp;gt;{_slots} } )
                {
                        my $timeout = $slot-&amp;gt;[1]   # e' in uso?
                                ? $self-&amp;gt;{read_timeout} 
                                : $self-&amp;gt;{idle_timeout};

                        # confronto il last_use
                        next unless $slot-&amp;gt;[3]+$timeout &amp;lt; time();

                        # se e' passato troppo tempo
                        $closing{$slot-&amp;gt;[0]-&amp;gt;fileno} ||= &amp;quot;TIMEOUT&amp;quot;;
                }
                
                # per tutte quelle in closing...
                while( my($fd, $err) = each %closing )
                {
                        my $slot = $self-&amp;gt;{_slots}-&amp;gt;{$fd};

                        # remove the slot
                        delete $self-&amp;gt;{_slots}-&amp;gt;{$fd};
                        $self-&amp;gt;{_sel}-&amp;gt;remove($slot-&amp;gt;[0]);

                        # call the ERROR callback if still in 
                        eval { $slot-&amp;gt;[2]-&amp;gt;($err); } if $slot-&amp;gt;[1];
                }
        }&lt;/pre&gt;
&lt;p&gt;e aggiungiamo alla sub &lt;code&gt;async&lt;/code&gt; un reset del &lt;code&gt;last_use&lt;/code&gt; alla fine prima di uscire:&lt;/p&gt;
&lt;pre&gt;
        $slot-&amp;gt;[3] = time();&lt;/pre&gt;
&lt;p&gt;ora non serve altro che impostare questi valori durante la costruzione:&lt;/p&gt;
&lt;pre&gt;
        my $pool = Pool-&amp;gt;new(
                host =&amp;gt; '1.2.3.4:1234',
                size =&amp;gt; 100,
                read_timeout =&amp;gt; 30, 
                idle_timeout =&amp;gt; 120,
        );&lt;/pre&gt;
&lt;p&gt;E il resto rimane uguale, ora le connessioni che non rispondono in 30 secondi chiameranno la callback di errore con
&lt;code&gt;TIMEOUT&lt;/code&gt; mentre quelle non usate per 120 secondi verranno chiuse silenziosamente.&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;h2&gt;&lt;a name="conclusioni"&gt;Conclusioni&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Certo si e' dovuto scrivere un mucchio di codice, e la gestione degli errori e' complessa, ma i vantaggi sono evidenti: Un solo task gestisce piu' connessioni, una sorta di reattore.&lt;/p&gt;
&lt;p&gt;E' necessario pero' tener presente che la gestione degli errori puo' esser complessa!&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ArticoliPerlIt?a=HDiUSKkZOME:YSXw0olvgl4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ArticoliPerlIt?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ArticoliPerlIt?a=HDiUSKkZOME:YSXw0olvgl4:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ArticoliPerlIt?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
<dc:subject>article</dc:subject>
<dc:creator>larsen</dc:creator>
<dc:date>2010-03-20T16:30:10+02:00</dc:date>
</item>

<item rdf:about="http://www.perl.it/documenti/articoli/2009/07/autobox-un-po-d.html">
<title>Autobox: un po' di futuro, adesso</title>
<link>http://www.perl.it/documenti/articoli/2009/07/autobox-un-po-d.html</link>
<description>&lt;p&gt;
Parlare del futuro, per noi perlisti, &amp;egrave; divenuta purtroppo una faccenda imbarazzante. Da talmente tanti anni ormai siamo convinti, o cercano di convincerci, che prima o poi il Perl6 arriver&amp;agrave;, che abbiamo ineluttabilmente accettato il fatto che sar&amp;agrave; il linguaggio di programmazione utilizzato dai nostri nipotini.
&lt;/p&gt;
&lt;p&gt;
Ma oggi non sono qui per affliggervi, tutt'altro! Esiste gi&amp;agrave;, se non altro, un &lt;i&gt;effetto collaterale&lt;/i&gt; del Perl6. Ed &amp;egrave; quello di aver spinto un sostanzioso numero di brillanti sviluppatori a spremersi le meningi per realizzare, in certa misura, una "compatibilit&amp;agrave; con le versioni successive" del linguaggo. In altre parole, aggiungere nuove e sempre pi&amp;ugrave; sorprendenti funzionalit&amp;agrave; al Perl5 attuale, in buona parte mutuate o ispirate da quello che sar&amp;agrave; il Perl6. 
&lt;/p&gt;
&lt;p&gt;
I primi sforzi hanno portato al fiorire, su CPAN, di vari moduli nel namespace Perl6 (&lt;tt&gt;Perl6::Variables&lt;/tt&gt;, &lt;tt&gt;Perl6::Rules&lt;/tt&gt;, &lt;tt&gt;Perl6::Junction&lt;/tt&gt; tanto per citarne alcuni). Utili a livello di prototipo per la progettazione del nuovo linguaggio, decisamente meno nell'uso quotidiano. Col passare del tempo, per&amp;ograve;, e con il consolidamento delle specifiche del Perl6, alcune nozioni - soprattutto per quanto riguarda la programmazione &lt;i&gt;object oriented&lt;/i&gt; - sono "trapelate" in strumenti tutt'altro che puramente teorici. Mi riferisco principalmente a Moose, del quale potete leggere &lt;a href="http://www.perl.it/blog/archives/000641.html"&gt;altrove su questo sito&lt;/a&gt;. 
&lt;/p&gt;
&lt;p&gt;
Questo dimostra sostanzialmente due cose: primo, che il processo di "invenzione" del Perl6 non &amp;egrave; campato in aria, che le idee ci sono, sono buone e vale la pena di implementarle. Secondo, che il Perl5, nonostante gli anni, non ha ancora finito di stupirci per potenza, flessibilit&amp;agrave; e capacit&amp;agrave; di rinnovarsi. 
&lt;/p&gt;
&lt;p&gt;
L'oggetto del mio articolo &amp;egrave; un modulo (due, in realt&amp;agrave;) dall'apparenza innocua, che trovate su CPAN. Ai lettori pi&amp;ugrave; smaliziati non sfuggiranno i riferimenti al Perl6 impliciti nel modulo. Si chiama semplicemente &lt;tt&gt;autobox&lt;/tt&gt;. Non ha un nome altisonante, non &amp;egrave; composto da migliaia di righe di codice, eppure pu&amp;ograve; davvero rivoluzionare il modo in cui scrivete codice Perl. Oggi.
&lt;/p&gt;
&lt;h2&gt;"hello autobox"&lt;/h2&gt;
&lt;p&gt;
La finalit&amp;agrave; del modulo &lt;tt&gt;autobox&lt;/tt&gt; &amp;egrave; enunciata quasi laconicamente nella sua documentazione: invocare metodi su tipi nativi.
&lt;/p&gt;
&lt;p&gt;
In altre parole, tramutare qualunque &lt;i&gt;termine&lt;/i&gt; di un programma in un oggetto. O meglio, visto che non si tratta di un vero e proprio tramutare, &lt;i&gt;estendere&lt;/i&gt; la sintassi object oriented facendo s&amp;igrave; che anche semplici valori, non solo ci&amp;ograve; che esplicitamente instanziamo tramite un costruttore, diventino oggetto d'invocazione di un metodo.
&lt;/p&gt;
&lt;p&gt;
Ma forse era pi&amp;ugrave; chiara la spiegazione laconica. Lasciamo da parte la teoria e vediamo un attimo come questa si traduce in pratica. Il modulo permette cose come questa:
&lt;/p&gt;

&lt;pre&gt;    use autobox;
    my $greeting = "hello autobox"-&gt;upper();
&lt;/pre&gt;

&lt;p&gt;
Sorprendente, no? &lt;tt&gt;"hello autobox"&lt;/tt&gt; &amp;egrave; una stringa, eppure la riga sopra &lt;i&gt;funziona&lt;/i&gt; (in realt&amp;agrave;, no. &lt;i&gt;Funzionerebbe&lt;/i&gt; se avessimo definito un metodo &lt;tt&gt;upper&lt;/tt&gt; che converte una stringa in maiuscolo; ma ci arriviamo). In sostanza, il codice equivale ad aver scritto una cosa del genere:
&lt;/p&gt;

&lt;pre&gt;    use String;
    my $string = String-&gt;new("hello autobox");
    my $greeting = $string-&gt;upper();
&lt;/pre&gt;
&lt;p&gt;    
Supponendo l'esistenza di una classe &lt;tt&gt;String&lt;/tt&gt;, dall'implementazione piuttosto ovvia. Eppure &lt;tt&gt;"hello autobox"&lt;/tt&gt; non &amp;egrave; un oggetto, non ci assomiglia neanche lontanamente. &amp;Egrave; una stringa!
&lt;/p&gt;
&lt;p&gt;
Da un altro punto di vista, per&amp;ograve;, esso &amp;egrave; anche uno &lt;i&gt;scalare&lt;/i&gt;, ossia qualcosa che rappresenta un valore. Cos&amp;igrave; come &lt;tt&gt;$foo&lt;/tt&gt; (una variabile) o &lt;tt&gt;2+2&lt;/tt&gt; (un'espressione). E &lt;tt&gt;autobox&lt;/tt&gt; non fa altro che definire "classi virtuali", per cos&amp;igrave; dire, delle quali implicitamente tutto pu&amp;ograve; essere istanza. Nella fattispecie, la classe per la nostra stringa &amp;egrave; &lt;tt&gt;SCALAR&lt;/tt&gt;.
&lt;/p&gt;
&lt;p&gt;
Dovremmo avere tutti gli elementi, a questo punto, per far effettivamente funzionare il nostro primo esempio:
&lt;/p&gt;

&lt;pre&gt;    use autobox;
    sub SCALAR::upper { return uc(@_); }
    
    my $greeting = "hello autobox"-&gt;upper();
    # $greeting ora contiene "HELLO AUTOBOX"!
&lt;/pre&gt;

&lt;p&gt;
In pratica, basta definire metodi appartenenti alla "classe virtuale" e la loro invocazione avviene &lt;i&gt;come se&lt;/i&gt; il termine fosse un'istanza di quella classe. Focalizzate i primi due esempi, quello che usa &lt;tt&gt;autobox&lt;/tt&gt; e quello che usa l'ipotetica classe &lt;tt&gt;String&lt;/tt&gt;. Questo &amp;egrave;, in sostanza, quello che succede:
&lt;/p&gt;

&lt;pre&gt;    "hello autobox"-&gt;upper()  corrisponde a: SCALAR::upper("hello autobox")
    $string-&gt;upper()          corrisponde a: String::upper($string)
&lt;/pre&gt;

&lt;p&gt;
La dicitura "tipi nativi", inoltre, non ci limita solo alle stringhe. Anche array e hash godono delle stesse prerogative. Un esempio:
&lt;/p&gt;

&lt;pre&gt;    use autobox;

    sub ARRAY::sum {
        my $array = shift;
        my $sum = 0; 
        $sum += $_ foreach(@$array); 
        return $sum; 
    }

    my @numeri = (1..10);
    print @numeri-&gt;sum(); # stampa 55
&lt;/pre&gt;

&lt;p&gt;    
Chiaro come il sole, no? Ok, lo so cosa state pensando. Sicuramente un trucchetto interessante, meritevole di un'alzata di sopracciglia. Ma andiamo, a chi potrebbe venire in mente di usare seriamente una sintassi del genere? Sono pienamente d'accordo con voi. Ma aspettate, il bello deve ancora venire...
&lt;/p&gt;

&lt;h2&gt;Facciamo 31&lt;/h2&gt;

&lt;p&gt;
Di per s&amp;eacute;, come abbiamo visto, &lt;tt&gt;autobox&lt;/tt&gt; non fornisce nulla se non la &lt;i&gt;possibilit&amp;agrave;&lt;/i&gt; di utilizzare sintassi object oriented su non-oggetti. Per convertire una stringa in maiuscolo ho dovuto scrivere una funzione (metodo) che utilizzasse la parola chiave &lt;tt&gt;uc&lt;/tt&gt;. Bell'affare.
&lt;/p&gt;
&lt;p&gt;
Esiste per&amp;ograve; un altro modulo su CPAN, chiamato &lt;tt&gt;autobox::Core&lt;/tt&gt;, il quale applica le potenzialit&amp;agrave; di &lt;tt&gt;autobox&lt;/tt&gt; nientepopodimeno che al &lt;i&gt;core&lt;/i&gt; del Perl, ossia tutte (o quasi) le sue parole chiave.
&lt;/p&gt;
&lt;p&gt;
Basta usare il modulo, e la magia si compie sotto i nostri occhi increduli:
&lt;/p&gt;

&lt;pre&gt;    use autobox::Core;
    
    "hello autobox"-&gt;uc()-&gt;print(); # stampa HELLO AUTOBOX
    
    my @numeri = (1..10);
    @numeri-&gt;join(",")-&gt;print(); # stampa 1,2,3,4,5,6,7,8,9,10
&lt;/pre&gt;

&lt;p&gt;
Ora s&amp;igrave; che la cosa si fa davvero interessante! Questi esempi &lt;i&gt;funzionano&lt;/i&gt;, usando una sintassi che non sembra solo il capriccio di un abile programmatore con troppo tempo libero. Una sintassi appetibile, elegante, certo spiazzante per il perlista di lunga data, ma sensata. Dannatamente sensata. Una sintassi, per dirla con un acronimo prettamente informatico, deliziosamente DWIM (&lt;i&gt;Do What I Mean&lt;/i&gt;). 
&lt;/p&gt;

&lt;h2&gt;Andiamo sul concreto&lt;/h2&gt;

&lt;p&gt;
Non pretendo di illustrarvi le conseguenze ultime dell'utilizzo di &lt;tt&gt;autobox&lt;/tt&gt;. Del resto, io stesso non ho ancora veramente "rivoluzionato" il modo in cui scrivo Perl. 
&lt;/p&gt;
&lt;p&gt;
Voglio darvi per&amp;ograve; qualche assaggio, codice alla mano, partendo da un caso concreto. Dove a mio avviso &lt;tt&gt;autobox&lt;/tt&gt; brilla davvero, e allevia alcune "brutture" congenite alla sintassi Perl, &amp;egrave; nella gestione di strutture dati complesse.
&lt;/p&gt;
&lt;p&gt;
Avevo come compito quello di realizzare una sorta di procedura di backup, in pratica serializzare su file alcuni dati contenuti in un database. I dettagli della procedura, comunque, sono poco importanti.
&lt;/p&gt;
&lt;p&gt;
Comincio il mio lavoro definendo una struttura nella quale andare a memorizzare tutto quello che mi serve:
&lt;/p&gt;

&lt;pre&gt;    my $data = {
        objects =&gt; [],
        languages =&gt; [],
        # ...
    };
&lt;/pre&gt;

&lt;p&gt;
Fin qui niente di speciale. Ora devo popolare la struttura con i dati provenienti da una query:
&lt;/p&gt;

&lt;pre&gt;    foreach my $object ( do_query() ) {
    	push(@{ $data-&gt;{objects} }, $object);
    }
&lt;/pre&gt;

&lt;p&gt;
Quant'&amp;egrave; brutto quel &lt;tt&gt;push&lt;/tt&gt;, eh? Eppure inevitabile. Almeno finch&amp;eacute; non c'era &lt;tt&gt;autobox::Core&lt;/tt&gt;:
&lt;/p&gt;

&lt;pre&gt;    use autobox::Core;
    foreach my $object ( do_query() ) {
        $data-&gt;{objects}-&gt;push( $object );
    }
&lt;/pre&gt;
&lt;p&gt;
Non so voi, ma a me cos&amp;igrave; piace molto di pi&amp;ugrave;! Ora diciamo che in un punto successivo del mio codice devo nuovamente scorrere la lista degli oggetti recuperati per qualche motivo:
&lt;/p&gt;

&lt;pre&gt;    ## prima
    foreach my $object (@{ $data-&gt;{objects} }) {
        do_stuff($object);
    }
    
    ## dopo
    foreach my $object ($data-&gt;{objects}-&gt;flatten) {
        do_stuff($object);
    }
&lt;/pre&gt;

&lt;p&gt;
Ok, c'&amp;egrave; un &lt;tt&gt;flatten&lt;/tt&gt; che forse non ci aspettavamo: &lt;tt&gt;$data-&gt;{objects}&lt;/tt&gt; contiene un riferimento ad array, e dunque dobbiamo in ogni caso dereferenziarlo per ottenere la lista vera e propria. Meglio &lt;tt&gt;flatten&lt;/tt&gt;, comunque, che un pi&amp;ugrave; criptico &lt;tt&gt;@{ ... }&lt;/tt&gt;. Scagli la prima pietra chi non ha mai dimenticato una parentesi graffa con la sintassi di "prima"!
&lt;/p&gt;

&lt;p&gt;
Ma non solo. Se Perl &amp;egrave; il linguaggio del "c'&amp;egrave; pi&amp;ugrave; di un modo per farlo", &lt;tt&gt;autobox&lt;/tt&gt; non &amp;egrave; da meno. Anche queste forme sono possibili (per quanto personalmente preferisca il caro, vecchio &lt;tt&gt;foreach&lt;/tt&gt;):
&lt;/p&gt;

&lt;pre&gt;    $data-&gt;{objects}-&gt;foreach(sub {
        do_stuff($_[0]);
    });

    ## ma anche...
    $data-&gt;{objects}-&gt;map(sub {
        do_stuff($_);
    });
&lt;/pre&gt;

&lt;p&gt;
E ora supponiamo di avere una struttura dati che contiene un elenco (strutturato a sua volta) di file per ogni linguaggio, una cosa del genere:
&lt;/p&gt;

&lt;pre&gt;    my %files = (
        en =&gt; {
            templates =&gt; 'po/templates_en.po',
            forms =&gt; 'po/forms_en.po',
        },
        it =&gt; {
            templates =&gt; 'po/templates_it.po',
            forms =&gt; 'po/forms_it.po',
            cities =&gt; 'po/cities_it.po',
        },
        # etc. etc.
    );
&lt;/pre&gt;

&lt;p&gt;
Devo andare a memorizzare in &lt;tt&gt;$data-&gt;{languages}&lt;/tt&gt; l'elenco dei file che mi servono, ossia quelli dei linguaggi utilizzati negli oggetti che ho recuperato.
&lt;/p&gt;

&lt;pre&gt;    ## prima
    my %language_seen;
    foreach my $object (@{ $data-&gt;{objects} }) {
        $language_seen{ $object-&gt;language_id } = 1;
    }
    foreach my $language (keys %language_seen) {
        push(@{ $data-&gt;{languages} }, values %{ $files{$language} });
    }	
&lt;/pre&gt;

&lt;p&gt;
La probabilit&amp;agrave; di scordarsi qualche parentesi cresce esponenzialmente... e ora vediamo cosa succede con &lt;tt&gt;autobox&lt;/tt&gt;. Ma se dobbiamo farlo, facciamolo bene! Abbiamo gi&amp;agrave; visto come sia facile definire metodi che vadano ad agire sui "tipi nativi", quindi chiamiamo in causa &lt;tt&gt;List::MoreUtils&lt;/tt&gt;:
&lt;/p&gt;

&lt;pre&gt;    ## dopo
    use autobox;
    use autobox::Core;
    use List::MoreUtils;
    sub ARRAY::uniq { return List::MoreUtils::uniq(@_) }

    foreach my $language ($data-&gt;{objects}-&gt;map( sub { $_-&gt;language_id } )-&gt;uniq-&gt;flatten) {
        $data-&gt;{languages}-&gt;push( $files{$language}-&gt;values-&gt;flatten );
    }
&lt;/pre&gt;
	
&lt;p&gt;
D'accordo, questo comincia a sembrare pi&amp;ugrave; un esercizio di stile che del serio e onesto codice. Del resto &lt;tt&gt;autobox&lt;/tt&gt; &amp;egrave; uno strumento, e in quanto tale soggetto ad essere abusato. Quello che ancora disturba un po', a mio avviso, &amp;egrave; la necessit&amp;agrave; di introdurre con &lt;tt&gt;sub&lt;/tt&gt; l'argomento del metodo &lt;tt&gt;map&lt;/tt&gt;. Ma nessuno &amp;egrave; perfetto :-).
&lt;/p&gt;

&lt;p&gt;
Concludo con un esempio "da manuale". Tutti sappiamo cos'&amp;egrave; la &lt;i&gt;trasformata di Schwartz&lt;/i&gt;, ovviamente (altrimenti, &lt;a href="http://www.perl.it/documenti/articoli/2008/06/dare-una-riordi.html"&gt;date una ripassata&lt;/a&gt;). Questo codice, liberamente tratto dalla documentazione Perl, ordina un array secondo il primo numero presente nella stringa. Per capirci:
&lt;/p&gt;

&lt;pre&gt;    my @data = ( 
        "Biancaneve e i 7 nani",
        "Ali baba e i 40 ladroni", 
        "I 3 Porcellini",
    );

    my @sorted = map  { $_-&gt;[0] }
                 sort { $a-&gt;[1] &lt;=&gt; $b-&gt;[1] }
                 map  { [ $_, (/(\d+)/)[0] ] } @data;

    # @sorted:
    # I 3 Porcellini
    # Biancaneve e i 7 nani
    # Ali baba e i 40 ladroni

    # (ossia 3, 7, 40)
&lt;/pre&gt;

&lt;p&gt;
Vediamo che faccia ha la nostra trasformata usando &lt;tt&gt;autobox&lt;/tt&gt;:
&lt;/p&gt;

&lt;pre&gt;    my @sorted = @data
        -&gt;map ( sub { [ $_, (/(\d+)/)[0] ] } )
        -&gt;sort( sub { my($a, $b) = @_; $a-&gt;[1] &lt;=&gt; $b-&gt;[1] } )
        -&gt;map ( sub { $_-&gt;[0] } )
        -&gt;flatten;
&lt;/pre&gt;

&lt;p&gt;
Pi&amp;ugrave; comprensibile? Meno comprensibile? Lascio a voi decidere. Sintassi a parte, la differenza sta nella sequenza delle istruzioni, che con &lt;tt&gt;autobox&lt;/tt&gt; seguono il "flusso" naturale dei dati. La normale trasformata di Schwartz al contrario si legge, per cos&amp;igrave; dire, da destra a sinistra:
&lt;/p&gt;

&lt;pre&gt;    normale: map &lt;- sort &lt;- map &lt;- array
    autobox: array -&gt; map -&gt; sort -&gt; map
&lt;/pre&gt;

&lt;p&gt;	
Nella documentazione di &lt;tt&gt;autobox::Core&lt;/tt&gt; trovate alcune interessanti osservazioni sul perch&amp;egrave; questa differenza &amp;egrave; cosa buona e giusta, oltre naturalmente a vari altri illuminanti esempi d'utilizzo.
&lt;/p&gt;

&lt;h2&gt;Conclusioni&lt;/h2&gt;

&lt;p&gt;
Questo &amp;egrave; un articolo breve (un pregio, direte voi): ho probabilmente tralasciato molti aspetti di &lt;tt&gt;autobox&lt;/tt&gt; che meriterebbero di essere approfonditi. 
&lt;/p&gt;
&lt;p&gt;
Un avvertimento per&amp;ograve; &amp;egrave; doveroso: l'utilizzo di &lt;tt&gt;autobox&lt;/tt&gt; influisce sulle prestazioni! Non ho fatto personalmente &lt;i&gt;benchmark&lt;/i&gt;,  ma sicuramente le chiamate a metodi sono costose. Soprattutto se applicate a strutture dati molto corpose (ad esempio, array con svariate decine di migliaia di elementi).
&lt;/p&gt;
&lt;p&gt;
Quello che apprezzo di pi&amp;ugrave; di &lt;tt&gt;autobox&lt;/tt&gt; &amp;egrave; la &lt;i&gt;discrezione&lt;/i&gt;. Quel che aggiunge al linguaggio non &amp;egrave; poca cosa: sar&amp;agrave; simulazione quanto volete, ma di fatto il modulo regala al Perl ci&amp;ograve; di cui moltri altri linguaggi - dinamici e non - si vantano: &lt;i&gt;everything is an object&lt;/i&gt;.
&lt;/p&gt;
&lt;p&gt;
E nonostante questo, non siete assolutamente &lt;i&gt;forzati&lt;/i&gt; a utilizzare le parole chiave del Perl come fossero metodi. Anzi, potete scegliere caso per caso: nello stesso programma possono convivere pacificamente costrutti tradizionali e spericolati viaggi ai confini della sintassi. &lt;tt&gt;autobox&lt;/tt&gt; non pesta i piedi a nessuno, e lo amo per questo.
&lt;/p&gt;
&lt;p&gt;
Non so dire se &lt;tt&gt;autobox&lt;/tt&gt; sia un gran passo avanti per l'umanit&amp;agrave; o un piccolo passo per il Perl (che lo avvicina - idealmente - al Perl6). Come ho gi&amp;agrave; accennato, non l'ho utilizzato in maniera estensiva, ma quel poco che ho visto mi ha divertito molto e volevo condividerlo. Spero lo troviate divertente anche voi :-)
&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ArticoliPerlIt?a=gJ5bjxMiVJ0:aCn2spDLSdc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ArticoliPerlIt?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ArticoliPerlIt?a=gJ5bjxMiVJ0:aCn2spDLSdc:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ArticoliPerlIt?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
<dc:subject>article</dc:subject>
<dc:creator>dada</dc:creator>
<dc:date>2009-07-25T15:27:28+02:00</dc:date>
</item>

<item rdf:about="http://www.perl.it/documenti/articoli/2008/11/mettiamoli-a-co.html">
<title>Mettiamoli a confronto</title>
<link>http://www.perl.it/documenti/articoli/2008/11/mettiamoli-a-co.html</link>
<description>&lt;p&gt;Perl offre un supporto alla manipolazione degli array molto comodo: possiamo allungarli ed accorciarli a nostro piacimento a run-time senza preoccuparci di troppe cose, crearli in svariate maniere, ciclarci sopra in modi diversi... Ma avete mai provato a confrontare una coppia di array?&lt;/p&gt;

&lt;p&gt;In questo articolo cercheremo di approfondire alcune nostre conoscenze sulle operazioni possibili su una coppia di array, infatti in taluni casi pu&amp;ograve; esser molto utile confrontare due collezioni di dati per vedere dove e in cosa differiscono. Ci viene in aiuto per questi compiti il comodissimo Array::Compare.&lt;/p&gt;

&lt;p&gt;Facciamo subito un piccolo esempio: creiamo due array che contengono i numeri da 0 a 10&lt;/p&gt;

&lt;pre&gt;
my @arr1 = 0 .. 10;
my @arr2 = 0 .. 10;
&lt;/pre&gt;

&lt;p&gt;istanziamo un oggetto della classe Array::Compare tramite il costruttore new&lt;/p&gt;

&lt;pre&gt;
my $comp = Array::Compare-&gt;new;
&lt;/pre&gt;

&lt;p&gt;su questo oggetto andiamo a chiamare il metodo 'compare', che accetta due riferimenti ad array e restituisce - ci credereste - vero o falso a seconda dell'esito del confronto:&lt;/p&gt;

&lt;pre&gt;
if ($comp-&gt;compare(\@arr1, \@arr2)) {
  print "Array identici\n";
} else {
  print "Array differenti\n";
}
&lt;/pre&gt;

&lt;p&gt;Ma come fa il nostro modulo a far tutto ci&amp;ograve;? Internamente quello che viene fatto per confrontare i due array non &amp;egrave; nient'altro che un join tra tutti gli elementi di ciascun array: questo "trasforma" i due array in altrettante stringhe che poi vengono confrontate con 'eq'. Il separatore interposto tra ciascun elemento dell'array dalla funzione join sono i caratteri "^G" che potrebbero portare a dei problemi se fossero presenti tra gli elementi dei vostri array. Diamo un'occhiata a questi due array:&lt;/p&gt;

&lt;pre&gt;
my @array1 = ('ciao^G', 'ola', 'hello', 'bueno');
my @array2 = ('ciao', '^Gola', 'hello', 'bueno');
&lt;/pre&gt;

&lt;p&gt;all'apparenza sembrerebbero diversi, ma per il motivo detto sopra il nostro comparatore cade nel tranello e crea due stringhe cos&amp;igrave;:&lt;/p&gt;

&lt;pre&gt;
$stringa1 = 'ciao^G^Gola^Ghello^Gbueno';
$stringa2 = 'ciao^G^Gola^Ghello^Gbueno';
&lt;/pre&gt;

&lt;p&gt;per cui quando va a confrontarle, per lui sono uguali e ci dice che gli array hanno gli stessi elementi! Per aggirare questo problema &amp;egrave; possibile ridefinire il separatore andando a passare al costruttore dell'oggetto (quindi mentre si sta instanziando l'oggetto stesso) il parametro 'Sep':&lt;/p&gt;

&lt;pre&gt;
my $comp = Array::Compare-&gt;new(Sep =&gt; '|');
&lt;/pre&gt;

&lt;p&gt;oppure possiamo anche cambiare il separatore su un oggetto che abbiamo precedentemente creato:&lt;/p&gt;

&lt;pre&gt;
$comp-&gt;Sep('|');
&lt;/pre&gt;

&lt;p&gt;&amp;Egrave; ovvio che conviene scegliere un separatore che non compare nei nostri dati; se non si &amp;egrave; certi se si ha o meno quel separatore nell'array si potrebbe pensare di utilizzare la funzione any contenuta nel package List::Moreutils in questo modo:&lt;/p&gt;

&lt;pre&gt;
print "cambia separatore!" if any { m/mioseparatore/ } @arr1;
&lt;/pre&gt;

&lt;p&gt;in maniera tale da fare un controllo al volo ed esser certi di non cadere in tranelli subdoli.&lt;/p&gt;

&lt;p&gt;Possiamo anche controllare se gli spazi devono esser significativi per il nostro confronto, ricorrendo al metodo WhiteSpace(). Di default tutti gli spazi sono significativi, in alternativa si pu&amp;ograve; far in modo che pi&amp;ugrave; spazi consecutivi vengano convertiti in un solo spazio passando al costruttore il seguente parametro:&lt;/p&gt;

&lt;pre&gt;
my $comp = Array::Compare-&gt;new(WhiteSpace =&gt; 0);
&lt;/pre&gt;

&lt;p&gt;oppure come al solito:&lt;/p&gt;

&lt;pre&gt;
$comp-&gt;WhiteSpace(0);
&lt;/pre&gt;

&lt;p&gt;La stessa identica cosa pu&amp;ograve; esser fatta per rendere il confronto case sensitive o meno passando al costruttore l'opzione "Case":&lt;/p&gt;

&lt;pre&gt;
my $comp = Array::Compare-&gt;new(Case =&gt; 0);
&lt;/pre&gt;

&lt;p&gt;l'altro modo non ve lo scrivo tanto l'avete gi&amp;agrave; capito... Fino a qui &amp;egrave; un modulino carino che fa qualche cosina che alla fin fine ci saremmo potuti scrivere in qualche riga anche noi, vero? Questo modulo per&amp;ograve; ci permette di fare qualcosa di pi&amp;ugrave; potente con poco sforzo, tipo confrontare due array ed avere una lista degli indici che differiscono. Questo tipo di confronto &amp;egrave; detto "confronto completo" ed in contesto scalare restituisce la lunghezza della lista di elementi che differiscono. Vediamo un piccolo esempio:&lt;/p&gt;

&lt;pre&gt;  
my @verdura_da_comprare = qw( zucchine pomodori asparagi insalata );
my @verdura_comprata = qw( zucchine melanzane peperoni insalata );

&lt;p&gt;my $comp = Array::Compare-&gt;new(DefFull =&gt; 1);&lt;/p&gt;

&lt;p&gt;my @lista_sbadato = $comp-&gt;compare(\@verdura_da_comprare, \@verdura_comprata);&lt;/p&gt;

&lt;p&gt;print "Ho comprato $verdura_comprata[$_] anziche' $verdura_da_comprare[$_]\n" for (@lista_sbadato);&lt;br /&gt;
&lt;/pre&gt;&lt;/p&gt;

&lt;p&gt;In questo frammento di codice andiamo a confrontare due array che contengono ci&amp;ograve; che volevamo comprare al banco di frutta e verdura e ci&amp;ograve; che invece abbiamo poi comprato perch&amp;eacute; ci siamo dimenticati la lista della spesa a casa. In @lista_sbadato abbiamo la lista degli indici i cui relativi elementi differiscono nel confronto e la utilizziamo comodamente per stampare gli elementi incriminati dei due array.&lt;/p&gt;

&lt;p&gt;Dato che il modulo rispetta a pieno la filosofia Perl, c'&amp;egrave; anche un altro modo per fare questa cosa, chiamando direttamente la funzione "full_compare":&lt;/p&gt;

&lt;pre&gt;
$comp-&gt;full_compare(\@arr1, \@arr2);
&lt;/pre&gt;

&lt;p&gt;per simmetria si pu&amp;ograve; invocare anche il confronto semplice in questo modo:&lt;/p&gt;

&lt;pre&gt;
$comp-&gt;simple_compare(\@arr1, \@arr2);
&lt;/pre&gt;

&lt;p&gt;Abbiamo un po' di verdura in pentola, siamo partiti dal semplice confronto e ora abbiamo gi&amp;agrave; un bel po' di opzioni per poter estrarre al volo molte informazioni sui nostri array. Andiamo avanti! Avete mai pensato di confrontare il podio delle gare di motociclismo? Quello della seconda fila si sta facendo una risata perch&amp;eacute; dice: "Cosa ti vuoi confrontare... vince sempre Valentino!". Beh, l'obiezione &amp;egrave; buona ma noi partendo dal presupposto che nelle due gare in esame abbia vinto sempre Valentino, vogliamo confrontare i secondi e terzi posti. Possiamo indicare al nostro modulo di fregarsene del contenuto del primo elemento di ciascun array e andare a vedere se gli altri due sono uguali:&lt;/p&gt;

&lt;pre&gt;
my %skip = (1 =&gt; 1); #il primo &amp;egrave; sempre lo stesso

&lt;p&gt;my @mugello = ('valentino','max','loris');&lt;br /&gt;
my @brno = ('valentino','loris','max');&lt;br /&gt;
&lt;/pre&gt;&lt;/p&gt;

&lt;p&gt;Ora confrontiamo questi due podi del motomondiale:&lt;/p&gt;

&lt;pre&gt;
my $podio = Array::Compare-&gt;new(Skip =&gt; \%skip);
$podio-&gt;compare(\@mugello, \@brno);
&lt;/pre&gt;
 
Ovviamente ci restituir&amp;agrave; falso (in contesto booleano) perch&amp;eacute; si vede subito che non sono uguali ma possiamo notare che i piloti che stanno sul podio sono stati gli stessi!! Non vi stuzzica neanche un po' questa cosa? Beh lo sviluppatore del modulo c'aveva pensato: possiamo facilmente controllare se un array &amp;egrave; la permutazione di un altro, cio&amp;egrave; contiene gli stessi elementi ma in ordine diverso:

&lt;pre&gt;
if ($podio-&gt;perm(\@mugello, \@brno) {
  print "Stesse persone sul podio\n";
} else {
  print "No. Sul podio ci sono andate persone diverse\n";
}
&lt;/pre&gt;

&lt;p&gt;Per resettare il comparatore in maniera tale da non far saltare alcun elemento nell'array possiamo usare:&lt;/p&gt;

&lt;pre&gt;
$podio-&gt;Skip({});
&lt;/pre&gt;

&lt;p&gt;A dire il vero il discorso su quali elementi saltare nel confronto di due array pu&amp;ograve; anche esser ribaltato vedendolo cos&amp;igrave;: dico al comparatore di ignorare degli elementi che sicuramente so esser diversi, ed andare cos&amp;igrave; a controllare se gli altri differiscono.&lt;/p&gt;

&lt;p&gt;Cala il sipario siori e siore ma io ho ancora qualcosa da suggerirvi e cio&amp;egrave; qualche modulo che potete andare a sbirciare e che pu&amp;ograve; tornarvi utile quando avete a che fare con array e liste:&lt;/p&gt;

&lt;p&gt;* List::Util &lt;-- una selezione di utility per liste e array.&lt;/p&gt;

&lt;p&gt;* List::Moreutils &lt;-- tutto ci&amp;ograve; che volevate in List::Util ma che il suo autore si è "ostinatamente" rifiutato di includere :D&lt;/p&gt;

&lt;p&gt;* Tie::File &lt;-- associa le linee di un file con gli elementi di un array, &amp;egrave; un modulo comodissimo, un'occhiata &amp;egrave; obbligatoria.&lt;/p&gt;

&lt;h2&gt;Pecche :-(&lt;/h2&gt;

&lt;p&gt;Se alla fine di questo articolo vi state domandando se sia possibile confrontare array multilivello, siete molto arguti ed avete scovato la falla di questo modulo. Purtroppo il confronto di strutture pi&amp;ugrave; complicate di un array non &amp;egrave; effettuabile tramite questo modulo, vi segnalo qualcosa che potr&amp;agrave; esservi utile per assolvere questo compito:&lt;/p&gt;

&lt;p&gt;* Data::Compare - compara strutture dati Perl&lt;/p&gt;

&lt;p&gt;Questo modulo non vi permette per&amp;ograve; tutte le opzioni con le quali potevate controllare il confronto su due array come con Array::Compare.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ArticoliPerlIt?a=3qJAm3ykuP4:HF8fmV5PqbM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ArticoliPerlIt?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ArticoliPerlIt?a=3qJAm3ykuP4:HF8fmV5PqbM:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ArticoliPerlIt?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
<dc:subject>article</dc:subject>
<dc:creator>guest</dc:creator>
<dc:date>2008-11-06T11:07:58+02:00</dc:date>
</item>

<item rdf:about="http://www.perl.it/documenti/articoli/2008/07/la-guida-di-bri.html">
<title>La guida di brian</title>
<link>http://www.perl.it/documenti/articoli/2008/07/la-guida-di-bri.html</link>
<description>&lt;ul&gt;

	&lt;li&gt;&lt;a href="#nome"&gt;NOME&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="#riassunto"&gt;RIASSUNTO&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="#descrizione"&gt;DESCRIZIONE&lt;/a&gt;&lt;/li&gt;
	&lt;ul&gt;

		&lt;li&gt;&lt;a href="#la_mia_filosofia_di_debugging"&gt;La mia filosofia di debugging&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href="#il_mio_metodo"&gt;Il mio metodo&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;

	&lt;li&gt;&lt;a href="#autore"&gt;AUTORE&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="#traduzione"&gt;TRADUZIONE&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="#copyright"&gt;COPYRIGHT&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;hr name="index" /&gt;

&lt;!-- INDEX END --&gt;

&lt;h1&gt;&lt;a name="nome"&gt;NOME&lt;/a&gt;&lt;/h1&gt;
La guida di brian per la risoluzione di qualsiasi problema sul Perl

&lt;hr /&gt;
&lt;h1&gt;&lt;a name="riassunto"&gt;RIASSUNTO&lt;/a&gt;&lt;/h1&gt;
Seguite questa guida e evitate di impazzire


&lt;hr /&gt;
&lt;h1&gt;&lt;a name="descrizione"&gt;DESCRIZIONE&lt;/a&gt;&lt;/h1&gt;


&lt;h2&gt;&lt;a name="la_mia_filosofia_di_debugging"&gt;La mia filosofia di debugging&lt;/a&gt;&lt;/h2&gt;
Io credo in tre cose:
&lt;br /&gt;
&lt;br /&gt;&lt;strong&gt;&lt;a name="non_una_cosa_personale" class="item"&gt;Non &amp;egrave; una cosa personale&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
Dimenticati la propriet&amp;agrave; del codice. Puoi pensare a te stesso come ad un artista, ma anche i grandi Maestri hanno prodotto un sacco di schifezze.  Il codice di chiunque &amp;egrave; una schifezza, il che significa che il mio codice &amp;egrave; una schifezza e il tuo codice &amp;egrave; una schifezza. Impara ad apprezzare questo fatto. Quando hai un problema, il tuo primo pensiero dovrebbe essere &amp;quot;C'&amp;egrave; qualcosa che non va nel mio schifoso codice&amp;quot;. Questo significa che non devi prendertela con &lt;code&gt;perl&lt;/code&gt;. Non &amp;egrave; una cosa personale.
&lt;br /&gt;
Scordati di come &lt;strong&gt;tu&lt;/strong&gt; fai le cose. Se il tuo modo di fare le cose
funzionasse, non staresti qui a leggere. Non &amp;egrave; neppure una
brutta cosa: &amp;egrave; semplicemente tempo di progredire. Ci siamo
passati tutti.
&lt;br /&gt;
&lt;br /&gt;&lt;strong&gt;&lt;a name="responsabilit_personale" class="item"&gt;Responsabilit&amp;agrave; personale&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
Se hai un problema con il tuo script, &amp;egrave; proprio questo: un tuo
problema.  Dovresti fare tutto il possibile per risolverlo da
solo. Ricorda, ognuno ha i propri script, il che significa che ognuno
ha i propri problemi. Svolgi i tuoi compiti per casa e fai del tuo
meglio prima di dare fastidio a qualcun altro con i tuoi problemi. Se
hai davvero provato tutto quello che &amp;egrave; scritto in questa guida
e non riesci ancora a risolvere il problema, hai fatto del tuo meglio
ed &amp;egrave; ora di dare fastidio a qualcun altro.
&lt;br /&gt;
&lt;br /&gt;&lt;strong&gt;&lt;a name="cambia_il_modo_in_cui_fai_le_cose" class="item"&gt;Cambia il modo in cui fai le cose&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
Risolvi le cose in modo da non avere di nuovo lo stesso problema. Il
problema sta probabilmente in &lt;strong&gt;come&lt;/strong&gt; scrivi il codice, non in &lt;strong&gt;cosa&lt;/strong&gt;
scrivi. Cambia il modo in cui fai le cose, in modo da semplificati la
vita. Non forzare Perl ad adattarsi a te stesso, perch&amp;eacute; non si
adatter&amp;agrave;. Adattati tu a Perl. &amp;Egrave; solo un linguaggio,
non uno stile di vita.
&lt;br /&gt;
&lt;h2&gt;&lt;a name="il_mio_metodo"&gt;Il mio metodo&lt;/a&gt;&lt;/h2&gt;
&lt;strong&gt;&lt;a name="il_tuo_script_compila_usando_i_controlli_sintattici" class="item"&gt;Il tuo script compila usando i controlli sintattici?&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
Se non stai ancora usando i controlli sintattici, attivali. I guru del
Perl sono tali perch&amp;eacute; usano &lt;code&gt;strict&lt;/code&gt;, che lascia loro molto
pi&amp;ugrave; tempo per risolvere altri problemi, imparare cose nuove e
inserire moduli funzionanti in CPAN.
&lt;br /&gt;
Puoi attivare i controlli sintattici all'interno del codice con la direttiva
&lt;code&gt;strict&lt;/code&gt;.
&lt;br /&gt;
&lt;pre&gt;
        &lt;span class="keyword"&gt;use&lt;/span&gt; &lt;span class="variable"&gt;strict&lt;/span&gt;&lt;span class="operator"&gt;;&lt;/span&gt;
&lt;/pre&gt;
&lt;br /&gt;
Da linea di comando, puoi attivare i controlli sintattici con il
parametro &lt;code&gt;-M&lt;/code&gt; a &lt;code&gt;perl&lt;/code&gt;.
&lt;br /&gt;
&lt;pre&gt;
        perl -Mstrict script.pl&lt;/pre&gt;
&lt;br /&gt;
Potresti essere infastidito dai controlli sintattici, ma dopo un paio
di settimane di programmazione con i controlli attivi, scriverai del
codice migliore, perderai meno tempo a rincorrere dei semplici errori,
e probabilmente non avrai bisogno di questa guida.
&lt;br /&gt;
&lt;br /&gt;&lt;strong&gt;&lt;a name="cosa_sono_gli_avvertimenti" class="item"&gt;Cosa sono gli avvertimenti?&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
Perl pu&amp;ograve; darti un sacco di avvertimenti sui costrutti
discutibili. Attiva gli avvertimenti e lascia che Perl ti aiuti.
&lt;br /&gt;
Puoi usare il parametro &lt;code&gt;-w&lt;/code&gt; nella shebang.
&lt;br /&gt;
&lt;pre&gt;
        &lt;span class="comment"&gt;#!/usr/bin/perl -w&lt;/span&gt;
&lt;/pre&gt;
&lt;br /&gt;
Puoi attivare gli avvertimenti dalla linea di comando.
&lt;br /&gt;
&lt;pre&gt;
        perl -w script.pl&lt;/pre&gt;
&lt;br /&gt;
Puoi usare gli avvertimenti lessicali con tutta una serie di
caratteristiche interessanti. Dai un'occhiata a &lt;em&gt;warnings&lt;/em&gt; per i
dettagli.
&lt;br /&gt;
&lt;pre&gt;
        &lt;span class="keyword"&gt;use&lt;/span&gt; &lt;span class="variable"&gt;warnings&lt;/span&gt;&lt;span class="operator"&gt;;&lt;/span&gt;
&lt;/pre&gt;
&lt;br /&gt;
Se non capisci un avvertimento, puoi cercarne una versione esplicativa
in &lt;em&gt;perldiag&lt;/em&gt;, oppure puoi usare la direttiva &lt;code&gt;diagnostics&lt;/code&gt; nel
codice.
&lt;br /&gt;
&lt;pre&gt;
        &lt;span class="keyword"&gt;use&lt;/span&gt; &lt;span class="variable"&gt;diagnostics&lt;/span&gt;&lt;span class="operator"&gt;;&lt;/span&gt;
&lt;/pre&gt;
&lt;br /&gt;&lt;strong&gt;&lt;a name="risolvi_il_primo_problema_per_primo" class="item"&gt;Risolvi il primo problema per primo!&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
Dopo aver ottenuto da &lt;code&gt;perl&lt;/code&gt; un errore o un messaggio di
avvertimento, risolvi il primo messaggio e poi vedi se &lt;code&gt;perl&lt;/code&gt;
continua a lamentarsi. Gli ulteriori messaggi potrebbero essere stati
conseguenze del primo problema.
&lt;br /&gt;
&lt;br /&gt;&lt;strong&gt;&lt;a name="guarda_il_codice_prima_del_numero_di_linea_nel_messaggio_d_errore" class="item"&gt;Guarda il codice prima del numero di linea nel messaggio d'errore!&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;perl&lt;/code&gt; ti fornisce dei messaggi d'avvertimento nel momento in cui
inizia a preoccuparsi, non prima. Al momento in cui &lt;code&gt;perl&lt;/code&gt; &amp;egrave;
preoccupato, il problema &amp;egrave; gi&amp;agrave; capitato e il numero di
linea di cui &lt;code&gt;perl&lt;/code&gt; si sta occupando sta in realt&amp;agrave; &lt;strong&gt;dopo&lt;/strong&gt;
il problema. Dai un'occhiata un paio di espressioni prima del numero
di linea dell'avvertimento.
&lt;br /&gt;
&lt;br /&gt;&lt;strong&gt;&lt;a name="il_valore_quello_che_tu_pensi_che_sia" class="item"&gt;Il valore &amp;egrave; quello che tu pensi che sia?&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
Non tirare ad indovinare! Esamina davvero il valore, subito prima di
usarlo in una espressione. Il migliore debugger dell'universo
&amp;egrave; &lt;code&gt;print&lt;/code&gt;.
&lt;br /&gt;
&lt;pre&gt;
        &lt;span class="keyword"&gt;print&lt;/span&gt; &lt;span class="variable"&gt;STDERR&lt;/span&gt; &lt;span class="string"&gt;"Il valore e` [$valore]\n"&lt;/span&gt;&lt;span class="operator"&gt;;&lt;/span&gt;
&lt;/pre&gt;
&lt;br /&gt;
Ho racchiuso &lt;code&gt;$valore&lt;/code&gt; tra parentesi in maniera da poter vedere
eventuali spazi o a capo all'inizio o alla fine del valore.
&lt;br /&gt;
Se ho a che fare con qualcosa di diverso da uno scalare, uso
&lt;code&gt;Data::Dumper&lt;/code&gt; per stampare le strutture dati.
&lt;br /&gt;
&lt;pre&gt;
        &lt;span class="keyword"&gt;require&lt;/span&gt; &lt;span class="variable"&gt;Data::Dumper&lt;/span&gt;&lt;span class="operator"&gt;;&lt;/span&gt;
&lt;/pre&gt;
&lt;br /&gt;
&lt;pre&gt;
        &lt;span class="keyword"&gt;print&lt;/span&gt; &lt;span class="variable"&gt;STDERR&lt;/span&gt; &lt;span class="string"&gt;"L'hash e` "&lt;/span&gt;&lt;span class="operator"&gt;,&lt;/span&gt; &lt;span class="variable"&gt;Data::Dumper::Dumper&lt;/span&gt;&lt;span class="operator"&gt;(&lt;/span&gt; &lt;span class="variable"&gt;%hash&lt;/span&gt; &lt;span class="operator"&gt;),&lt;/span&gt; &lt;span class="string"&gt;"\n"&lt;/span&gt;&lt;span class="operator"&gt;;&lt;/span&gt;
&lt;/pre&gt;
&lt;br /&gt;
Se il valore non &amp;egrave; quello che pensi sia, torna indietro di
qualche passo e prova di nuovo! Fai cos&amp;igrave; fino a che non trovi
il punto nel quale il valore smette di essere quello che pensi
dovrebbe essere!
&lt;br /&gt;
Puoi anche usare il debugger integrato in &lt;code&gt;perl&lt;/code&gt;, tramite il
parametro &lt;code&gt;-d&lt;/code&gt;.  Studia &lt;em&gt;perldebug&lt;/em&gt; per i dettagli.
&lt;br /&gt;
&lt;pre&gt;
        perl -d script.pl&lt;/pre&gt;
&lt;br /&gt;
Puoi anche utilizzare altri debugger o ambienti di sviluppo, come
&lt;code&gt;ptkdb&lt;/code&gt; (un debugger grafico basato su &lt;code&gt;Tk&lt;/code&gt;) oppure Komodo (l'IDE
Perl di Activestate basato su Mozilla).
&lt;br /&gt;
&lt;br /&gt;&lt;strong&gt;&lt;a name="stai_usando_la_funzione_in_maniera_corretta" class="item"&gt;Stai usando la funzione in maniera corretta?&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
Programmo in Perl da un sacco di tempo e consulto ancora &lt;em&gt;perlfunc&lt;/em&gt;
quasi tutti i giorni. Alcune cose non riesco proprio a memorizzarle, e
qualche volta ho cos&amp;igrave; tanto sonno arretrato che il cervello se
ne va in vacanza, e mi domando come mai &lt;code&gt;sprintf()&lt;/code&gt; non stampi a
schermo.
&lt;br /&gt;
Puoi cercare una particolare funzione con il comando &lt;code&gt;perldoc&lt;/code&gt; e il suo
parametro &lt;code&gt;-f&lt;/code&gt;.
&lt;br /&gt;
&lt;pre&gt;
        perldoc -f nome_funzione&lt;/pre&gt;
&lt;br /&gt;
Se stai usando un modulo, controlla la documentazione per assicurarti
di usarlo nel modo giusto. Puoi controllare la documentazione del
modulo usando &lt;code&gt;perldoc&lt;/code&gt;.
&lt;br /&gt;
&lt;pre&gt;
        perldoc Nome::Modulo
&lt;/pre&gt;
&lt;br /&gt;&lt;strong&gt;&lt;a name="stai_usando_la_variabile_speciale_giusto" class="item"&gt;Stai usando la  variabile speciale giusta?&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
Di nuovo, io faccio continuamente riferimento a &lt;em&gt;perlvar&lt;/em&gt;. Beh, non
proprio, visto che trovo &lt;em&gt;The Perl Pocket Reference&lt;/em&gt; molto
pi&amp;ugrave; facile da usare.
&lt;br /&gt;
&lt;br /&gt;&lt;strong&gt;&lt;a name="hai_la_versione_giusta_del_modulo" class="item"&gt;Hai la versione giusta del modulo?&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
Alcuni moduli cambiano il loro comportamento da una versione
all'altra. Hai la versione del modulo che pensi di avere? Puoi
controllare la versione della maggior parte dei moduli con una semplice
riga di &lt;code&gt;perl&lt;/code&gt;.
&lt;br /&gt;
&lt;pre&gt;
        &lt;span class="variable"&gt;perl&lt;/span&gt; &lt;span class="operator"&gt;-&lt;/span&gt;&lt;span class="variable"&gt;MNome::Modulo&lt;/span&gt; &lt;span class="operator"&gt;-&lt;/span&gt;&lt;span class="keyword"&gt;le&lt;/span&gt; &lt;span class="string"&gt;'print Nome::Modulo-&amp;gt;VERSION'&lt;/span&gt;&lt;span class="operator"&gt;;&lt;/span&gt;
&lt;/pre&gt;
&lt;br /&gt;Se consulti la maggior parte della tua documentazione sul web, ad
esempio su &lt;a href="http://www.perldoc.com"&gt;http://www.perldoc.com&lt;/a&gt; oppure &lt;a href="http://search.cpan.org,"&gt;http://search.cpan.org,&lt;/a&gt;
invece che leggere quella che hai sulla tua macchina, &amp;egrave;
pi&amp;ugrave; facile che tu finisca per leggere la documentazione di una
versione diversa da quella che hai.
&lt;br /&gt;
&lt;br /&gt;&lt;strong&gt;&lt;a name="hai_scritto_dei_piccoli_test" class="item"&gt;Hai scritto dei piccoli test?&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
Se stai sperimentando qualcosa di nuovo, o se pensi che una
particolare porzione di codice si stia comportando in maniera
bizzarra, scrivi il programma pi&amp;ugrave; breve possibile che
implementi quella porzione e nient'altro. Questo toglie di mezzo la
maggior parte dei fattori irrilevanti. Se questo breve programma di
test fa quello che pensi debba fare, probabilmente il problema non sta
in quel codice. Se il programma non fa quello che pensi debba fare,
forse hai trovato il problema.
&lt;br /&gt;
&lt;br /&gt;&lt;strong&gt;&lt;a name="hai_controllato_l_ambiente" class="item"&gt;Hai controllato l'ambiente?&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
Alcune cose dipendono dalle variabili d'ambiente. Sei sicuro che siano
impostate con i valori giusti? Il tuo ambiente &amp;egrave; lo stesso che
il programma vede quando &amp;egrave; in esecuzione? Ricordati che i
programmi eseguiti via CGI o cron, possono vedere ambienti differenti
rispetto a quelli eseguiti nella tua shell, specialmente su altre
macchine.
&lt;br /&gt;
Perl mette a disposizione l'ambiente tramite &lt;code&gt;%ENV&lt;/code&gt;. Se hai
bisogno di una di queste variabili, fornisci un valore di default per
quando non esiste, anche solo a scopo di test.
&lt;br /&gt;
Se hai ancora qualche problema, esamina l'ambiente.
&lt;br /&gt;
&lt;pre&gt;
        &lt;span class="keyword"&gt;require&lt;/span&gt; &lt;span class="variable"&gt;Data::Dumper&lt;/span&gt;&lt;span class="operator"&gt;;&lt;/span&gt;
        &lt;span class="keyword"&gt;print&lt;/span&gt; &lt;span class="variable"&gt;STDERR&lt;/span&gt; &lt;span class="variable"&gt;Data::Dumper::Dumper&lt;/span&gt;&lt;span class="operator"&gt;(&lt;/span&gt; &lt;span class="operator"&gt;\&lt;/span&gt;&lt;span class="variable"&gt;%ENV&lt;/span&gt; &lt;span class="operator"&gt;);&lt;/span&gt;
&lt;/pre&gt;
&lt;br /&gt;&lt;strong&gt;&lt;a name="hai_controllato_google" class="item"&gt;Hai controllato Google?&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
Se hai un problema, probabilmente qualcun altro l'ha gi&amp;agrave;
avuto. Controlla se qualcuno ha gi&amp;agrave; pubblicato qualcosa su
usenet nel gruppo &lt;code&gt;comp.lang.perl.misc&lt;/code&gt;, tramite la ricerca con
Google Groups (&lt;a href="http://groups.google.com/"&gt;http://groups.google.com/&lt;/a&gt;). La differenza tra le
persone che fanno domande su usenet e quelle che rispondono, sta
nell'abilit&amp;agrave; di usare Google Groups.
&lt;br /&gt;
&lt;br /&gt;&lt;strong&gt;&lt;a name="hai_misurato_le_prestazioni_della_tua_applicazione" class="item"&gt;Hai misurato le prestazioni della tua applicazione?&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
Se vuoi scovare le parti lente del programma, ne hai misurato le
prestazioni?  Fai fare il lavoro pesante a
&lt;code&gt;Devel::SmallProf&lt;/code&gt;. &lt;code&gt;Devel::SmallProf&lt;/code&gt; conta le volte che &lt;code&gt;perl&lt;/code&gt;
esegue ciascuna linea di codice e quanto impiega ad eseguirla, e
stampa un bel resoconto.
&lt;br /&gt;
&lt;br /&gt;&lt;strong&gt;&lt;a name="quale_test_fallisce" class="item"&gt;Quale test fallisce?&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
Se hai una suite di test, qual'&amp;egrave; il test che fallisce?
Dovresti essere in grado di scovare l'errore molto velocemente, visto
che ogni test dovrebbe esercitare solo una piccola porzione di codice.
&lt;br /&gt;
Se non hai una suite di test, perch&amp;eacute; non farne una? Se hai uno
script davvero breve o si tratta di un uno script usa e getta, non ti
obbligo certo a scrivere un paio di test. In tutti gli altri casi, un
po' di script di test portano molti vantaggi. &lt;code&gt;Test::Harness&lt;/code&gt; rende
l'esecuzione dei test talmente semplice, che non hai proprio alcuna
scusa per non scriverli. Se non ne hai il tempo, forse stai sprecando
troppo tempo nel fare il debug degli script senza i test. &lt;code&gt;MakeMaker&lt;/code&gt;
e simili non sono solo per i moduli, si possono usare anche per gli
script.
&lt;br /&gt;
&lt;br /&gt;&lt;strong&gt;&lt;a name="hai_parlato_con_l_orsacchiotto" class="item"&gt;Hai parlato con l'orsacchiotto?&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
Spiega il tuo problema ad alta voce. Pronuncia davvero le parole.
&lt;br /&gt;
Per un paio d'anni ho avuto il piacere di lavorare con un
programmatore davvero bravo che riusciva a risolvere praticamente
qualsiasi cosa. Quando ero proprio bloccato, andavo alla sua scrivania
e iniziavo a spiegare il problema. Di solito non arrivavo alla terza
frase senza dire &amp;quot;Lascia perdere, ho capito&amp;quot;. Non si sbagliava quasi
mai.
&lt;br /&gt;
Visto che ti capiter&amp;agrave; piuttosto spesso, ti consiglio di
procurarti un qualche peluche che ti faccia da &amp;quot;psicanalista&amp;quot; Perl, in
modo da non disturbare i tuoi colleghi. Io ho un orsetto seduto sulla
mia scrivania, al quale spiego i miei problemi. La mia ragazza non fa
neppure pi&amp;ugrave; caso a quando parlo da solo.
&lt;br /&gt;
&lt;br /&gt;&lt;strong&gt;&lt;a name="il_problema_sembra_differente_sulla_carta" class="item"&gt;Il problema sembra differente sulla carta?&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
Stai guardando fisso il monitor del computer; magari un supporto
differente ti far&amp;agrave; vedere le cose in un una maniera
diversa. Prova a dare un'occhiata ad una stampa del tuo programma.
&lt;br /&gt;
&lt;br /&gt;&lt;strong&gt;&lt;a name="hai_guardato_il_quiz_quotidiano_con_gerri_scotti" class="item"&gt;Hai guardato il quiz quotidiano con Gerri Scotti?&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
Davvero. Se non vi piace Gerri Scotti, sceglietevi qualcos'altro. Fate
una pausa. Smettete di pensare al problema per un po' e lasciate che
la vostra mente si rilassi. Torna al problema pi&amp;ugrave; tardi, e la
sua risoluzione potrebbe essere immediatamente ovvia.
&lt;br /&gt;
&lt;br /&gt;&lt;strong&gt;&lt;a name="hai_cestinato_il_tuo_ego" class="item"&gt;Hai cestinato il tuo ego?&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
Se, arrivati a questo punto, non hai ancora risolto, il problema
potrebbe essere psicologico. Potresti essere emotivamente legato ad
una certa parte del codice, per cui non vuoi cambiarlo. Potresti anche
pensare che tutti abbiano torto tranne te. Ogni volta che pensi
qualcosa del genere, non stai prendendo seriamente in considerazione
la pi&amp;ugrave; probabile fonte di bug -- tu stesso. Non ignorare
nulla. Verifica tutto.
&lt;br /&gt;
&lt;br /&gt;
&lt;hr /&gt;
&lt;h1&gt;&lt;a name="autore"&gt;AUTORE&lt;/a&gt;&lt;/h1&gt;
brian d foy, &amp;lt;&lt;a href="mailto:bdfoy@cpan.org"&gt;bdfoy@cpan.org&lt;/a&gt;&amp;gt;
&lt;br /&gt;
&lt;hr /&gt;
&lt;h1&gt;&lt;a name="traduzione"&gt;TRADUZIONE&lt;/a&gt;&lt;/h1&gt;
Traduzione a cura del gruppo di www.perl.it
Originale disponibile presso &lt;a href="http://www.pair.com/~comdog/brian's_guide.pod"&gt;http://www.pair.com/~comdog/brian's_guide.pod&lt;/a&gt;
&lt;br /&gt;
&lt;hr /&gt;
&lt;h1&gt;&lt;a name="copyright"&gt;COPYRIGHT&lt;/a&gt;&lt;/h1&gt;
Copyright 2002, Perl Documentation Project, 
Tutti i diritti riservati&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ArticoliPerlIt?a=MB8bQv59SjU:uBdtztvW-L8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ArticoliPerlIt?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ArticoliPerlIt?a=MB8bQv59SjU:uBdtztvW-L8:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ArticoliPerlIt?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
<dc:subject>article</dc:subject>
<dc:creator>dree</dc:creator>
<dc:date>2008-07-25T17:41:05+02:00</dc:date>
</item>

<item rdf:about="http://www.perl.it/documenti/articoli/2008/06/redirezione.html">
<title>Redirezione</title>
<link>http://www.perl.it/documenti/articoli/2008/06/redirezione.html</link>
<description>&lt;p&gt;Capita a volte di voler redirigere l'output di un programma su un file, o
da qualche altra parte. Altre volte, invece, vorremmo che gli input
arrivassero da dove diciamo noi, invece che da dove il programma pensa
che stiano arrivando. A volte, infine, abbiamo bisogno che queste 
redirezioni siano temporanee, e dopo un po' vogliamo ``tornare indietro''.
Vediamo un po' come fare.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ArticoliPerlIt?a=IwdPqN98dXo:zzFPrcgkiqM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ArticoliPerlIt?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ArticoliPerlIt?a=IwdPqN98dXo:zzFPrcgkiqM:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ArticoliPerlIt?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
<dc:subject>article</dc:subject>
<dc:creator>polettix</dc:creator>
<dc:date>2008-06-21T20:57:12+02:00</dc:date>
</item>

<item rdf:about="http://www.perl.it/documenti/articoli/2008/06/dare-una-riordi.html">
<title>Dare una riordinata in Perl</title>
<link>http://www.perl.it/documenti/articoli/2008/06/dare-una-riordi.html</link>
<description>&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ArticoliPerlIt?a=5_e93sSKBOo:ZzBmui6mg-w:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ArticoliPerlIt?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ArticoliPerlIt?a=5_e93sSKBOo:ZzBmui6mg-w:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ArticoliPerlIt?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
<dc:subject>article</dc:subject>
<dc:creator>guest</dc:creator>
<dc:date>2008-06-05T12:25:36+02:00</dc:date>
</item>

<item rdf:about="http://www.perl.it/documenti/articoli/2008/02/dati-statici-di.html">
<title>Dati di classe in Perl</title>
<link>http://www.perl.it/documenti/articoli/2008/02/dati-statici-di.html</link>
<description>&lt;p&gt;Probabilmente, una delle cose più sorprendenti per chi proviene da altri linguaggi è la incredibile varietà di approcci all'object orientation che offre il Perl.&lt;br /&gt;
Come se non bastassero la libertà e flessibilità offerte dal linguaggio nel 'fai da te', esistono le soluzioni preconfezionate su &lt;span class="caps"&gt;CPAN, &lt;/span&gt;dalle più leggere e semplici a quelle più estese e complesse, dai metamodelli e class class generators (MOP, Moose) all'implementazione del Design By Contract (Class::Contract).&lt;br /&gt;
Anche per un perlista esperto, il numero di moduli dedicati all'OO su &lt;span class="caps"&gt;CPAN &lt;/span&gt;è qualcosa che lascia disorientati.&lt;/p&gt;

&lt;p&gt;In questo articolo voglio parlare di un aspetto dell'OO che in Perl è relativamente trascurato, o quantomeno che non ha trovato per me le soluzioni che avrei voluto. Si tratta dei dati di classe, detti anche dati statici. Persino in Programming Perl Third Edition § 12.8 si può leggere, "No matter how you roll it, package-relative class data is always a bit awkward.".&lt;br /&gt;
Come noto, questi dati sono condivisi da tutti gli oggetti della classe e servono tipicamente a mantenere uno stato globale, informazioni comuni, o tenere traccia di quello che la classe sta facendo.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ArticoliPerlIt?a=LTtH2aInbZg:LUix52uW38c:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ArticoliPerlIt?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ArticoliPerlIt?a=LTtH2aInbZg:LUix52uW38c:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ArticoliPerlIt?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
<dc:subject>article</dc:subject>
<dc:creator>guest</dc:creator>
<dc:date>2008-02-07T14:25:04+02:00</dc:date>
</item>

<item rdf:about="http://www.perl.it/documenti/articoli/2008/01/contextualretur-1.html">
<title>Contextual::Return - una recensione</title>
<link>http://www.perl.it/documenti/articoli/2008/01/contextualretur-1.html</link>
<description>&lt;p&gt;Per chi non lo conoscesse, Damian Conway &amp;egrave; uno dei punti di riferimento
nella comunit&amp;agrave; Perl: moduli, libri, conferenze... Una delle sue
ultime fatiche, &lt;em&gt;Perl Best Practices&lt;/em&gt;, riporta una serie di 256
raccomandazioni per migliorare il proprio modo di produrre codice.&lt;/p&gt;
&lt;p&gt;Una cosa che ho trovato interessante nel libro &amp;egrave; stata il fatto che,
in moltissime occasioni, sembra una promozione dei propri moduli
pubblicati su CPAN. Non so, m'&amp;egrave; sembrato un po' autocelebrativo,
ma se non si autocelebra Conway parlando di Perl... chi pu&amp;ograve; farlo?&lt;/p&gt;
&lt;p&gt;In una raccomandazione, in particolare, suggerisce di utilizzare
il modulo Contextual::Return, che permette di restituire, in uscita
da una funzione, valori differenti a seconda del &lt;em&gt;contesto&lt;/em&gt; in cui
la funzione viene chiamata.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ArticoliPerlIt?a=llQhefwrWGI:OA4yEuWqgHY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ArticoliPerlIt?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ArticoliPerlIt?a=llQhefwrWGI:OA4yEuWqgHY:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ArticoliPerlIt?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
<dc:subject>article</dc:subject>
<dc:creator>larsen</dc:creator>
<dc:date>2008-01-25T11:30:00+02:00</dc:date>
</item>

<item rdf:about="http://www.perl.it/documenti/articoli/2008/01/graylister-prov.html">
<title>Graylister - proviamo a fermare lo "SPAM"</title>
<link>http://www.perl.it/documenti/articoli/2008/01/graylister-prov.html</link>
<description>&lt;p&gt;&lt;style type="text/css"&gt;&lt;/p&gt;

&lt;p&gt;/*
:Author: David Goodger
:Contact: goodger@users.sourceforge.net
:Date: $Date: 2004/12/22 19:08:26 $
:Version: $Revision: 1.46 $
:Copyright: This stylesheet has been placed in the public domain.&lt;/p&gt;

&lt;p&gt;Default cascading style sheet for the HTML output of Docutils.
*/&lt;/p&gt;

&lt;p&gt;/* "! important" is used here to override other &lt;code&gt;margin-top&lt;/code&gt; and
   &lt;code&gt;margin-bottom&lt;/code&gt; styles that are later in the stylesheet or 
   more specific.  See &lt;a href="http://www.w3.org/TR/CSS1#the-cascade"&gt;http://www.w3.org/TR/CSS1#the-cascade&lt;/a&gt;. */
.first {
  margin-top: 0 ! important }&lt;/p&gt;

&lt;p&gt;.last {
  margin-bottom: 0 ! important }&lt;/p&gt;

&lt;p&gt;.hidden {
  display: none }&lt;/p&gt;

&lt;p&gt;a.toc-backref {
  text-decoration: none ;
  color: black }&lt;/p&gt;

&lt;p&gt;blockquote.epigraph {
  margin: 2em 5em ; }&lt;/p&gt;

&lt;p&gt;dl.docutils dd {
  margin-bottom: 0.5em }&lt;/p&gt;

&lt;p&gt;/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
  font-weight: bold }
*/&lt;/p&gt;

&lt;p&gt;div.abstract {
  margin: 2em 5em }&lt;/p&gt;

&lt;p&gt;div.abstract p.topic-title {
  font-weight: bold ;
  text-align: center }&lt;/p&gt;

&lt;p&gt;div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
  margin: 2em ;
  border: medium outset ;
  padding: 1em }&lt;/p&gt;

&lt;p&gt;div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
  font-weight: bold ;
  font-family: sans-serif }&lt;/p&gt;

&lt;p&gt;div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title {
  color: red ;
  font-weight: bold ;
  font-family: sans-serif }&lt;/p&gt;

&lt;p&gt;/* Uncomment (and remove this text!) to get reduced vertical space in
   compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
  margin-bottom: 0.5em }&lt;/p&gt;

&lt;p&gt;div.compound .compound-last, div.compound .compound-middle {
  margin-top: 0.5em }
*/&lt;/p&gt;

&lt;p&gt;div.dedication {
  margin: 2em 5em ;
  text-align: center ;
  font-style: italic }&lt;/p&gt;

&lt;p&gt;div.dedication p.topic-title {
  font-weight: bold ;
  font-style: normal }&lt;/p&gt;

&lt;p&gt;div.figure {
  margin-left: 2em }&lt;/p&gt;

&lt;p&gt;div.footer, div.header {
  font-size: smaller }&lt;/p&gt;

&lt;p&gt;div.line-block {
  display: block ;
  margin-top: 1em ;
  margin-bottom: 1em }&lt;/p&gt;

&lt;p&gt;div.line-block div.line-block {
  margin-top: 0 ;
  margin-bottom: 0 ;
  margin-left: 1.5em }&lt;/p&gt;

&lt;p&gt;div.sidebar {
  margin-left: 1em ;
  border: medium outset ;
  padding: 1em ;
  background-color: #ffffee ;
  width: 40% ;
  float: right ;
  clear: right }&lt;/p&gt;

&lt;p&gt;div.sidebar p.rubric {
  font-family: sans-serif ;
  font-size: medium }&lt;/p&gt;

&lt;p&gt;div.system-messages {
  margin: 5em }&lt;/p&gt;

&lt;p&gt;div.system-messages h1 {
  color: red }&lt;/p&gt;

&lt;p&gt;div.system-message {
  border: medium outset ;
  padding: 1em }&lt;/p&gt;

&lt;p&gt;div.system-message p.system-message-title {
  color: red ;
  font-weight: bold }&lt;/p&gt;

&lt;p&gt;div.topic {
  margin: 2em }&lt;/p&gt;

&lt;p&gt;h1.title {
  text-align: center }&lt;/p&gt;

&lt;p&gt;h2.subtitle {
  text-align: center }&lt;/p&gt;

&lt;p&gt;hr.docutils {
  width: 75% }&lt;/p&gt;

&lt;p&gt;ol.simple, ul.simple {
  margin-bottom: 1em }&lt;/p&gt;

&lt;p&gt;ol.arabic {
  list-style: decimal }&lt;/p&gt;

&lt;p&gt;ol.loweralpha {
  list-style: lower-alpha }&lt;/p&gt;

&lt;p&gt;ol.upperalpha {
  list-style: upper-alpha }&lt;/p&gt;

&lt;p&gt;ol.lowerroman {
  list-style: lower-roman }&lt;/p&gt;

&lt;p&gt;ol.upperroman {
  list-style: upper-roman }&lt;/p&gt;

&lt;p&gt;p.attribution {
  text-align: right ;
  margin-left: 50% }&lt;/p&gt;

&lt;p&gt;p.caption {
  font-style: italic }&lt;/p&gt;

&lt;p&gt;p.credits {
  font-style: italic ;
  font-size: smaller }&lt;/p&gt;

&lt;p&gt;p.label {
  white-space: nowrap }&lt;/p&gt;

&lt;p&gt;p.rubric {
  font-weight: bold ;
  font-size: larger ;
  color: maroon ;
  text-align: center }&lt;/p&gt;

&lt;p&gt;p.sidebar-title {
  font-family: sans-serif ;
  font-weight: bold ;
  font-size: larger }&lt;/p&gt;

&lt;p&gt;p.sidebar-subtitle {
  font-family: sans-serif ;
  font-weight: bold }&lt;/p&gt;

&lt;p&gt;p.topic-title {
  font-weight: bold }&lt;/p&gt;

&lt;p&gt;pre.address {
  margin-bottom: 0 ;
  margin-top: 0 ;
  font-family: serif ;
  font-size: 100% }&lt;/p&gt;

&lt;p&gt;pre.line-block {
  font-family: serif ;
  font-size: 100% }&lt;/p&gt;

&lt;p&gt;pre.literal-block, pre.doctest-block {
  margin-left: 2em ;
  margin-right: 2em ;
  background-color: #eeeeee }&lt;/p&gt;

&lt;p&gt;span.classifier {
  font-family: sans-serif ;
  font-style: oblique }&lt;/p&gt;

&lt;p&gt;span.classifier-delimiter {
  font-family: sans-serif ;
  font-weight: bold }&lt;/p&gt;

&lt;p&gt;span.interpreted {
  font-family: sans-serif }&lt;/p&gt;

&lt;p&gt;span.option {
  white-space: nowrap }&lt;/p&gt;

&lt;p&gt;span.option-argument {
  font-style: italic }&lt;/p&gt;

&lt;p&gt;span.pre {
  white-space: pre }&lt;/p&gt;

&lt;p&gt;span.problematic {
  color: red }&lt;/p&gt;

&lt;p&gt;table.citation {
  border-left: solid thin gray }&lt;/p&gt;

&lt;p&gt;table.docinfo {
  margin: 2em 4em }&lt;/p&gt;

&lt;p&gt;table.docutils {
  margin-top: 0.5em ;
  margin-bottom: 0.5em }&lt;/p&gt;

&lt;p&gt;table.footnote {
  border-left: solid thin black }&lt;/p&gt;

&lt;p&gt;table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
  padding-left: 0.5em ;
  padding-right: 0.5em ;
  vertical-align: top }&lt;/p&gt;

&lt;p&gt;th.docinfo-name, th.field-name {
  font-weight: bold ;
  text-align: left ;
  white-space: nowrap }&lt;/p&gt;

&lt;p&gt;h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
  font-size: 100% }&lt;/p&gt;

&lt;p&gt;tt.docutils {
  background-color: #eeeeee }&lt;/p&gt;

&lt;p&gt;ul.auto-toc {
  list-style-type: none }&lt;/p&gt;

&lt;p&gt;&lt;/style&gt;
&lt;div class="section" id="un-po-di-storia"&gt;&lt;/p&gt;

&lt;h1&gt;&lt;a name="un-po-di-storia"&gt;Un po' di storia&lt;/a&gt;&lt;/h1&gt;

&lt;p&gt;Non provo neppure a spiegare cosa si intende con &amp;quot;spam&amp;quot; parlando di
posta elettronica. Se non lo sapete, vuol dire che non avete usato la
posta elettronica negli ultimi &amp;lt;troppi&amp;gt; anni, per cui questo articolo
non vi interessa &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;:-)&lt;/span&gt;&lt;/tt&gt;.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ArticoliPerlIt?a=tYri7k0Ci-I:Tvc66MRNe2E:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ArticoliPerlIt?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ArticoliPerlIt?a=tYri7k0Ci-I:Tvc66MRNe2E:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ArticoliPerlIt?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
<dc:subject>article</dc:subject>
<dc:creator>dakkar</dc:creator>
<dc:date>2008-01-14T16:40:54+02:00</dc:date>
</item>

<item rdf:about="http://www.perl.it/documenti/articoli/2007/11/matrici-in-perl.html">
<title>Matrici in Perl</title>
<link>http://www.perl.it/documenti/articoli/2007/11/matrici-in-perl.html</link>
<description>&lt;!-- start doc --&gt;
&lt;a name='___top' class='dummyTopAnchor' &gt;&lt;/a&gt;
&lt;p&gt;Se uno d&amp;#224; un&amp;#39;occhiata rapida al manuale (in particolare perlvar), scopre un&amp;#39;interessante verit&amp;#224; circa i principali tipi di variabili in Perl:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;b&gt;&lt;a name="scalari" &gt;scalari&lt;/a&gt;&lt;/b&gt;: possono contenere un valore singolo, di varia natura (come un numero, o una stringa);&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;a name="array" &gt;array&lt;/a&gt;&lt;/b&gt;: sono delle collezioni ordinate di elementi - elementi &lt;i&gt;scalari&lt;/i&gt;;&lt;/li&gt; 
&lt;li&gt;&lt;b&gt;&lt;a name="hash" &gt;hash&lt;/a&gt;&lt;/b&gt;: sono delle associazioni fra stringhe (dette &lt;i&gt;chiavi&lt;/i&gt;) e valori, i quali sono, nuovamente, degli &lt;i&gt;scalari&lt;/i&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cos&amp;#236;, di primo acchito, verrebbe da dire che non ci sia molto per sbizzarrirsi.  O valori singoli, oppure insiemi che contengono valori singoli.  Ma allora una matrice come la rappresentiamo?!?  Come facciamo ad aggiungere dimensioni ad un semplice array?&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ArticoliPerlIt?a=RcSY1BbAnNo:x3txXtbHhMc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ArticoliPerlIt?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ArticoliPerlIt?a=RcSY1BbAnNo:x3txXtbHhMc:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ArticoliPerlIt?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
<dc:subject>article</dc:subject>
<dc:creator>jontk</dc:creator>
<dc:date>2007-11-05T10:42:13+02:00</dc:date>
</item>

<item rdf:about="http://www.perl.it/documenti/articoli/2007/09/gtk2-perl-e-dra.html">
<title>Gtk2, Perl e Drag&amp;Drop</title>
<link>http://www.perl.it/documenti/articoli/2007/09/gtk2-perl-e-dra.html</link>
<description>&lt;p&gt;Avevo bisogno di un modo semplice per tenere una coda di "cose da leggere". Mi capita spesso di trovare in rete dei riferimenti interessanti, ma di non avere tempo / modo di leggerli sul momento. Certo, ci sono i "bookmark", ma li sento un po' troppo permanenti (sì, uso un'applicazione web per gestirmi i bookmark in modo centralizzato, ma quello è materiale per un altro articolo).

Per cui ho pensato di avere un piccolo "riquadro" su cui trascinare delle URL, e ritrovarmele in una cartella del mio account di posta, da cui posso riprenderle con comodo, e cancellare dopo lette.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ArticoliPerlIt?a=b4EQm3B2qks:J0MVci3EdDU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ArticoliPerlIt?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ArticoliPerlIt?a=b4EQm3B2qks:J0MVci3EdDU:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ArticoliPerlIt?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
<dc:subject>article</dc:subject>
<dc:creator>dakkar</dc:creator>
<dc:date>2007-09-06T09:01:27+02:00</dc:date>
</item>

<item rdf:about="http://www.perl.it/documenti/articoli/2007/02/perl-template-t.html">
<title>Perl Template Toolkit</title>
<link>http://www.perl.it/documenti/articoli/2007/02/perl-template-t.html</link>
<description>&lt;p&gt;Tra gli sviluppatori Perl circola una battuta scherzosa secondo la quale una delle tappe fisse dello studio del linguaggio è la realizzazione di un sistema di templating fatto in casa. Sono certo che si tratta di una battuta diffusa anche presso altri gruppi di programmatori, per lo meno tra coloro che usano linguaggi adatti allo sviluppo di applicazioni web.&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ArticoliPerlIt?a=PkmRqKZ7uyQ:jfg_SCv9k3c:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ArticoliPerlIt?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ArticoliPerlIt?a=PkmRqKZ7uyQ:jfg_SCv9k3c:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ArticoliPerlIt?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
<dc:subject>article</dc:subject>
<dc:creator>larsen</dc:creator>
<dc:date>2007-02-03T12:44:59+02:00</dc:date>
</item>

<item rdf:about="http://www.perl.it/documenti/articoli/2007/01/introspezione.html">
<title>Introspezione!</title>
<link>http://www.perl.it/documenti/articoli/2007/01/introspezione.html</link>
<description>&lt;p&gt;Capita ogni tanto che, sul canale IRC #perl.it, qualcuno o qualcosa venga ad accendere una scintilla d'interesse in una altrimenti grigia e noiosa giornata lavorativa. Cos'&amp;egrave; un canale IRC, chiedete? Quello che comunemente passa sotto il nome di &lt;em&gt;chat&lt;/em&gt;, e nella fattispecie la chat sulla quale si possono trovare molti degli autori di Perl.it (praticamente tutti). Se qualcuno di voi sta pensando che la chat sia una cosa da scellerati perdigiorno o adolescentelli brufolosi che non hanno una vera vita, si dovr&amp;agrave; ora ricredere. Perlomeno per quanto riguarda i brufoli, che personalmente avevo una quindicina d'anni fa :-)&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/ArticoliPerlIt?a=i56H5FXT-v0:rNnsSRrqqZ8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ArticoliPerlIt?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/ArticoliPerlIt?a=i56H5FXT-v0:rNnsSRrqqZ8:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/ArticoliPerlIt?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;</description>
<dc:subject>article</dc:subject>
<dc:creator>dada</dc:creator>
<dc:date>2007-01-08T19:16:16+02:00</dc:date>
</item>


</rdf:RDF>
