Archivi Categorie: JavaScript

Javascript – Strumenti di lavoro

Anzitutto una piccola parentesi per quei pochissimi che non hanno mai provato ad eseguire javascript. Gli strumenti minimi necessari sono un browser ed un editor di testi. Personalemente uso un paio di browser come eredità dei tempi andati quando i due browser maggiori (Internet Explorer e Firefox) si guardavano in cagnesco e quando meno te lo aspettavi un codice perfetto su uno dei due, inaspettatemente, sull’altro aveva effetti fantasiosi. Ora i due non possono più chiamarsi “maggiori” perché superati dall’ultimo arrivato Chrome di Google e, per fortuna, sembra che hanno messo fine alle ostilità allineandosi quasi perfettamente allo standard della W3C, rendendo inutili i vecchi script per il riconoscimento del browser.

Qual è il migliore editor di testi? Ovvio, quello che conoscete meglio. Io uso Textpad da troppi anni e la voglia di imparare nuove cose si è molto affievolita. Un editor molto diffuso ed apprezzato e gratuito, cosa che non guasta mai, è Notepad++.

Un accenno a Brackets, un editor open source per diversi linguaggi (HTML, CSS e JavaScript) su cui l’Adobe sta lavorando e dalle caratteristiche interessanti (completamento automatico del codice HTML e CSS, suggerimenti e chi più ne ha più ne metta). Io l’ho provato prima con un js estremamente grosso (più di 50000 righe di codice) e Brackets non riesce a portare a termine il caricamento. Poi ho provato js più accettabili e al termine del caricamento vengono segnalati errori incomprensibili; segno di un’immaturità del programma. Vedremo in futuro se manterrà le promesse.

Accanto agli editor tradizionali vi sono anche ambienti di sviluppo integrati, come Eclipse e Visual Studio che, con un apposito plugin, permettono di gestire javascript. Entrambi sono gratuiti.

Con il normale editor di testi bisogna, anzitutto, scrivere uno scheletro di pagina HTML:

<!DOCTYPE html>
<html>
<head>
<head>
<body>
< script>

// qui va messo il codice javascript

</script>
</body>
</html>

(Nota: è stato aggiunto uno spazio dopo il segno di minore e prima di script solo per motivi “tipografici”, altrimenti WordPress avrebbe cancellato tutto il tag)
Il codice precedente è perfetto per l’HTML5. Con l’HTML4 la prima riga era un mezzo papier e anche nel tag script bisognava specificare il tipo di script (type=”text/javascript”), che ora non è obbligatorio, o anche, nelle versioni più vecchie, il linguaggio (language=”JavaScript”, attualmente obsoleto). Il linguaggio poteva essere diverso, forse nelle speranze di coloro che hanno ideato l’html. In questo momento probabilmente il javascript è diventato il linguaggio “per eccellenza”, indispensabile se si vuole fare pagine web non troppo banali.

Per la mia pigrizia, poiché non voglio passare la vita a scrivere cose inutili, utilizzo anche Dreamweaver, che è un editor HTML per Windows e per Apple. Infatti tutta quella roba là sopra viene scritta automaticamente appena si crea la pagina web. Poi, per eseguire il codice, si preme il tasto F12 con cui viene richiamato il browser di default.

In mancanaza di Dreamweaver (che costa un pacco di soldi) o di altro strumento ci arrangiamo come possiamo. Scriviamo quindi il primo facilissimo script (Kernighan & Ritchie insegnano):

alert(“Hello world!”);

 

e lo mettiamo là, al posto dei puntini, all’interno del tag script:

<!DOCTYPE html>
<html>
<head>
</head>
<body>
< script>
alert(“Hello world”);
</script>
</body>
</html>

Poi salviamo il tutto con il nome, ad esempio, Hello.htm (o quello che vi pare, basta che il nome del file abbia estensione HTM o HTML). Magari cerchiamo di salvare il file in una certella facilmente raggiungibile, così non ci dobbiamo rovinare la giornata per ritrovare dove abbiamo salvato il nostro lavoro. Anche il desktop va bene (provvisoriamente, perché è proprio brutto vedere il desktop pieno di tutte quelle icone, di solito inutili, che non sappiamo nemmeno da dove scappano fuori). Infine clicchiamo due volte sull’icona di Hello.htm e… voilà… ecco apparire una finestrella (popup modale) con scritto l’ormai usuale saluto.

Non succede niente? Evidentemente si è verificato un qualche errore di battitura.
Già, ma quale? Dobbiamo fare una ricerca da certosini, misurare la lunghezza della virgola per essere sicuri di non averla confusa col punto? Per fortuna i browser hanno i loro bravi strumenti di debugger. In particolare la Console. Con Firefox si apre il menù Strumenti -> Sviluppo web -> Console web e troveremo l’indicazione della prima istruzione che il browser non riesce ad interpretare. Con Internet Explorer si accede alla Console con premendo il tasto F12. Anche con Chrome si può accedere alla Console tramite menù (More Tools -> Javascript Console). A questo punto dobbiamo solo correggere il sorgente e riprovare.

Maurizio.

Perché JavaScript non va bene per i dispositivi mobili

E’ possibile che un tablet possa sostituire efficacemente un PC?

Qualche tempo fa mi sono imbattuto in questo post che contiene un sacco di informazioni interessanti sui linguaggi di programmazione dinamici e sul perché non siano adatti alla programmazione di applicazioni per dispositivi mobili. Ne consiglio a tutti la lettura. Ma dato che il post è lungo, ne farò qui un sommario aggiungendo i miei commenti.

Il garbage collector

I linguaggi di programmazione possono essere categorizzati in molti modi. Uno dei modi è quello di distinguere i linguaggi managed da quelli unmanaged. I primi utilizzano, tra le altre cose, il meccanismo di garbage collection (o GC) per gestire automaticamente la memoria dinamica utilizzata dai nostri programmi, mentre i secondi lasciano il compito di gestire la memoria essenzialmente al programmatore. Tra i linguaggi managed ci sono per lo più linguaggi dinamici come Python, Ruby, JavaScript, ma anche linguaggi compilati come Java e Haskell. Il tipico linguaggio unmanaged è il C/C++. Oggi, moltissimi linguaggi sono managed, e la ragione sarà più evidente nel proseguimento del post.

La GC è stata inventata da una vecchia conoscenza di questo blog: da John McCarthy, si proprio lui, l’inventore del linguaggio LISP. L’idea è quella di liberare il programmatore dal difficile compito di dover gestire personalmente la memoria dinamica. In un linguaggio non managed, come il C ad esempio, ogni volta che faccio una p = malloc(nbytes) ottengo un puntatore a una nuova zona di memoria della dimensione richiesta che posso usare per memorizzare i miei dati; corrispondentemente, quando quella zona di memoria non mi serve più dovrò fare una free(p) per liberare la memoria e renderla di nuovo disponibile. Se mi scordo di fare la free(), e magari cancello il puntatore, la memoria resterà occupata, almeno fino a quando il programma resterà in esecuzione. Se il programma rimane in esecuzione per lungo tempo, è bene assicurarsi che ad ogni malloc() corrisponda sempre una free(), altrimenti la memoria occupata dal programma potrebbe crescere in maniera incontrollata.

Pensate ad esempio ad un server che accetta richieste di connessione; questo programma eseguirà per un tempo indeterminato, giorni, mesi, anni. Supponiamo che ad ogni richiesta venga allocata della memoria, ma al termine del completamente del servizio questa memoria non viene deallocata. Ad ogni richiesta, le dimensioni della memoria del programma continueranno a crescere mandando prima o poi in crash il sistema. Inoltre, la memoria si riempie di spazzatura, ovvero dati ormai inutili. Un tale tipo di errore viene chiamato memory leak, perché sembra che la memoria “goccioli via” come da un secchio bucato. Nel passato, il numero di errori che avevano a che fare con una cattiva gestione della memoria da parte del programma era piuttosto elevato, per cui si pensò di porre rimedio sottraendo il compito di gestire la memoria al programmatore.

I linguaggi managed permettono al programmatore di allocare memoria per i propri dati; evitano però che il programmatore debba liberare la memoria quando non è più necessaria. In pratica, permettono la malloc(), ma evitano di farci fare la free(). Un algoritmo, chiamato garbage collector periodicamente analizza la memoria del nostro programma per vedere se qualche zona di memoria precedentemente allocata può essere liberata. In pratica, raccoglie la spazzatura per noi. Per far questo, ad ogni zona di memoria viene associato un contatore dei riferimenti (reference counter) che conta quanti puntatori attivi riferiscono quella particolare zona di memoria. Ogni volta che la zona viene riferita da una nuova variabile puntatore, il contatore viene incrementato; ogni volta che un puntatore che riferisce quella zona viene cancellato, il contatore viene decrementato. Quando il contatore raggiunge il valore zero, vuol dire che nessun’altra parte del programma riferisce quella zona, che quindi può essere liberata. Non viene però liberata immediatamente (a causa di una serie di casi particolari, non è sempre così facile accorgersi del fatto che una zona di memoria può essere liberata!). In particolare, il GC esegue periodicamente due fasi: nella prima, chiamata mark, si marcano le zone da liberare; nella seconda, chiamata sweep, le zone marcate vengono effettivamente liberate.

La GC è stata sempre oggetto del contendere tra due diversi modi di vedere la programmazione: da una parte quelli che dicono che la GC è la panacea di tutti i mali; dall’altra quelli che dicono che la GC è inutilmente pesante e sostanzialmente inutile. Chi ha ragione? Il post che ho citato all’inizio ci da un punto di vista secondo me molto chiaro e rilevante.

VM

Per implementare la GC ci vuole una Virtual Machine. In pratica, bisogna essere in grado di tradurre un assegnamento tra puntatori in una operazione più complicata che coinvolge i reference counters. Inoltre, le variabili puntatori assumono uno status tutto particolare e differente dalle variabili int o float, perché il GC deve essere in grado di riconoscerle e seguire la “pista” alla ricerca di zone di memoria da liberare. Naturalmente, una VM significa overhead in più di traduzione. E’ vero che ci sono i Just in Time Compilers, che generano codice macchina a partire dal byte code; è anche vero che la VM si può evitare del tutto, come ad esempio fa Haskell con un run-time corposo. Quello che è importate sottolineare però è che per quanto si possa ottimizzare lo strato di VM o di run-time, resta il fatto che l’algoritmo di GC va implementato, e per quanto si possa fare in maniera efficiente, resta sempre un algoritmo piuttosto pesante.

Problemi con il GC

Io vedo due ordini di problemi con il GC. Il primo è strettamente tecnico: il GC ha bisogno di analizzare la memoria del nostro programma alla ricerca di zone di memoria da poter liberare. Mentre fa questo lavoro, la VM quasi sempre di blocca in attesa che il GC abbia finito. Questo perché il GC “legge” e “modifica” le strutture dati del gestore di memoria, e queste strutture dati sono costantemente utilizzate dalla VM sia per allocare nuova memoria, sia per aggiornare i reference counters. Non è sempre possibile permettere che il GC vada in parallelo con il resto del programma, per cui potrebbe accadere che la vostra applicazione abbia un piccolo “freeze” (cioè si blocchi completamente) per un po’ di tempo a causa del GC.

Quanto dura questo “freeze” dipende da un sacco di fattori, il più importante dei quali è l’uso che il programma fa della memoria. Se il programma alloca e libera continuamente tanti oggetti di piccola dimensione, il GC potrebbe prendere tantissimo tempo per eseguire, e il freze potrebbe durare anche qualche secondo. Un altro problema tecnico è capire quando il GC viene eseguito per liberare la memoria. All’inizio del post ho scritto che il GC viene eseguito periodicamente, ma con quale periodo? beh, dipende anche dall’utilizzo della memoria: se c’è poca memoria libera nel sistema, il GC verrà eseguito più frequentemente, nel tentativo di liberare memoria, e questo incrementerà l’overhead, cioè il numero e la durata dei “freeze”.

In ogni caso, quel che è peggio è che quasi nessun linguaggio managed permette al programmatore di controllare quando e quanto spesso il GC va in esecuzione. Quindi il programmatore ha poco controllo.

E veniamo con questo al secondo ordine di problemi del GC. Dato che la gestione della memoria è completamente demandata al sistema e nascosta al programmatore, il programmatore poco esperto tende a usare tanta memoria, creando e distruggendo oggetti inutilmente. Per esempio, in programmi Java scritti da programmatori poco esperti è comune leggere codice come il seguente:

String s = new String("Questa è una stringa");
String c = s.toUpperCase();

questa linea di codice crea un oggetto di tipo stringa per copia da una costante di tipo stringa. Quindi trasforma tutti i caratteri in maiuscolo.
Quello che il programmatore non sa, o dimentica spesso, è che la classe stringa è immutabile, ovvero non si può modificare un oggetto di classe stringa. Ad esempio, ogni volta che volete rimuovere un carattere da una String Java, viene creata un nuovo oggetto di tipo stringa che contiene tutti i caratteri di quello originale meno quello da rimuovere. Per cui, nella riga sopra ci sono 3 oggetti: la stringa originale, quella puntata da s che non può essere modificata, e quella puntata da c. Quella puntata da s è quindi un inutile duplicato, anzi più che inutile, dannoso, perché prima o poi il GC dovrà occuparsi anche di lui! Un modo efficiente di scrivere sarebbe semplicemente:

String s = "Questa è una stringa";
String c = s.toUpperCase();

In questo caso ci sono solo due oggetti, l’originale e quello puntato da c. Di esempi così se ne potrebbero fare molti. E’ così facile creare nuovi oggetti che il programmatore inesperto lo fa senza quasi accorgersene, incrementando notevolmente il lavoro del GC e quindi la lentezza del programma.

Quello che io considero un problema, però, è anche la forza dei linguaggi managed. Poiché non c’è da occuparsi della gestione della memoria, scrivere programmi funzionanti (anche se non molto efficienti) è più semplice, quindi aumenta la produttività del programmatore medio, si riduce il time-to-market, il costo di sviluppo, ecc. E finché la potenza e la memoria disponibile aumentavano, non c’erano problemi: più memoria avete sul vostro PC, meglio funzioneranno programmi scritti con linguaggi managed.

Come detto efficacemente da Miguel de Icaza,

This is a pretty accurate statement on the difference of the mainstream VMs for managed languages (.NET, Java and Javascript). Designers of managed languages have chosen the path of safety over performance for their designs.

Alcuni numeri

Nel post il buon Drew Crawford riporta alcune statistiche che non conoscevo, prese da questo paper. Riporto qui le frasi più importanti, come fa Drew:

In particular, when garbage collection has five times as much memory as required, its runtime performance matches or slightly exceeds that of explicit memory management. However, garbage collection’s performance degrades substantially when it must use smaller heaps. With three times as much memory, it runs 17% slower on average, and with twice as much memory, it runs 70% slower. Garbage collection also is more susceptible to paging when physical memory is scarce. In such conditions, all of the garbage collectors we examine here suffer order-of-magnitude performance penalties relative to explicit memory management. […]
These graphs show that, for reasonable ranges of available memory (but not enough to hold the entire application), both explicit memory managers substantially outperform all of the garbage collectors. For instance, pseudoJBB running with 63MB of available memory and the Lea allocator completes in 25 seconds. With the same amount of available memory and using GenMS, it takes more than ten times longer to complete (255 seconds). We see similar trends across the benchmark suite. The most pronounced case is 213 javac: at 36MB with the Lea allocator, total execution time is 14 seconds, while with GenMS, total execution time is 211 seconds, over a 15-fold increase.

La conclusione quindi è che per stare sicuri di avere performance decenti con il GC, bisogna avere almeno 3-4 volte la memoria minima strettamente necessaria (cioè quella richiesta da un programma che usa allocazione esplicita della memoria). Su un PC prendetevi almeno 4Gb di RAM (meglio 8Gb) e andate tranquilli. Su un dispositivo mobile però non è così semplice.

Il problema delle webapp

Una webapp è una applicazione web, che di solito usa il cosidetto AJAX, ovvero una combinazione di programmi client e server, per fornire funzionalità dinamiche complesse. Per quanto riguarda la parte client, si usa JavaScript (o più propriamente ECMAScript), un linguaggio ormai popolarissimo proprio in ambito web. Si tratta di un linguaggio dinamico, managed, che usa il browser come VM. E naturalmente, usa un GC per gestire la memoria. Essendo un linguaggio vero e proprio, è possibile costruire applicazioni anche molto complesse, che però eseguiranno nel vostro browser.

Una web app particolarmente complicata, ad esempio, è Google Docs, che cerca di replicare un subset delle funzionalità di una suite office sul browser. Qualche anno fa, quando Google Docs fu proposto, ci fu una certa euforia fra i primi utilizzatori e fra gli stessi sviluppatori: era convinzione diffusa che si potesse interamente sostituire una suite come Microsoft Office con qualcosa come Google Docs basata interamente sul web. Se usate Google Docs sul vostro PC, e se questo è abbastanza carrozzato, non ci sono grandi problemi: non è velocissimo, ma è ancora usabile. Se invece qualcuno tentasse di usare Google Docs sul suo Tablet o sul cellulare, beh, i tempi di risposta andrebbero a farsi benedire. Ecco cosa dice personale di Google a proposito:

Complex web apps–the kind that Google specializes in–are struggling against the platform and working with a language that cannot be tooled and has inherent performance problems.

A dire la verità, anche web app molto più semplici soffrono notevolmente: per esempio provate ad accedere alla pagina di Dropbox tramite browser su tablet: dovrete attendere diversi secondi dopo ogni click. In effetti, molto meglio scaricarsi l’app di Dropbox e tentare di fare le proprie operazioni da lì (ma anche quella non è un fulmine).

Il problema è duplice. Il primo problema è di lentezza del processore. Una cosa è avere un bell’Intel i7 sul proprio desktop o portatile, una cosa completamente diversa è di avere un ARM progettato e realizzato con il risparmio energetico in mente. Inoltre, JavaScript è interpretato (o JIT-compilato), e le performance sono nettamente inferiori per questo motivo; Drew calcola che un programma JavaScript è da 5 a 10 volte più lento su un dispositivo mobile rispetto allo stesso programma su PC. Quello che richiede un secondo sul PC può richiedere 10 secondi sul mobile. Leggetevi attentamente la prima parte del post per una lunga analisi delle differenze di velocità.

A questo aggiungete il fatto che JavaScript usa il GC, e che la memoria di un dispositivo mobile è severamente limitata e avete il quadro completo della situazione.

Cosa succederà ora?

Eh, ad avere la palla di cristallo.

Ovviamente, credo non sia possibile continuare sulla strada di sviluppare Webapp sempre più complesse con l’idea che possano completamente sostituire programmi sviluppati nativimente per la piattaforma hardware. I programmi .exe, insomma, non spariranno tanto presto, anzi.

Per quanto riguarda Android, la strada scelta da Google di basarsi su Java è sembrata essere vincente all’inizio, perché ha permesso di sviluppare una grande quantità di app in breve tempo grazie alla maggiore produttività e sicurezza di un linguaggio managed come Java. Sul lungo termine però, il GC sta ponendo più problemi che soluzioni perché, come descrive Drew, i programmatori si vedono costretti ad aggirare il GC con trucchi e trucchetti per evitare la degradazione delle performance.

Si tornerà ad utilizzare il C++ anche sui dispositivi mobili? Credo piuttosto che l’hardware arriverà in soccorso del software ancora una volta… ma chi può saperlo?

Una pagina html con tutti i link che servono davvero


Alle volte un’idea semplicissima diventa, una volta sviluppata e realizzata, una di quelle cose che rendono la vita migliore –almeno un pochino.
Come quella di cui voglio parlare in questo post. L’idea non è mia –sia chiaro da subito– ma sapete come vanno le cose.
Anche Stefano Lavori ha copiato l’idea che ha cambiato il mondo dei ‘puter: scrivania, cartelle, documenti, topo e quant’altro li ha copiati dopo averli visti nel parco della collina del coyote. Bravo Stefano, che ha visto che era un’idea che acchiappava, ma, dico io, bravi quelli del parco che quelle cose le avevano immaginate.
Tutto questo per dire che chi è stato bravo davvero è Mattux (quello che in casa si ostinano a chiamare Matteo o, esagerando Matteo Pani)


Trovate tutto sul suo blog, nella pagina Startpage minimale che utilizza un menù. Quindi, dopo aver proposto a Matteo di brevettare il tutto, magari con il nome iMattux (Stefano insegna) il mio compito è finito. No! Aspettate un momentino, adesso vi racconto quelle che sono le mie personalizzazioni.

Al CSS di Matteo ho apportato un unica modifica: ho allargato il campo di destra. Nella riga (dovrebbe essere la n. 110)

ul.link { position:absolute; left:250px; top:50px; opacity:0; width:250px; visibility:hidden;

ho cambiato il valore di width sostituendo 250 con 400, altrimenti le descrizioni lunghe venivano spezzate su due linee. Il resto è tutto OK.

Nel file html le modifiche sono, ovviamente più numerose e personali.
Intanto il titolo, quello che appare sulla barra della finestra: è definito nelle prime righe, così <title>Tutti i link</title>.

La scritta grande in testa alla pagina è definita della divisione testata:

<div id="testata"> <h1>Tutti i link che servono davvero</h1> </div>

seguono tante div class=”contenuto_due” in cui vengono definite le scritte del menu e dei link. Qui io propongo una variazione rispetto alla versione di Matteo: la linea tipica per l’elenco della class=”link” è del tipo

<li><a href="https://plus.google.com/" target ="_blank">Google Plus</a></li>.
L’aggiunta di target =”_blank” aprirà la pagina indicata in un nuovo tab. Così questo menu si apre una volta sola e rimane aperto sempre nel tab più a sinistra, meglio no? 8)

Per inserire una riga vuota, non clickabile basta mettere
<li><a href="#">&nbsp;</a></li>

Attenzione che ogni div id=”gruppo” deve avere identificatori unici e consistenti per indice_# e lista_#; ma è facilissimo.

Tutto lì.
Funziona con Linux, Windows, Mac, _________. A meno che siate proprio speciali. Io l’ho testato con Firefox ma il codice è davvero standard, non dovrebbero esserci problemi. Per dire potreste usare anche Internet Explorer 8) –che sarebbe comunque una pessima idea.

Nel mio caso si vede che mancano le voci relative al Reader dei siti RSSati e per la mail. Ciò perché ho due estensioni che mi avvisano all’arrivo di nuovi documenti da leggere.

Oggi quello della mail non funziona 😦

Alcuni penseranno come direbbe il mio tutor a UCDB Gyro Gearloose

Troppo semplice, non capisco

ma a altri potrebbe piacere, e magari servire. Io per esempio lo sto usando. Sempre che Matteo non voglia farsi pagare le royalties 8)

Oggi JavaScript

È incredibile la confusione esistente tra JavaScript e Java. E il colmo è che inizialmente era intenzionalmente voluta. Marc Andreessen, l’allora boss di Netscape e Brendan Eich, l’autore di JavaScript sono i responsabili, tra le altre cose, del fatto che il mio amico G*** abbia toppato lo tsunami di Java spendendo tutto il suo budget per l’acquisto libresco su un malloppo di 800 pagine che reca sulla copertina il logo di Netscape e script scritto grosso. Ma sono cose dell’altro millennio.
JavaScript è una di quelle cose di cui non possiamo fare a meno: se non ci fosse il mondo sarebbe molto diverso, Micro$oft lo sa e ha tentato di assassinarlo con JScript e (orrore) VBscript.

Adesso non è che mi metto a raccontare Mocha LiveScript JavaScript, è estate, tutti sono al mare tranne me che ho il naso bendato e non posso nemmeno lavarmi i capelli, sigh 😦

Piuttosto, pensando a quelli che sotto l’ombrellone leggono la Settimana Enigmistica e in particolare la mia pagina preferita Forse non tutti sanno che, voglio proporre tre esempi creativi di JavaScript.

Comincio con un esempio semplice e vecchiotto, l’8-Bit Binary Converter. Semplice e didascalico ma la cosa intrigante è che l’ho trovato sul sito di Brian Kernighan, qui.

Un esempio più articolato di uso creativo di JavaScript si trova qui. Chi sia Colin Barschel non lo so. Il suffisso ICANN .vu sta per Vanuatu, gruppo di isole vicine all’Australia (ma comunque molto lontane dalla stessa).
Ma in ogni caso funziona con parecchi comandi *nix, provate per esempio ls, e cat about.txt. Bello questo

E adesso, rullo di tamburi, Randall Munroe. Non poteva mancare, è inutile che metta il link a Wikipedia, sarebbe un’inutile ridondanza. Nata come pesce d’aprile esiste questa paginalollosa come direbbe il mio amico Picchio.
È possibile navigare nel suo blag xkcd e provare la versione randalliana di alcuni comandi comuni, tipo cat, echo, whoami.
E, naturalmente non può mancare 😀

Maggiori informazione su unixkcd qui.
Doveroso ringraziamento a Chromakode e Rod Mcfarland.

Buone ferie/vacanze a tutti!