Introduzione al Mondo degli Oggetti JavaScript
Nel vasto e dinamico universo della programmazione web, JavaScript regna sovrano come il linguaggio che dà vita all'interattività dei siti. Uno dei suoi concetti più fondamentali e onnipresenti è quello degli oggetti. Gli oggetti sono collezioni di proprietà, dove ogni proprietà ha un nome (una "chiave") e un valore associato. Pensali come dei contenitori intelligenti che organizzano i dati in modo logico e strutturato.
Immagina di dover gestire le informazioni di un utente: nome, email, età, ruolo. Invece di avere quattro variabili separate, puoi raggrupparle in un unico oggetto utente. Questo rende il codice più leggibile, manutenibile e scalabile. Ma cosa succede quando hai un oggetto e vuoi accedere a tutte le sue chiavi, a tutti i suoi valori, o a entrambe le cose contemporaneamente? È qui che entrano in gioco tre metodi potentissimi e indispensabili: Object.keys(), Object.values(), e Object.entries().
Questi metodi, introdotti con ECMAScript 2015 (ES6) e successivi, hanno rivoluzionato il modo in cui interagiamo con gli oggetti in JavaScript, offrendo soluzioni eleganti e performanti per estrarre e manipolare i dati. Se sei un principiante nel mondo della programmazione web, capire a fondo questi strumenti ti darà una base solida per lavorare con i dati provenienti da API, form o qualsiasi altra fonte.
In questo articolo, esploreremo in dettaglio ciascuno di questi metodi, capiremo quando e perché usarli, e li metteremo in pratica con numerosi esempi chiari e contestualizzati, adatti anche a chi è alle prime armi. Preparati a sbloccare nuove possibilità nella gestione dei tuoi dati JavaScript!
I Fondamentali degli Oggetti in JavaScript: Un Breve Ripasso
Prima di immergerci nei dettagli di Object.keys, Object.values e Object.entries, facciamo un rapido ripasso su come funzionano gli oggetti in JavaScript. Un oggetto è una collezione di coppie "chiave-valore". Le chiavi sono tipicamente stringhe (o simboli), mentre i valori possono essere di qualsiasi tipo di dato: numeri, stringhe, booleani, array, altre funzioni, o persino altri oggetti.
Ecco un esempio semplice di un oggetto:
const prodotto = {
nome: "Laptop Pro",
prezzo: 1200,
disponibile: true,
categorie: ["elettronica", "informatica"],
specifiche: {
ram: "16GB",
storage: "512GB SSD"
}
};
console.log(prodotto.nome); // Output: Laptop Pro
console.log(prodotto["prezzo"]); // Output: 1200
Come puoi vedere, accediamo alle proprietà usando la dot notation (.) o la bracket notation ([]). Ma cosa succede se volessimo ottenere un elenco di tutti i nomi delle proprietà, o tutti i valori, senza sapere a priori quali sono? È qui che i metodi Object.keys(), Object.values() e Object.entries() diventano estremamente utili. Essi ci permettono di "ispezionare" l'oggetto in modo dinamico, estraendo le sue componenti principali in un formato più gestibile: gli array.
È importante notare che questi metodi lavorano solo con le proprietà proprie ed enumerabili dell'oggetto. Le proprietà enumerabili sono quelle che possono essere iterate (ad esempio, tramite un ciclo for...in), e la maggior parte delle proprietà che definisci direttamente sugli oggetti sono enumerabili per impostazione predefinita. Le proprietà ereditate dalla catena di prototipi dell'oggetto non vengono considerate, garantendo che tu stia lavorando solo con i dati direttamente definiti sull'istanza dell'oggetto in questione.
Object.keys(): Estraiamo le Chiavi degli Oggetti
Il metodo Object.keys() è il tuo migliore amico quando hai bisogno di un elenco di tutti i nomi delle proprietà (le "chiavi") di un oggetto. Immagina di ricevere dati da un'API e di voler sapere quali campi sono presenti in quell'oggetto, magari per costruire dinamicamente un'interfaccia utente o per validare i dati. Object.keys() fa esattamente questo.
Come Funziona Object.keys()
Object.keys() prende un oggetto come argomento e restituisce un array di stringhe, dove ogni stringa è il nome di una proprietà enumerabile dell'oggetto. L'ordine delle chiavi nell'array è lo stesso dell'ordine di inserimento delle proprietà nell'oggetto, per le proprietà non numeriche (un comportamento garantito da ES2015 in poi).
Sintassi:
Object.keys(obj)
Dove obj è l'oggetto di cui vuoi estrarre le chiavi.
Esempi Pratici con Object.keys()
Vediamo alcuni scenari in cui Object.keys() è incredibilmente utile.
Esempio 1: Elenco Semplice di Chiavi
Supponiamo di avere un oggetto che rappresenta le impostazioni di un'applicazione e vogliamo elencare tutte le impostazioni disponibili.
const impostazioniApp = {
tema: "dark",
lingua: "italiano",
notifiche: true,
sincronizzazione: false
};
const chiaviImpostazioni = Object.keys(impostazioniApp);
console.log(chiaviImpostazioni); // Output: ["tema", "lingua", "notifiche", "sincronizzazione"]
Ora abbiamo un array con tutte le chiavi, che possiamo facilmente iterare o manipolare.
Esempio 2: Iterazione e Accesso Dinamico
Conoscere le chiavi ci permette di accedere ai valori in modo dinamico. Questo è particolarmente utile quando non conosciamo in anticipo i nomi delle proprietà.
const utente = {
id: 101,
nome: "Mario Rossi",
email: "mario.rossi@example.com",
ruolo: "admin"
};
const proprietaUtente = Object.keys(utente);
console.log("Proprietà dell'utente:");
proprietaUtente.forEach(chiave => {
console.log(`${chiave}: ${utente[chiave]}`);
});
/* Output:
Proprietà dell'utente:
id: 101
nome: Mario Rossi
email: mario.rossi@example.com
ruolo: admin
*/
In questo esempio, Object.keys() ci dà un array di chiavi, e poi usiamo forEach per iterare su queste chiavi. All'interno del ciclo, usiamo la bracket notation (utente[chiave]) per accedere al valore corrispondente a ogni chiave. Questo è un pattern molto comune e potente nella programmazione web.
Esempio 3: Controllare la Presenza di Campi
Possiamo usare Object.keys() per verificare se un oggetto contiene un certo numero o tipo di campi.
const datiForm = {
username: "user123",
password: "securepassword",
email: "user@example.com"
};
const campiRichiesti = ["username", "password", "email"];
const campiPresenti = Object.keys(datiForm);
const tuttiPresenti = campiRichiesti.every(campo => campiPresenti.includes(campo));
if (tuttiPresenti) {
console.log("Tutti i campi richiesti sono presenti.");
} else {
console.log("Mancano alcuni campi richiesti.");
}
Qui, confrontiamo le chiavi estratte con un array di campi richiesti per una validazione semplice.
Object.values(): Accediamo ai Valori degli Oggetti
Se Object.keys() ti fornisce i nomi delle proprietà, Object.values() si concentra sui dati che contengono. Questo metodo è perfetto quando non ti interessa il nome della proprietà, ma solo il valore associato. Immagina di voler sommare tutti i prezzi di prodotti in un carrello, o di voler visualizzare un elenco di tutti i tag associati a un articolo.
Come Funziona Object.values()
Object.values() prende un oggetto come argomento e restituisce un array dei valori delle proprietà enumerabili dell'oggetto. Anche qui, l'ordine dei valori nell'array corrisponde all'ordine di inserimento delle proprietà nell'oggetto.
Sintassi:
Object.values(obj)
Dove obj è l'oggetto di cui vuoi estrarre i valori.
Esempi Pratici con Object.values()
Vediamo come Object.values() può semplificare la manipolazione dei dati.
Esempio 1: Estrazione Semplice di Valori
Consideriamo un oggetto che mappa i codici dei paesi ai loro nomi completi.
const paesi = {
IT: "Italia",
FR: "Francia",
DE: "Germania",
ES: "Spagna"
};
const nomiPaesi = Object.values(paesi);
console.log(nomiPaesi); // Output: ["Italia", "Francia", "Germania", "Spagna"]
Abbiamo ottenuto un array pulito con solo i nomi dei paesi.
Esempio 2: Calcolo della Somma di Valori Numerici
Questo è un caso d'uso classico per Object.values(), utile per calcolare totali o medie.
const venditeTrimestrali = {
Q1: 15000,
Q2: 18000,
Q3: 17500,
Q4: 20000
};
const valoriVendite = Object.values(venditeTrimestrali);
const totaleVendite = valoriVendite.reduce((acc, current) => acc + current, 0);
console.log(`Totale vendite annuali: ${totaleVendite} euro`); // Output: Totale vendite annuali: 70500 euro
Qui, Object.values() ci dà un array di numeri, che poi possiamo sommare facilmente usando il metodo reduce degli array. Questo è molto più conciso che ciclare manualmente sull'oggetto.
Esempio 3: Generare Contenuto Dinamico
Puoi usare Object.values() per popolare dinamicamente elementi HTML o liste.
const coloriPalette = {
primary: "#FF5733",
secondary: "#33FF57",
accent: "#3357FF"
};
const codiciColore = Object.values(coloriPalette);
console.log("Colori nella palette:");
codiciColore.forEach(colore => {
console.log(`- ${colore}`);
// In un contesto web reale, potresti creare un div con background: colore
});
/* Output:
Colori nella palette:
- #FF5733
- #33FF57
- #3357FF
*/
Questo mostra come i valori estratti possano essere usati direttamente per la presentazione dei dati.
Object.entries(): Tutto in Un Colpo Solo
Object.keys() e Object.values() sono utili individualmente, ma a volte hai bisogno di lavorare con la coppia chiave-valore completa per ogni proprietà. Object.entries() è il metodo che ti permette di fare proprio questo, fornendoti un array di array, dove ogni array interno contiene una coppia [chiave, valore].
Come Funziona Object.entries()
Object.entries() prende un oggetto come argomento e restituisce un array di array. Ogni array interno è una coppia [chiave, valore] corrispondente a una proprietà enumerabile dell'oggetto. L'ordine delle coppie è lo stesso dell'ordine di inserimento delle proprietà nell'oggetto.
Sintassi:
Object.entries(obj)
Dove obj è l'oggetto di cui vuoi estrarre le coppie chiave-valore.
Esempi Pratici con Object.entries()
Object.entries() è estremamente versatile e apre le porte a manipolazioni di dati più complesse.
Esempio 1: Estrazione Semplice di Coppie
Prendiamo un oggetto che descrive un libro.
const libro = {
titolo: "Il Signore degli Anelli",
autore: "J.R.R. Tolkien",
anno: 1954,
genere: "Fantasy"
};
const dettagliLibro = Object.entries(libro);
console.log(dettagliLibro);
/* Output:
[
["titolo", "Il Signore degli Anelli"],
["autore", "J.R.R. Tolkien"],
["anno", 1954],
["genere", "Fantasy"]
]
*/
Come puoi vedere, otteniamo un array di array, dove ogni array interno è una coppia [chiave, valore]. Questo formato è molto comodo per l'iterazione.
Esempio 2: Iterazione e Destructuring
Uno dei modi più potenti per usare Object.entries() è combinarlo con la destructuring assignment all'interno di un ciclo forEach o for...of. Questo ci permette di accedere direttamente a chiave e valore per ogni iterazione.
const configurazioneServer = {
host: "localhost",
port: 3000,
debugMode: true,
timeout: 5000
};
console.log("Configurazione del server:");
for (const [chiave, valore] of Object.entries(configurazioneServer)) {
console.log(`${chiave}: ${valore}`);
}
/* Output:
Configurazione del server:
host: localhost
port: 3000
debugMode: true
timeout: 5000
*/
Qui, for...of combinato con [chiave, valore] rende il codice incredibilmente leggibile e pulito per processare ogni coppia.
Esempio 3: Trasformazione di Dati e Filtri
Object.entries() è eccellente per trasformare o filtrare oggetti. Possiamo convertire l'oggetto in un array di entries, manipolarlo con metodi degli array (come filter o map), e poi, se necessario, riconvertirlo in un nuovo oggetto usando Object.fromEntries() (introdotto in ES2019).
const prodottiNegozio = {
mela: { prezzo: 1.2, scorte: 150 },
banana: { prezzo: 0.8, scorte: 200 },
arancia: { prezzo: 1.5, scorte: 0 }, // Esaurita
kiwi: { prezzo: 2.0, scorte: 75 }
};
// Filtriamo solo i prodotti disponibili (scorte > 0)
const prodottiDisponibiliEntries = Object.entries(prodottiNegozio).filter(
([nomeProdotto, dettagli]) => dettagli.scorte > 0
);
// Riconvertiamo in un oggetto (richiede Object.fromEntries, ES2019+)
const prodottiDisponibili = Object.fromEntries(prodottiDisponibiliEntries);
console.log("Prodotti disponibili:");
console.log(prodottiDisponibili);
/* Output:
Prodotti disponibili:
{
mela: { prezzo: 1.2, scorte: 150 },
banana: { prezzo: 0.8, scorte: 200 },
kiwi: { prezzo: 2.0, scorte: 75 }
}
*/
Questo esempio mostra una pipeline di trasformazione dati molto comune: da oggetto ad array di entries, filtro, e poi ritorno a oggetto. È un pattern potente per la manipolazione di oggetti complessi.
Confronto e Scenari d'Uso: Quando Usare Cosa?
Ora che abbiamo esplorato singolarmente Object.keys(), Object.values() e Object.entries(), è fondamentale capire quando scegliere l'uno o l'altro. La scelta dipende strettamente da ciò che vuoi ottenere dal tuo oggetto.
| Metodo | Restituisce un Array di... | Quando Usarlo |
|---|---|---|
Object.keys(obj) |
Stringhe (le chiavi) | - Hai bisogno di un elenco dei nomi delle proprietà. |
- Vuoi iterare sulle proprietà per accedere ai loro valori in modo dinamico (
obj[chiave]). - Devi verificare la presenza di specifiche chiavi o contare quante chiavi ha un oggetto. |
|
Object.values(obj)| Valori (i dati) | - Ti interessano solo i valori delle proprietà, non i loro nomi. - Devi eseguire operazioni aggregate sui valori (es. somma, media, ricerca).
- Vuoi visualizzare tutti i dati contenuti nell'oggetto, senza etichette. |
|
Object.entries(obj)| Array[chiave, valore]| - Hai bisogno di lavorare sia con la chiave che con il valore contemporaneamente. - Devi trasformare, filtrare o mappare le coppie chiave-valore dell'oggetto.
- Vuoi ricostruire un oggetto da un array di coppie chiave-valore (spesso con
Object.fromEntries). |
Esempi Pratici Aggiuntivi: Casi d'Uso Reali
Vediamo alcuni scenari più complessi che integrano questi metodi nel contesto della programmazione web.
Scenario 1: Elaborazione di Dati da API
Immagina di ricevere una risposta JSON da un'API che contiene dati su diversi prodotti, ma la struttura può variare leggermente. Vuoi visualizzare solo i prodotti con un prezzo superiore a un certo valore e mostrare sia il nome che il prezzo.
const datiAPI = {
prod123: { nome: "Smartphone", prezzo: 799, inStock: true },
prod456: { nome: "Cuffie Wireless", prezzo: 149, inStock: false },
prod789: { nome: "Smartwatch", prezzo: 299, inStock: true },
prod101: { nome: "Power Bank", prezzo: 39, inStock: true }
};
const prezzoMinimo = 200;
console.log(`Prodotti disponibili con prezzo superiore a ${prezzoMinimo}€:`)
Object.entries(datiAPI)
.filter(([, dettagliProdotto]) => dettagliProdotto.prezzo > prezzoMinimo && dettagliProdotto.inStock)
.forEach(([codiceProdotto, dettagli]) => {
console.log(`- ${dettagli.nome} (Codice: ${codiceProdotto}): ${dettagli.prezzo}€`);
});
/* Output:
Prodotti disponibili con prezzo superiore a 200€:
- Smartphone (Codice: prod123): 799€
- Smartwatch (Codice: prod789): 299€
*/
Qui, Object.entries() ci permette di accedere sia al codice del prodotto (la chiave) che ai suoi dettagli (il valore). Usiamo filter per selezionare i prodotti che soddisfano i criteri e forEach per visualizzarli, usando sia la chiave che il valore.
Scenario 2: Costruzione Dinamica di Query String URL
Supponiamo di avere un oggetto che rappresenta i parametri di una query HTTP e di voler costruire una stringa URL.
const parametriRicerca = {
query: "javascript tutorial",
category: "web-dev",
page: 1,
sort: "relevance"
};
const queryParts = Object.entries(parametriRicerca)
.map(([chiave, valore]) => `${encodeURIComponent(chiave)}=${encodeURIComponent(valore)}`);
const queryString = queryParts.join("&");
console.log(`URL della ricerca: /search?${queryString}`);
// Output: URL della ricerca: /search?query=javascript%20tutorial&category=web-dev&page=1&sort=relevance
In questo esempio, Object.entries() è fondamentale per trasformare ogni coppia chiave-valore in una parte della query string, gestendo anche la codifica degli URL con encodeURIComponent.
Scenario 3: Validazione di un Oggetto di Configurazione
Vuoi assicurarti che un oggetto di configurazione contenga solo chiavi permesse e che i loro valori siano del tipo corretto.
const configUtente = {
theme: "light",
fontSize: "medium",
notifications: true,
invalidKey: "oops"
};
const configPermessa = {
theme: String,
fontSize: String,
notifications: Boolean
};
const erroriConfig = [];
Object.keys(configUtente).forEach(key => {
if (!Object.keys(configPermessa).includes(key)) {
erroriConfig.push(`Chiave non valida: '${key}'`);
} else if (typeof configUtente[key] !== configPermessa[key].name.toLowerCase()) {
erroriConfig.push(`Tipo non corretto per '${key}'. Previsto: ${configPermessa[key].name.toLowerCase()}, Trovato: ${typeof configUtente[key]}`);
}
});
if (erroriConfig.length > 0) {
console.error("Errori di configurazione:", erroriConfig);
} else {
console.log("Configurazione valida.");
}
/* Output (con invalidKey):
Errori di configurazione: [
"Chiave non valida: 'invalidKey'"
]
*/
Qui, Object.keys() è usato sia per iterare sulle chiavi della configurazione utente sia per verificare la presenza di chiavi valide nell'oggetto configPermessa.
Considerazioni Avanzate e Best Practices
Mentre Object.keys(), Object.values() e Object.entries() sono relativamente semplici da usare, ci sono alcune considerazioni e best practice che ogni sviluppatore dovrebbe conoscere.
Immutabilità e Nuovi Array
È importante ricordare che tutti e tre i metodi restituiscono nuovi array. Non modificano l'oggetto originale. Questo è un aspetto fondamentale dell'immutabilità in JavaScript, che contribuisce a rendere il codice più prevedibile e meno soggetto a effetti collaterali indesiderati. Puoi manipolare l'array restituito senza preoccuparti di alterare l'oggetto da cui proviene.
Ordine delle Proprietà
Come accennato, a partire da ECMAScript 2015 (ES6), l'ordine delle proprietà restituite da questi metodi è garantito essere lo stesso dell'ordine di inserimento per le proprietà non numeriche (stringhe normali). Per le chiavi che possono essere convertite in indici di array (es. "0", "1", "2"), l'ordine è numerico crescente. Nella maggior parte dei casi pratici, non devi preoccuparti troppo dell'ordine, ma è un buon dettaglio da conoscere.
Proprietà Enumerabili e Non Enumerabili
Questi metodi considerano solo le proprietà proprie ed enumerabili dell'oggetto. Le proprietà ereditate dal prototipo non sono incluse, né lo sono le proprietà non enumerabili (come quelle che a volte vengono definite internamente da JavaScript o con Object.defineProperty se non si specifica enumerable: true). Questo comportamento è quasi sempre quello desiderato, in quanto ti consente di lavorare solo con i dati che hai esplicitamente definito sull'oggetto corrente.
Gestione di null e undefined
Tentare di chiamare Object.keys(), Object.values() o Object.entries() su un valore che non è un oggetto (come null o undefined) genererà un TypeError. Assicurati sempre che il tuo argomento sia un oggetto valido prima di invocare questi metodi, specialmente quando lavori con dati provenienti da fonti esterne che potrebbero essere imprevedibili.
const datiNullo = null;
// Object.keys(datiNullo); // Errore: TypeError: Cannot convert undefined or null to object
const datiUndefined = undefined;
// Object.values(datiUndefined); // Errore: TypeError: Cannot convert undefined or null to object
Un controllo semplice può prevenire questi errori:
const datiPotenzialmenteNullo = null;
if (typeof datiPotenzialmenteNullo === 'object' && datiPotenzialmenteNullo !== null) {
const keys = Object.keys(datiPotenzialmenteNullo);
console.log(keys);
} else {
console.log("L'argomento non è un oggetto valido.");
}
Performance (per i più curiosi)
Per la maggior parte delle applicazioni web e per oggetti di dimensioni ragionevoli, le differenze di performance tra questi metodi sono trascurabili. Sono tutti altamente ottimizzati. Concentrati sulla leggibilità e sulla correttezza logica del tuo codice piuttosto che su micro-ottimizzazioni, specialmente come principiante.
Errori Comuni e Come Evitarli
Anche se semplici, ci sono alcuni errori comuni che i principianti commettono quando usano Object.keys, Object.values e Object.entries.
-
Chiamare i Metodi su
nulloundefined: Come visto sopra, questo genera unTypeError. Soluzione: Controlla sempre che l'oggetto non sianulloundefinedprima di chiamare il metodo. -
Aspettarsi un Oggetto come Ritorno: Ricorda che tutti e tre i metodi restituiscono array, non oggetti. Se hai bisogno di un nuovo oggetto, dovrai usare
Object.fromEntries()(conObject.entries()) o costruire manualmente l'oggetto iterando l'array restituito. -
Dimenticare l'Immutabilità: Modificare l'array restituito non modificherà l'oggetto originale. Questo non è un errore in sé, ma una mancata comprensione può portare a risultati inattesi se ti aspetti che l'oggetto originale venga aggiornato.
-
Confondere Proprietà Proprie ed Ereditate: Questi metodi ignorano le proprietà ereditate. Se hai bisogno di accedere anche a quelle, dovrai usare un ciclo
for...ine poi filtrare conhasOwnProperty().const proto = { protoProp: "sono del prototipo" }; const obj = Object.create(proto); obj.ownProp = "sono mia"; console.log(Object.keys(obj)); // Output: ["ownProp"] // Per includere le proprietà ereditate (non il focus di questi metodi): for (let key in obj) { console.log(key); // Output: ownProp, protoProp } -
Non Usare la Destructuring con
Object.entries(): Mentre puoi accedere alle coppie comeentry[0]eentry[1], l'uso della destructuring ([chiave, valore]) rende il codice molto più leggibile e intuitivo.
Prossimi Passi e Risorse per Approfondire
Congratulazioni! Hai fatto un passo significativo nella comprensione di come manipolare gli oggetti in JavaScript, una competenza fondamentale per qualsiasi sviluppatore web. La padronanza di Object.keys(), Object.values() e Object.entries() ti renderà più efficiente nel gestire i dati e nel scrivere codice più pulito e funzionale.
Per continuare il tuo percorso di apprendimento, ti suggerisco di esplorare i seguenti argomenti:
Object.fromEntries(): Questo metodo (introdotto in ES2019) è il complemento perfetto diObject.entries(), permettendoti di trasformare un array di coppie[chiave, valore]nuovamente in un oggetto. È estremamente utile per pipeline di trasformazione dati.MapeSet: Sono strutture dati alternative agli oggetti che offrono diversi vantaggi, specialmente quando hai bisogno di chiavi di tipo diverso da stringhe o di collezioni uniche di valori.Mapè particolarmente rilevante per le collezioni di coppie chiave-valore.- Cicli
for...inefor...of: Comprendi a fondo le differenze e i casi d'uso di questi cicli per iterare su oggetti e array.for...inè tradizionalmente usato per gli oggetti (ma con alcune insidie relative alle proprietà ereditate), mentrefor...ofè ideale per gli array e altre strutture iterabili (come quelle restituite dai metodiObject.*). - Spread Syntax (
...) per Oggetti: Impara come usare l'operatore spread per clonare oggetti o per unire più oggetti in modo conciso e immutabile. Spesso si combina con questi metodi per creare nuove strutture di dati. Object.defineProperty()e Descrittori di Proprietà: Per un controllo più granulare su come le proprietà di un oggetto si comportano (se sono enumerabili, scrivibili, configurabili), puoi approfondireObject.defineProperty().
Continuare a praticare con esempi reali e a sperimentare con questi concetti è il modo migliore per consolidare la tua conoscenza. La manipolazione degli oggetti è al centro di quasi ogni applicazione JavaScript, quindi più ti sentirai a tuo agio con questi strumenti, più sarai efficace come sviluppatore web. Buon lavoro!