Differences
This shows you the differences between two versions of the page.
— |
pub:labprog:2020-11-26 [2020/11/26 17:50] (current) atrent created |
||
---|---|---|---|
Line 1: | Line 1: | ||
+ | # Note lezione (26/11/2020) | ||
+ | |||
+ | lezione precedente sul wiki del corso: http://sl-lab.it/dokuwiki/doku.php/pub:labprog:home | ||
+ | |||
+ | |||
+ | ## Mem | ||
+ | |||
+ | Questo script funziona su linux, serve anche gnuplot. | ||
+ | |||
+ | ```bash | ||
+ | #!/bin/bash | ||
+ | # https://stackoverflow.com/questions/7998302/graphing-a-processs-memory-usage | ||
+ | |||
+ | # IMPORTANTE! limitare mem altrimenti crasha pc | ||
+ | LIMIT=2000000 # ok | ||
+ | #LIMIT=20000 # troppo poco | ||
+ | ulimit -m $LIMIT | ||
+ | ulimit -v $LIMIT | ||
+ | ulimit -a | ||
+ | |||
+ | #timeout 10 $* & # non va bene perché osserva il timeout invece del processo | ||
+ | $* & | ||
+ | PID=$! | ||
+ | |||
+ | echo === | ||
+ | while | ||
+ | kill -0 $PID 2>/dev/null | ||
+ | do | ||
+ | echo $(date +%s) $(ps --pid $PID -o %mem=) | ||
+ | #echo $(date +%s) $(ps --pid $PID -o drs=) | ||
+ | |||
+ | #ps --pid $PID -o pid=,%mem=,vsz= | ||
+ | done | tee prova.mon | gnuplot -p -e "set terminal x11 size 600,400; set yrange [0:3.2]; set ylabel 'mem'; set xlabel 'timestamp'; plot \"/dev/stdin\" with linespoints title 'memory'" | ||
+ | |||
+ | ``` | ||
+ | |||
+ | |||
+ | ```go | ||
+ | package main | ||
+ | |||
+ | import ( | ||
+ | "fmt" | ||
+ | "math/rand" | ||
+ | "time" | ||
+ | ) | ||
+ | |||
+ | const DIM = 10000000 // attenzione a non esagerare che un mio amico gli è morto il pc ;) | ||
+ | const SLEEP = 5 // nano | ||
+ | |||
+ | func main() { | ||
+ | attendo() | ||
+ | |||
+ | /* an int array with 5 elements */ | ||
+ | var balance [DIM]int | ||
+ | //var avg float32 | ||
+ | |||
+ | rand.Seed(time.Now().Unix()) | ||
+ | |||
+ | fmt.Println("riempio...") | ||
+ | for i, _ := range balance { | ||
+ | //fmt.Println(i) | ||
+ | balance[i] = rand.Intn(10000) | ||
+ | time.Sleep(SLEEP) // nano | ||
+ | } | ||
+ | |||
+ | attendo() | ||
+ | |||
+ | // copy | ||
+ | //fmt.Println(getAverage(balance)) | ||
+ | |||
+ | // pointer | ||
+ | fmt.Println(getAverage2(&balance)) | ||
+ | |||
+ | attendo() | ||
+ | } | ||
+ | |||
+ | func attendo() { | ||
+ | fmt.Println("attendo...") | ||
+ | time.Sleep(3 * time.Second) | ||
+ | fmt.Println("fine attesa") | ||
+ | } | ||
+ | |||
+ | func getAverage(arr [DIM]int) float64 { | ||
+ | var avg float64 | ||
+ | var sum int64 | ||
+ | |||
+ | fmt.Println("calcolo...") | ||
+ | for i, _ := range arr { | ||
+ | sum += int64(arr[i]) | ||
+ | time.Sleep(SLEEP) // nano | ||
+ | } | ||
+ | |||
+ | avg = float64(sum) / DIM | ||
+ | return avg | ||
+ | } | ||
+ | |||
+ | func getAverage2(arr *[DIM]int) float64 { | ||
+ | var avg float644 | ||
+ | var sum int64 | ||
+ | |||
+ | for i, _ := range arr { | ||
+ | sum += int64(arr[i]) | ||
+ | time.Sleep(SLEEP) // nano | ||
+ | } | ||
+ | |||
+ | avg = float64(sum) / DIM | ||
+ | return avg | ||
+ | } | ||
+ | |||
+ | ``` | ||
+ | |||
+ | |||
+ | ## Note esercizi consegnati in settimana (scorsa lezione) | ||
+ | |||
+ | ### problema lettura specifiche? o concezione di "specchio"? | ||
+ | |||
+ | ```go | ||
+ | func specchiaPunto(p *Punto) { | ||
+ | (*p).x = -p.x // MANTERREI STESSA SINTASSI A DESTRA E SINISTRA | ||
+ | (*p).y = p.y // inutile perché non cambia lo stato | ||
+ | return | ||
+ | } | ||
+ | o | ||
+ | func specchiaPunto(p *Punto) { | ||
+ | p.x = 0 - (p.x) | ||
+ | } | ||
+ | o | ||
+ | func funzSpecchio(p1 Punto) Punto { // restituisce invece di modificare | ||
+ | var p Punto | ||
+ | p.x = -p1.x | ||
+ | p.y = p1.y <<<<<<<<<<<<<< | ||
+ | return p | ||
+ | } | ||
+ | ``` | ||
+ | |||
+ | |||
+ | invece di | ||
+ | |||
+ | ```go | ||
+ | func specchiaPunto(p *Punto) { | ||
+ | (*p).x *= -1 // corretto | ||
+ | } | ||
+ | o | ||
+ | func specchiaPunto(p *Punto) { | ||
+ | (*p).x = -(*p).x // corretto | ||
+ | } | ||
+ | ``` | ||
+ | |||
+ | |||
+ | |||
+ | ### passaggio per puntatore inutile | ||
+ | |||
+ | ```go | ||
+ | func main() { | ||
+ | var contaNumeri [10]int | ||
+ | var parola string | ||
+ | n := 0 | ||
+ | fmt.Print("\nInserire una serie di parole terminate da \x22stop\x22:\n\n") | ||
+ | for { | ||
+ | fmt.Scan(&parola) | ||
+ | if parola == "stop" { | ||
+ | break | ||
+ | } | ||
+ | contaCifre(parola, &n, &contaNumeri) //A COSA SERVE n QUI? meglio fare un return nella fn | ||
+ | } | ||
+ | fmt.Printf("\n%d stringhe con cifre\n\n%v\n%v\n\n", n, numeri, contaNumeri) | ||
+ | } | ||
+ | |||
+ | func contaCifre(s string, n *int, x *[10]int) { | ||
+ | check := false | ||
+ | for _, r := range s { | ||
+ | if unicode.IsDigit(r) { | ||
+ | appo, _ := strconv.Atoi(string(r)) | ||
+ | (*x)[appo]++ | ||
+ | check = true | ||
+ | } | ||
+ | } | ||
+ | if check { | ||
+ | (*n)++ | ||
+ | } | ||
+ | } | ||
+ | ``` | ||
+ | |||
+ | |||
+ | ### ottimizzazione | ||
+ | |||
+ | ```go | ||
+ | //QUI PROBLEMA DI SPECIFICHE, ANDAVA MODIFICATO L'ARRAY SUL POSTO //AT: anche, ma mi ero concentrato sull'invocazione multipla di len | ||
+ | |||
+ | func reverse(a [DIM]int) [DIM]int { // passare per punt | ||
+ | for i := 0; len(a)-i-1 != i; i++ { //IO IN QUESTI CASI PREFERISCO IL > AL != //AT: claro! | ||
+ | a[i], a[len(a)-i-1] = a[len(a)-i-1], a[i] | ||
+ | } | ||
+ | return a | ||
+ | } | ||
+ | ``` | ||
+ | |||
+ | |||
+ | ### delega (OK) | ||
+ | |||
+ | ```go | ||
+ | func countdown(c *Clock) { | ||
+ | (*c).sec-- | ||
+ | if (*c).sec < 0 { | ||
+ | (*c).sec = 59 | ||
+ | changeMin(&c) // "bastava" 'c' (è GIA' un puntatore, quindi '&c' è puntatore a puntatore) | ||
+ | } | ||
+ | } | ||
+ | |||
+ | func changeMin(c **Clock) { // idem | ||
+ | (**c).min-- | ||
+ | if (**c).min < 0 { | ||
+ | (**c).min = 59 | ||
+ | changeHour(&c) | ||
+ | } | ||
+ | } | ||
+ | |||
+ | func changeHour(c ***Clock) { // idem | ||
+ | (***c).hour-- | ||
+ | if (***c).hour < 0 { // questo no se no non termina | ||
+ | (***c).hour = 23 | ||
+ | } | ||
+ | } | ||
+ | ``` | ||
+ | |||
+ | ### compattabile | ||
+ | |||
+ | ```go | ||
+ | //INVITA A FARE GLI ESERCIZI TUTTI E NELL'ORDINE IN CUI SONO PROPOSTI, LEGGENDO SUGGERIMENTI ECC // diventa istruzione singola (c'era esercizio che suggeriva il modo) | ||
+ | |||
+ | |||
+ | BASTAVA 'num_comparsi[char]++' | ||
+ | al posto di: | ||
+ | |||
+ | switch char { | ||
+ | case '0': | ||
+ | num_comparsi[0]++ | ||
+ | case '1': | ||
+ | num_comparsi[1]++ | ||
+ | case '2': | ||
+ | num_comparsi[2]++ | ||
+ | case '3': | ||
+ | num_comparsi[3]++ | ||
+ | case '4': | ||
+ | num_comparsi[4]++ | ||
+ | case '5': | ||
+ | num_comparsi[5]++ | ||
+ | case '6': | ||
+ | num_comparsi[6]++ | ||
+ | case '7': | ||
+ | num_comparsi[7]++ | ||
+ | case '8': | ||
+ | num_comparsi[8]++ | ||
+ | case '9': | ||
+ | num_comparsi[9]++ | ||
+ | default: | ||
+ | continue | ||
+ | } | ||
+ | |||
+ | ``` | ||
+ | |||
+ | ### compattabile valori di n da 1 a 9 (oppure array! c'era indicazione nel testo) | ||
+ | |||
+ | ```go | ||
+ | func carta(n int) (carta Carta) { | ||
+ | switch n % VALORI { | ||
+ | case 0: | ||
+ | carta.valore = "A" | ||
+ | case 1: | ||
+ | carta.valore = "2" | ||
+ | case 2: | ||
+ | carta.valore = "3" | ||
+ | case 3: | ||
+ | carta.valore = "4" | ||
+ | case 4: | ||
+ | carta.valore = "5" | ||
+ | case 5: | ||
+ | carta.valore = "6" | ||
+ | case 6: | ||
+ | carta.valore = "7" | ||
+ | case 7: | ||
+ | carta.valore = "8" | ||
+ | case 8: | ||
+ | carta.valore = "9" | ||
+ | case 9: | ||
+ | carta.valore = "10" | ||
+ | case 10: | ||
+ | carta.valore = "J" | ||
+ | case 11: | ||
+ | carta.valore = "Q" | ||
+ | case 12: | ||
+ | carta.valore = "K" | ||
+ | } | ||
+ | |||
+ | switch n / VALORI { | ||
+ | case 0: | ||
+ | carta.seme = CUORI | ||
+ | case 1: | ||
+ | carta.seme = QUADRI | ||
+ | case 2: | ||
+ | carta.seme = FIORI | ||
+ | case 3: | ||
+ | carta.seme = PICCHE | ||
+ | } | ||
+ | |||
+ | return | ||
+ | } | ||
+ | ``` | ||
+ | |||
+ | ### trovare la variabile "inutilizzata" | ||
+ | |||
+ | ```go | ||
+ | func main() { | ||
+ | var s string | ||
+ | var nStringhe int | ||
+ | var count [DIM]int | ||
+ | arr := [DIM]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} | ||
+ | |||
+ | for { | ||
+ | fmt.Scan(&s) | ||
+ | if s == "stop" { | ||
+ | break | ||
+ | } | ||
+ | |||
+ | temp, ok := contaCifre(s) | ||
+ | if !ok { | ||
+ | continue | ||
+ | } | ||
+ | |||
+ | for i, x := range temp { | ||
+ | count[i] += x | ||
+ | } | ||
+ | nStringhe++ | ||
+ | } | ||
+ | |||
+ | fmt.Println(nStringhe, "stringhe con cifre.") | ||
+ | fmt.Println(arr) // per stampare una stringa formattata?!? | ||
+ | fmt.Println(count) | ||
+ | } | ||
+ | |||
+ | // poi probabilmente l'intenzione era di avere una "stringa" da stampare sotto a nStringhe... | ||
+ | ``` | ||
+ | |||
+ | ### compattare | ||
+ | |||
+ | (err è bool) | ||
+ | |||
+ | ```go | ||
+ | if err == true { | ||
+ | fmt.Println("Errore, valore non valido. Esecuzione interrotta") | ||
+ | return | ||
+ | } | ||
+ | ``` | ||
+ | |||
+ | |||
+ | ### lettura specifiche (o problemi implementazione) | ||
+ | |||
+ | Era da fare SENZA array di appoggio | ||
+ | ```go | ||
+ | /* scambia il primo con l'ultimo dei valori in un array | ||
+ | di dimensione DIM */ | ||
+ | func switchFirstLast(originale *[DIM]int) { | ||
+ | var ArrayDiAppoggio [DIM]int | ||
+ | ArrayDiAppoggio = *originale | ||
+ | originale[0] = ArrayDiAppoggio[DIM-1] | ||
+ | originale[DIM-1] = ArrayDiAppoggio[0] | ||
+ | } | ||
+ | |||
+ | ``` | ||
+ | ### non scalabile | ||
+ | |||
+ | ```go | ||
+ | var array [DIM]int | ||
+ | array[0] = 1 | ||
+ | array[1] = 2 | ||
+ | array[2] = 3 | ||
+ | array[3] = 4 | ||
+ | array[4] = 5 | ||
+ | array[5] = 6 | ||
+ | |||
+ | // meglio usare un for | ||
+ | ``` | ||
+ | ### ripensarlo? | ||
+ | ```go | ||
+ | func estraiCarta(n int) Carta { | ||
+ | var carta Carta | ||
+ | |||
+ | if n >= 0 && n <= 12 { | ||
+ | carta.seme = "di cuori" | ||
+ | } else if n >= 13 && n <= 25 { | ||
+ | carta.seme = "di quadri" | ||
+ | } else if n >= 26 && n <= 38 { | ||
+ | carta.seme = "di fiori" | ||
+ | } else if n >= 39 && n <= 51 { | ||
+ | carta.seme = "di picche" | ||
+ | } | ||
+ | if n == 0 || n == 13 || n == 26 || n == 39 { | ||
+ | carta.valore = "Asso" | ||
+ | } else if n == 1 || n == 14 || n == 27 || n == 40 { | ||
+ | carta.valore = "Due" | ||
+ | } else if n == 2 || n == 15 || n == 28 || n == 41 { | ||
+ | carta.valore = "Tre" | ||
+ | } else if n == 3 || n == 16 || n == 29 || n == 42 { | ||
+ | carta.valore = "Quattro" | ||
+ | } else if n == 4 || n == 17 || n == 30 || n == 43 { | ||
+ | carta.valore = "Cinque" | ||
+ | } else if n == 5 || n == 18 || n == 31 || n == 44 { | ||
+ | carta.valore = "Sei" | ||
+ | } else if n == 6 || n == 19 || n == 32 || n == 45 { | ||
+ | carta.valore = "Sette" | ||
+ | } else if n == 7 || n == 20 || n == 33 || n == 46 { | ||
+ | carta.valore = "Otto" | ||
+ | } else if n == 8 || n == 21 || n == 34 || n == 47 { | ||
+ | carta.valore = "Nove" | ||
+ | } else if n == 9 || n == 22 || n == 35 || n == 48 { | ||
+ | carta.valore = "Dieci" | ||
+ | } else if n == 10 || n == 23 || n == 36 || n == 49 { | ||
+ | carta.valore = "J" | ||
+ | } else if n == 11 || n == 24 || n == 37 || n == 50 { | ||
+ | carta.valore = "Q" | ||
+ | } else if n == 12 || n == 25 || n == 38 || n == 51 { | ||
+ | carta.valore = "K" | ||
+ | } | ||
+ | return carta | ||
+ | } | ||
+ | |||
+ | ``` | ||
+ | |||
+ | ### switchabile ma cmq BASTA UNA SOLA ISTRUZIONE | ||
+ | |||
+ | BASTAVA una cosa tipo: ```'ripetizioniNumeri[strInput[i]-'0']++' ```(a meno di una conversione) | ||
+ | |||
+ | ```go | ||
+ | if strInput[i] == '0' { | ||
+ | ripetizioniNumeri[0]++ | ||
+ | } else if strInput[i] == '1' { | ||
+ | ripetizioniNumeri[1]++ | ||
+ | } else if strInput[i] == '2' { | ||
+ | ripetizioniNumeri[2]++ | ||
+ | } else if strInput[i] == '3' { | ||
+ | ripetizioniNumeri[3]++ | ||
+ | } else if strInput[i] == '4' { | ||
+ | ripetizioniNumeri[4]++ | ||
+ | } else if strInput[i] == '5' { | ||
+ | ripetizioniNumeri[5]++ | ||
+ | } else if strInput[i] == '6' { | ||
+ | ripetizioniNumeri[6]++ | ||
+ | } else if strInput[i] == '7' { | ||
+ | ripetizioniNumeri[7]++ | ||
+ | } else if strInput[i] == '8' { | ||
+ | ripetizioniNumeri[8]++ | ||
+ | } else if strInput[i] == '9' { | ||
+ | ripetizioniNumeri[9]++ | ||
+ | } | ||
+ | ``` | ||
+ | |||
+ | ## Note su slice e mappe | ||
+ | |||
+ | #### Dichiarazione di una map: | ||
+ | |||
+ | sintassi: `var map1 map[keytype]valuetype` | ||
+ | |||
+ | es: `var map1 map[string]int` | ||
+ | |||
+ | #### Allocazione(creazione)/inizializzazione di una map | ||
+ | |||
+ | sintassi: `map1 := make(map[keytype]valuetype)` | ||
+ | o anche: `map1 := map[keytype]valuetype{} // tra {} ci può essere una lista di coppie chiave-valore` | ||
+ | |||
+ | es: `map1 := make(map[string]float64)` | ||
+ | o anche: `map1 := map[string]float64{} | ||
+ | map1 := map[string]float64{"zero" : 0., "uno" : 1.} | ||
+ | }` | ||
+ | |||
+ | #### Dichiarazione di una slice: | ||
+ | |||
+ | sintassi: `var slice []type` | ||
+ | |||
+ | es: `var slice []int` | ||
+ | |||
+ | #### Allocazione(creazione)/inizializzazione di una slice | ||
+ | |||
+ | sintassi: | ||
+ | ```go | ||
+ | slice := make([]type, length, capacity) | ||
+ | slice := make([]type, length) //la capacità può non essere specificata | ||
+ | | ||
+ | slice := []type{} // tra {} ci può essere una lista di valori | ||
+ | ``` | ||
+ | |||
+ | es: | ||
+ | ```go | ||
+ | slice := make([]int, 0, 5) | ||
+ | slice := []int{} | ||
+ | slice := []int{1, 2, 3, 4} | ||
+ | ``` | ||
+ | |||
+ | #### Differenza tra ```new``` e ```make```: | ||
+ | |||
+ | - ```new(T)``` alloca memoria per un nuovo elemento di tipo T e restituisce il suo indirizzo, quindi un valore di tipo *T (un puntatore) | ||
+ | |||
+ | - ```make(T)``` restituisce un valore di tipo T; si applica solo ai tipi riferimento predefiniti: slice, mappe (e canali). | ||
+ | |||
+ | In altre parole, ```new``` alloca, ```make``` inizializza | ||
+ | |||
+ | |||
+ | #### Funzioni built-in per slice | ||
+ | (vedi documentazione packages, sotto builtin) | ||
+ | |||
+ | - ```func append(slice []Type, elems ...Type) []Type``` | ||
+ | es: | ||
+ | ```go | ||
+ | slice = append(slice, elem1, elem2) | ||
+ | slice = append(slice, anotherSlice...) | ||
+ | ``` | ||
+ | - ```func copy(dest, src []Type) int``` | ||
+ | |||
+ | ## Note generali (slegate dagli esercizi) | ||
+ | |||
+ | Non è necessario utilizzare una variabile di appoggio quando dovete scambiare di valore due variabili (*nota: non è possibile farlo in tutti i linguaggi, ma in questo si*) | ||
+ | |||
+ | ```go | ||
+ | a := 1 | ||
+ | b := 2 | ||
+ | a, b = b, a // fantastico! | ||
+ | ``` | ||
+ | |||
+ | --- | ||
+ | |||
+ | I calcoli devono essere fatti dal computer, non da voi. Cercate sempre di trovare un *pattern/formula* per risolvere i prolemi che si presentano, sopratutto se sono di assegnamento, tipo: si deve inizializzare un array di 5 elementi con i valori 0..4 -> usate un for, non inizializzate ogni posizione in modo esplicito | ||
+ | |||
+ | Lo stesso discorso vale per lo switch: dove si può compattare, si compatta, senza mai fare calcoli espliciti. | ||
+ | |||
+ | --- | ||
+ | |||
+ | Per stampare le rune: | ||
+ | |||
+ | ```go | ||
+ | fmt.Printf("%c", <carattere>) | ||
+ | //oppure | ||
+ | fmt.Println(string(<carattere>)) | ||
+ | ``` | ||
+ | |||
+ | --- | ||
+ | |||
+ | |||
+ | |||
+ | ## FAQ | ||
+ | |||
+ | ### NumToText (svolto insieme) | ||
+ | |||
+ | #### mappe - costruzione e uso | ||
+ | |||
+ | Scrivere un programma ```num2text.go``` per convertire un numero | ||
+ | intero non negativo nella sequenza delle parole corrispondenti | ||
+ | alle sue cifre. | ||
+ | Il programma legge un intero non negativo da standard input, | ||
+ | per ogni nuova (non incontrata finora) cifra del numero | ||
+ | chiede il nome corrispondente (e alimenta un dizionario), e infine | ||
+ | stampa la sequenza delle parole corrispondenti alle sue cifre. | ||
+ | Ad esempio, per il numero 203, il programma stampa | ||
+ | due - zero - tre | ||
+ | |||
+ | #### Esempio di esecuzione | ||
+ | |||
+ | ``` | ||
+ | $ go run num2text.go | ||
+ | un numero: 622 | ||
+ | parola per 2 ? due | ||
+ | parola per 6 ? sei | ||
+ | sei - due - due | ||
+ | ``` | ||
+ | |||
+ | ```go | ||
+ | package main | ||
+ | |||
+ | import "fmt" | ||
+ | |||
+ | func main(){ | ||
+ | | ||
+ | var m map[int]string | ||
+ | m = make(map[int]string) | ||
+ | | ||
+ | var n int | ||
+ | var nome string | ||
+ | fmt.Print("Inserire un numero intero: ") | ||
+ | fmt.Scan(&n) | ||
+ | | ||
+ | parola := "" | ||
+ | for n!=0{ | ||
+ | cifra:=n%10 | ||
+ | //fmt.Println(cifra) | ||
+ | _,ok:=m[cifra] // cerca valore mappato di 'cifra', se non lo trova restituisce false | ||
+ | if !ok{ | ||
+ | fmt.Printf("parola per %d? ",cifra) | ||
+ | fmt.Scan(&nome) | ||
+ | m[cifra]=nome | ||
+ | } | ||
+ | parola = m[cifra] + " - " + parola | ||
+ | n=n/10 | ||
+ | } | ||
+ | | ||
+ | fmt.Println(parola[:len(parola)-3]) | ||
+ | // fmt.Println(m) | ||
+ | | ||
+ | } | ||
+ | ``` | ||
+ | |||
+ | ### Vocali | ||
+ | |||
+ | Nelle mappe, non c'è di norma un ordinamento delle chiavi | ||
+ | |||
+ | --- | ||
+ | |||
+ | Potete implementare una funzione che stampa la mappa, al posto di usare `Print(mappa)` | ||
+ | |||
+ | --- | ||
+ | |||
+ | Per la stampa ordinata: potete usare una stringa di appoggio, sapete già quali sono le vocali e in quale ordine sono | ||
+ | |||
+ | ### Anagrammi | ||
+ | |||
+ | Per "estrarre" una runa da una stringa: chiedetevi come sono "definite" le stringhe.. | ||
+ | |||
+ | --- | ||
+ | |||
+ | Linea di comando = parametri del `main` | ||
+ | |||
+ | ### Galleggianti | ||
+ | |||
+ | |||
+ | --- | ||
+ | |||
+ | ### Operazioni_slice | ||
+ | |||
+ | --- | ||
+ | |||
+ | ### Appello | ||
+ | |||
+ | --- | ||
+ | |||
+ | ### Temperature | ||
+ | |||
+ | --- | ||
+ | |||
+ | ### Posizioni_parole | ||