Archivio categoria: Programmazione

Semplificarsi la vita con MATLAB

spyScrivo questo breve articolo per suggerirvi qualche trucchetto che può semplificarvi la vita lavorando con MATLAB.

Cerca su Google da command window

Molto spesso mi capita di dover cercare rapidamente qualcosa su Google, mentre lavoro nella console di MATLAB. Specialmente quando lavoro sul netbook, dove ho davvero poca RAM disponibile, aprire Chrome per una rapida ricerca è davvero un supplizio.
Allora ho pensato: perché non utilizzare il browser integrato in MATLAB?
Detto fatto.

Ecco una semplice funzione che richiama il browser integrato per effettuare ricerche immediate:
Download google.zip
Mostra codice ▼

In questo modo basterà digitare google(‘oggetto da cercare’) per aprire il browser di MATLAB.

No, I do mean Wirgilio!

.

Avvia il debug durante l’esecuzione

Durante l’esecuzione di script molto lunghi è fondamentale essere sicuri che il codice stia funzionando correttamente. MATLAB mette a disposizione un comando molto utile che permette di investigare durante l’esecuzione del codice: keyboard.

Il comando è molto semplice è intuitivo, ma il problema è: come faccio ad attivarlo quando decido io? Ad esempio, sto osservando i risultati di uno script ogni tot iterazioni attraverso una figura, quando mi accorgo che qualcosa sta andando storto e voglio avviare il debug. Come fare?
L’idea è quella di utilizzare una variabile presente all’interno delle figure, ossia CurrentCharacter. Quando si preme un tasto della tastiera attraverso una figure, la variable CurrentCharacter assume il valore pari al tasto premuto.

Con una semplice riga si può quindi avviare il debug premendo un tasto della tastiera, in questo caso la lettera k.

if get(gcf,'CurrentCharacter') == 'k', keyboard, end

Per continuare l’esecuzione sarà sufficiente chiudere la figura e premere F5.

Esempio di utilizzo:
Mostra codice ▼

.

Focus delle figure

Quando una figure di MATLAB viene selezionata, questa acquisice il focus e viene mostrata davanti a tutte le altre finestre. Se si sta lavorando al codice durante l’esecuzione, può succedere che il continuo apparire delle figure ci impedisca di fare qualsiasi altra cosa.

Una possibile soluzione è quella di utilizzare la funzione set per cambiare la figura attiva, invece del classico figure().

Esempio di utilizzo:
Mostra codice ▼

.

Figure a schermo intero

Un altro comando che utilizzo molto spesso è quello che permette di aprire una figure a schermo intero. Il trucco è definire le unità normalizzate quando si crea la figura:

figure('Units','normalized','Position',[0 0 1 1])

L’attributo Position richiede un array di quattro valori: [Posizione_x, Posizione_y, Larghezza, Altezza]. Utilizzando le unità normalizzate sarà sufficiente inserire valori unitari per larghezza e altezza.
Questo tipo di unità permette anche una più agevole disposizione delle figure sullo schermo, indipendentemente dalle sue dimensioni.

Esempio di utilizzo:
Mostra codice ▼

finestre

 

.

Barra di caricamento

Una delle funzioni che adoro di MATLAB è senza dubbio la waitbar.
Ideale quando un codice richiede più di qualche istante per essere eseguito!

L’utilizzo è estremamente semplice, riporto direttamente l’esempio dall’help di MATLAB:

h = waitbar(0,'Please wait...');
for i=1:1000,
% computation here %
waitbar(i/1000,h)
end

Se le iterazioni sono molto rapide, come nel codice dell’esempio, la chiamata a waitbar può essere più lenta del calcolo che viene effettuato durante l’iterazione stessa e può rallentare drasticamente l’esecuzione del codice! Per evitare ciò, vi consiglio di utilizzare sempre una condizione che aggiorni la waitbar un numero sensato di volte:

h = waitbar(0,'Please wait...');
 for i=1:1000,
     % computation here %
     if mod(i, 100) == 0
        % Questo codice viene eseguito solo ogni 100 iterazioni
        waitbar(i/1000,h)
     end
 end

wait


Flood – Un gioco realizzato in MATLAB

secchioProgrammare è un’attività davvero molto stimolante. È un po’ come risolvere i cruciverba o i giochi di logica della Settimana Enigmistica, solo che hai molta più libertà e hai a disposizione strumenti talmente potenti da avere solo la fantasia come unica limitazione.

Non si può dire di saper  usare un computer, se non si conosce un linguaggio di programmazione!

È proprio da questi presupposti (abbinati all’esaurimento-esami) che nasce questo semplice giochino, realizzato con MATLAB, Flood.
L’idea non è mia, ma non credo si possa parlare di un vero e proprio ideatore di questo gioco… È un po’  come giocare con il Paint!

paint

Il gioco è molto semplice: bisogna riempire l’intera finestra di gioco con uno stesso simbolo, nel minor numero di mosse possibile, partendo dall’angolo in alto a sinistra. I simboli simili si contagiano orizzontalmente e verticalmente. È possibile modificare i simboli presenti nel gioco e il livello di difficoltà.
Una matrice generata casualmente, color, contiene i numeri a cui sono associati i simboli, e un vettore di nome path contiene tutti gli elementi che sono stati “riempiti”.

Il gioco non ha un’interfaccia grafica, per il semplice motivo che l’ho realizzato sul tablet con Octave, che ha un po’ di problemi con gli oggetti figure. Sarebbe carino realizzarne una versione grafica utilizzando una matrice di colori, ma è un gioco talmente stupido che non credo ne valga la pena! Ad ogni modo sarebbe sufficiente utilizzare la funzione imagesc applicata alla matrice color, con un’opportuna colormap.
Probabilmente è stato più divertente realizzarlo che giocarci successivamente 🙂

Download – flood.zip (pochi kB)

flood

Download – flood.zip (pochi kB)


Campo magnetico (e velocità indotta da un vortice) lungo una curva generica con MATLAB

Premessa: la lettura di questo articolo potrebbe risultare molto confusa. È talmente specifico che, molto probabilmente, servirà a una persona su un milione. In realtà servirà molto più a me per fissare certe cose che a qualcun altro…

L’induzione magnetica (e la velocità indotta da un vortice, in aerodinamica) è descritta dalla legge di Biot-Savart:

\Gamma =\frac{k}{4\pi}\oint_{C} \frac{dL\times R}{|R^3|}

Dove k è una costante moltiplicativa proporzionale all’intensità (della corrente o del vortice). Per questa legge esistono diverse soluzioni analitiche, per i casi più semplici e anche più frequenti: filo rettilineo di lunghezza infinita, solenoide, …

Potrebbe essere interessante osservare il campo magnetico anche per un filo di una forma più strana, come una spirale a passo non costante, o una forma geometrica complessa. Soluzioni analitiche per forme geometriche complesse non ne esistono ed è necessario integrare numericamente la legge di Biot-Savart.
Concettualmente è molto semplice: divido il filo in piccoli intervalli finiti di lunghezza \Delta L, per ognuno dei quali calcolo l’induzione \Delta \Gamma e infine ne faccio una sommatoria:

\Delta\Gamma=\frac{k}{4\pi}\frac{\Delta L\times R}{|R^3|}
\Gamma = \sum_i \Delta\Gamma_i

Ecco cosa fa il codice che ho scritto: si assegna un dominio di calcolo (non troppo grande, altrimenti ci impiega un’eternità!) e si fa un ciclo per ogni punto del dominio (tre cicli for su i, jk). Per ognuno di questi punti, si discretizza la curva in intervalli di ampiezza ds e si calcola l’induzione di ogni elementino sul punto del dominio in questione, sommando i vari contributi (componenti UV, W).

campo

Non è il massimo dal punto di vista dalle performance, è stata la prima cosa che mi è venuta in mente e non ho neanche pensato se fosse la migliore. Funziona e basta 😀

Un unico appunto lo vorrei fare sull’utilizzo delle meshgrid e del prodotto vettoriale. Il campo magnetico (campo di moto) è descritto da una serie di vettori tridimensionali. Questi vettori dipendono dal punto di applicazione, o meglio, ogni punto del campo ha un suo vettore di induzione, che ne descrive direzione, intensità e verso. In MATLAB, ogni cosa è una matrice e non fanno eccezione i campi vettoriali. Il problema è questo: ogni vettore ha tre componenti, ognuna delle quali è contenuta in una matrice NxNxN. Ho bisogno di tre matrici NxNxN per descrivere il campo vettoriale. Come faccio però a capire in quali punti sono applicati questi vettori?
Qui interviene la funzione meshgrid, che genera una matrice contenente le coordinate dei punti in cui voglio che siano applicati i vettori. Quindi avrò: tre matrici U, V e W contenenti le componenti lungo gli assi xyz dell’induzione e tre matrici XY e Z contenenti i punti di applicazione dei vettori. Quando si fa il calcolo del \Delta\Gamma di Biot-Savart bisogna tenere presente quanto detto: per il calcolo del vettore R dovrò considerare le matrici XYZ, dato che mi interessa il punto di applicazione del vettore.

Forse era una precisazione banale. Forse no.

Considerazioni aerodinamiche

Il codice permette di integrare la legge di Biot-Savart, che è nota nella fisica per l’induzione di un campo magnetico. In aerodinamica viene invece utilizzata per calcolare la velocità indotta da un vortice. È interessante andare a calcolare il campo di moto nella scia di un’ala utilizzando questo codice.

La Teoria del Filetto Portante di Prandtl ci spiega come sia possibile modellare il campo di moto attorno ad un’ala mediante un sistema di vortici. La schematizzazione più semplice di questo sistema di vortici è il cosiddetto vortice a staffa, di cui rubo senza pietà un’immagine da Google:

vortice_staffa

Inserendo nel codice i punti di un vortice a staffa:

L = [-1 6 0;
     -1 0 0;
      1 0 0;
      1 6 0];

Si ottiene un campo di moto di questo tipo:

linee_campo

Non è molto preciso perché è stato calcolato su un dominio di 20 punti, ma rende comunque l’idea.
Se a questo campo di moto sommiamo una corrente uniforme, otteniamo il campo di moto attorno a un’ala:

vortici1

trittico

Il confronto con un’immagine ottenuta per via sperimentale (linee di fumo) mostra la validità di questa teoria:

vortici_ala

Download dell’animazione in 3D (.avi, 4.9 MB)

Un’altra figura interessante che è possibile ottenere è quella relativa al downwash:

downwash

L’immagine è stata ottenuta utilizzando la funzione surf alla componente verticale della velocità.

Da questa figura si possono notare due cose: la prima è che il vortice parallelo all’ala (vortice aderente) produce un upwash sulla corrente incidente, la seconda è che il downwash è dovuto essenzialmente all’effetto dei vortici laterali (vortici liberi).

Tutte le figure delle linee di corrente sono state ottenute utilizzando la funzione streamtube, che prende in input le mesh, il campo di moto e tre vettori/matrici contenenti i punti da cui devono partire le linee di corrente.

Potete scaricare il codice dal seguente link, o dal file exchange di MATLAB.

Download biot_savart.zip
Download da MATLAB file exchange


Creare un video time-lapse con MATLAB

Stavo facendo una simulazione in CFD e volevo ottenere un video a partire da un migliaio di immagini. In giro ci sono decine di software per farlo, ma a prima vista non ho trovato nulla di estremamente rapido, gratuito e che non richiedesse installazione. Allora ho pensato: “Io ho MATLAB!“. Bene, perché non usarlo per questo scopo? Detto fatto. Dopo un’oretta di codice per capire come utilizzare la classe VideoWriter mi è uscito questo simpatico codice che permette di:

  1. Selezionare le immagini (in qualsiasi formato)
  2. Selezionare un file di output .avi
  3. Impostare il framerate, la qualità (JPEG) e un fattore di scala per ridimensionare le immagini
  4. Esportare il video

Il tutto con una simpatica interfaccia grafica 😀

*** Download time-lapse.zip ***

screenshot

Ho scritto il codice in inglese per poterlo caricare sul file exchange di MATLAB.

*** Download time-lapse.zip ***

Giusto per curiosità, ecco il video che ho ottenuto con lo script: http://www.youtube.com/watch?v=xYUQxIDwDOQ


Simulatore di Giroscopi in MATLAB

retrogrado– Download del codice – eulero.zip

Ultimamente ho passato un po’ di tempo a giocare con la funzione ode45 di MATLAB e, dopo aver speso una decina di minuti necessari a capire come impostare i vari parametri di funzionamento, ho iniziato ad integrare tutte le equazioni differenziali che ho incontrato nel corso degli studi.

Tra i vari problemi in cui mi sono cimentato ultimamente, c’è quello delle Equazioni di Eulero, ossia le equazioni che descrivono le rotazioni di un oggetto di forma arbitraria soggetto a dei momenti forzanti. In questo articolo voglio proporre un codice scritto da me che permette la risoluzione di queste equazioni e ne mostra i risultati sottoforma di animazione.

Impostazione del problema

Per prima cosa, impostiamo il problema. Abbiamo un corpo di forma arbitraria nell’ipotesi semplificativa, grazie a opportune simmetrie, di prodotti d’inerzia nulli; chiameremo i momenti principali d’inerzia AB e C. Questo corpo ha un orientamento nello spazio che è descritto da una terna di angoli di Eulero; in particolare, è stata scelta una sequenza del tipo XYZ e gli angoli sono stati rinominati\psi, \theta, \phi. Il corpo è soggetto ad un momento le cui componenti attorno agli assi xy, z, sono state rinominate L(t)M(t)N(t). Le equazioni da risolvere, in questi termini, sono:

\left\{\begin{matrix} A\ddot\psi=L + \dot\theta\ \dot\phi\ \left(B-C\right)\\ B\ddot\theta=M + \dot\psi\ \dot\phi\ \left(C-A\right) \\ C\ddot\phi=N + \dot\psi\ \dot\theta\ \left(A-B\right)\\ \end{matrix}\right.

La funzione che utilizziamo per integrare le equazioni è, come preannunciato, ode45. Questa funzione accetta in input una function(t,y), il cui valore è il secondo membro di un’equazione differenziale del primo ordine. Il nostro sistema è del secondo ordine, ma è facilmente trasformabile in un sistema del primo ordine utilizzando altre tre equazioni. Chiamando:

\dot\psi=\omega_x\ \ \ \ \dot\theta=\omega_y\ \ \ \ \dot\phi=\omega_z

Il sistema diventa:

\left\{\begin{matrix}A\ \dot\omega_x=L + \omega_y \omega_z\ \left(B-C\right)\\B\ \dot\omega_y=M + \omega_x\ \omega_z\ \left(C-A\right) \\C\ \dot\omega_z=N + \omega_x\ \omega_y\ \left(A-B\right)\\\dot\psi=\omega_x\\ \dot\theta=\omega_y\\ \dot\phi=\omega_z\end{matrix}\right.

Il codice

– Download del codice – eulero.zip

Per quanto riguarda il codice, questo è diviso in tre file:

  • main.m – contenente il codice principale del programma
  • eulero.m – contenente il sistema di equazioni da integrare
  • ang2dcm.m – funzione che restituisce la matrice dei coseni direttori utilizzata per le rappresentazioni grafiche

Iniziamo dal main.m.

Mostra codice ▼

Questa prima parte del codice è molto semplice. Si limita a pulire la memoria, definire due variabili del problema e mostrare un menù di scelta che presenta alcuni casi di problemi preimpostati. L’intero gruppo switch può essere ovviamente rimpiazzato da uno solo dei casi.
Notare che le leggi temporali delle componenti del momento L, M ed N, sono state definite utilizzando le anonymous function, che consistono nell’unico caso in cui è possibile definire una function all’interno di uno script in MATLAB. Queste funzioni sono state definite utilizzando un’altra comodissima routine, che è interp1: questa funzione prende in input (nel nostro caso) due vettori (uno di tempi e uno dei valori del momento) ed uno scalare. Utilizzando una semplice interpolazione lineare permette di restituire un valore della funzione al tempo t, interpolando i valori di M che sono stati forniti a determinati istanti di tempo. In pratica, tu gli dici quanto vale M al tempo 0, 1 e 5, lui ti dice quanto vale M in un qualsiasi istante compreso nell’intervallo [1,5], interpolando linearmente. Le funzionalità di interp1 sono molto più vaste, ma nel nostro caso la utilizziamo semplicemente per questo.

Vediamo ora come impostare il calcolo vero e proprio.

Mostra codice ▼

La funzione odeset permette di impostare i parametri relativi all’algoritmo di integrazione. Senza addentrarci troppo nel suo funzionamento, ci limitiamo a settare i parametri di precisione, il cui valore influenza pesantemente il tempo di integrazione.

La funzione waitbar, come dice il nome, permette di creare una barra di caricamento a partire da un valore compreso tra 0 e 1, che nel nostro caso sarà l’intervallo di tempo di integrazione normalizzato. È una funzione comodissima, da quando l’ho scoperta la piazzo praticamente ovunque 😀

La funzione ode45 è quella che effettua l’integrazione. Per il funzionamento nel dettaglio si rimanda all’help di MATLAB, ma per quanto riguarda il nostro problema è sufficiente sapere che accetta in input una funzione (nel nostro caso eulero.m) che restituisce un vettore di sei righe, il cui valore è quello del secondo membro del sistema di equazioni differenziali (opportunamente modificato in modo da avere a primo membro le sole derivate prime delle variabili).

\left\{\begin{matrix}\dot{y}(1)=f_1(y,\ \ldots)\\ \dot{y}(2)=f_2(y,\ \ldots) \\ \ldots\end{matrix}\right.

La funzione che andiamo ad integrare dipende dal tempo t, dal vettore di stato y e da una serie di parametri aggiuntivi Par:

Mostra codice ▼

Questa funzione viene richiamata ad ogni step di integrazione. Il suo compito è valutare le derivate prime del vettore di stato y. Oltre a fare ciò, questa funzione aggiorna anche la barra di caricamento ad ogni step. In questo modo potremo sapere graficamente a che punto dell’integrazione siamo arrivati.

La terza parte del codice, la più divertente, è quella che mostra graficamente i risultati dell’integrazione.

Mostra codice ▼

Vengono create due finestre: nella prima viene mostrato l’andamento degli angoli di Eulero, nella seconda l’animazione di un corpo che si muove secondo gli angoli di Eulero trovati.

La prima figura è molto semplice. L’unica particolarità è che gli angoli\theta e\phi vengono limitati agli intervalli [-180, 180] e [0, 360].

angoliPrima di procedere con l’animazione è necessario conoscere un comportamento peculiare di ode45: insieme al vettore Y contenente le variabili di stato integrate, viene restituito anche un vettore temporale T cui corrispondono gli istanti di tempo relativi ad Y. Questo vettore è, generalmente, non lineare. ode45 ha infatti la capacità di modificare il passo di integrazione rendendolo più o meno fitto a seconda della variazione del vettore di stato. Se utilizzassimo questo vettore senza modificarlo, il risultato sarebbe un video che va piano quando ci sono variazioni irregolari di Y e veloce quando Y è più regolare.
Per ottenere un’animazione fisicamente realistica dobbiamo quindi linearizzare il tempo.

In questo caso, ho deciso di prendere 300 time-step per ogni secondo di simulazione (dovreste metterlo più grande se il vostro computer è performante, più piccolo nel caso contrario). La funzione linspace genera un vettore equidistanziato tra 0 e tfin. La funzione interp1 permette di valutare il vettore di stato in questi nuovi istanti di tempo, interpolando il vettore risultato di ode45.

Gli oggetti che vengono rappresentati graficamente sono tre: un cilindro, l’asse del disco e la sua traccia. Il cilindro ha sempre le stesse dimensioni, indipendentemente dai valori dei momenti di inerzia impostati. Ciò può essere fuorviante nel caso in cui A e B siano diversi tra loro (es. case 3), ma non importa.

Sia per la rappresentazione del cilindro che per l’asse, è necessario utilizzare la matrice dei coseni direttori. Questa matrice consente di rappresentare un generico vettore[x_0,\ y_0,\ z_0] utilizzando gli angoli di Eulero. Per chi avesse installato l’Aerospace Toolbox di MATLAB, esiste una funzione angle2dcm che consente di scrivere una matrice di rotazione per una qualsiasi sequenza di rotazioni.
Dato che non tutti hanno questo strumento, ho aggiunto al codice la funzione ang2dcm, la quale non è altro che una versione semplificata di angle2dcm limitata alla sola sequenza XYZ, che è quella che ho utilizzato.

La traccia dell’asse viene mostrata soltanto per gli ultimi 150 timestep, in modo da non appesantire la rappresentazione grafica.

Nel codice sono presenti una serie di istruzioni commentate riferenti la variabile Mov e la funzione getframe. Questa funzione permette di acquisire l’immagine della figure per poterne creare successivamente un video. Se la utilizzate, tenete presente che richiede molta RAM e rallenta notevolmente il codice.

Assi giunti

giroscopioSpesso i giroscopi si studiano utilizzando un sistema di riferimento diverso da quello utilizzato da me. Si considera il giroscopio montato su uno snodo cardanico (vedi figura) e si scrivono angoli e momenti rispetto agli assi degli snodi.

Questa formulazione è molto più conveniente da un punto di vista pratico, ma porta ad una formulazione delle equazioni più articolata. Senza addentrarci troppo nel discorso, la differenza sostanziale nell’utilizzo di ode45 per questo tipo di sistema è che una delle equazioni presenta due termini del secondo ordine. Per questo motivo è necessario impostare mediante odeset una matrice di massa (funzione come al solito di yt) previa scrittura del sistema in questa forma:

equazione

La matrice di massa funziona esattamente come la funzione eulero.m. Notare che nel nostro caso la matrice di massa non è stata impostata, anche se questa corrisponderebbe alla matrice identità.

Video

Ecco infine i video dei 4 case proposti:

retrogrado spirale notadisk piccolo

– Download del codice – eulero.zip


MATLAB Cheatsheet – Riassunto comandi

Troppo spesso mi è capitato di imparare ad utilizzare MATLAB e poi di dimenticare tutto a causa di lunghi periodi di inutilizzo.

“Come si chiamava quella funzione?”
“Com’è che si faceva a fare… ?”
“Che sintassi usavo per fare quel coso… ?”

Ma stavolta ho detto basta! E così mi sono deciso a scrivere un file in cui ho riassunto tutte le funzioni, i costrutti e le cose (imho) più utili da ricordare di MATLAB. Il risultato è questo pratico cheatsheet  che ho deciso di condividere con tutti.

Se avete consigli o suggerimenti per migliorarlo, scrivetelo nei commenti.

Download MATLAB cheatsheet (.PDF) – 92 kB


PyFoil 1.2

Ecco la nuova versione della mia applicazione PyFoil, sviluppata in Python per Symbian S60.

Purtroppo a causa della mancanza di tempo non sono riuscito a completarla e sono presenti alcuni bug che segnalo stesso in questa pagina:

  • I dati sulla pressione e la temperatura nella stratosfera non vengono calcolati correttamente
  • Il calcolo del centro aerodinamico dell’ala non è corretto in caso di angolo di freccia
  • Il calcolo del coefficiente di momento non è corretto
  • È possibile settare i dati del piano di coda orizzontale, ma questi non vengono ancora utilizzati per fare calcoli

L’applicazione è comunque in grado di calcolare svariati parametri geometrici e aerodinamici sull’ala, impostandone caratteristiche alla radice e all’estremità.

Segue il codice del programma.
Leggi il resto dell’articolo »


PyFoil 1.1

Sto continuando lo sviluppo dell’applicazione presentata in un precedente articolo, PyFoil.

PyFoil è scritto in Python per dispositivi mobili Symbian. Per utilizzarlo è necessario installare PyS60 sul proprio cellulare.

La versione precedente a questa era in grado solo di disegnare profili alari, in questa versione ho migliorato questa funzione e ne ho aggiunte di nuove.
L’applicazione è divisa in quattro schede:

  • Intro: è una semplice scheda di introduzione sul programma
  • Plot: permette di disegnare un NACA a 4 o 5 cifre e di esportare l’immagine in un file
  • Group: permette il calcolo di alcuni gruppi adimensionali quali Reynolds, Mach e Froude, a partire da diversi parametri
  • ISA: restituisce i parametri dell’Atmosfera Standard in base all’altitudine, espressa in metri o piedi.

Prossimi sviluppi: l’obiettivo è quello di creare un’applicazione che possa essere da supporto (mobile) ad un ingegnere aerospaziale. Le prossime funzioni riguarderanno: la risoluzione del campo di moto attorno ai profili con relative informazioni connesse; aumento del numero di gruppi adimensionali calcolabili; calcolo di informazioni relative all’ala.

Bug noti: il calcolo di densità e pressione nell’ISA utilizza la stessa funzione sia per la troposfera che per la stratosfera, che è un errore. Purtroppo la formula del calcolo in stratosfera mi dava qualche errore e ho dovuto fare questa semplificazione che risolverò nella prossima versione.

Alcuni screenshot:

Segue il codice del programma.
Leggi il resto dell’articolo »