16
TEMA 9 1/16 Xilòfon És difícil de creure que l'ús de la tecnologia per enregistrar i reproduir música només es remunta a 1878, quan Edison va patentar el fonògraf. Hem arribat molt lluny per descomptat, amb sintetitzadors de música, CD, mostreig i la remescla, telèfons que reprodueixen música, i fins i tot a llarga distància per Internet. En aquest tema, podràs prendre part en aquesta tradició mitjançant la creació d'una aplicació que registra reproduix música de xilòfon. El que construiràs Amb l'aplicació que es mostra a la Figura 9-1 (originalment creada per Liz Looney l'equip de App Inventor), pot: Tocar huit notes diferents en tocar botons de colors a la pantalla. Premeu un botó de Reproducció per reproduir les notes que ha tocat abans. Premeu un botó de Reinici perquè l'aplicació oblidar el que assenyala que ha jugat anteriorment perquè pugui escriure una nova cançó. El que aprendràs Aquest tutorial cobreix els següents conceptes: L'ús d'un component de so només per tocar diferents arxius d'àudio. Utilització del component del rellotge per mesurar i fer complir les demores entre les accions. Decidir quan crear un procediment. Creació d'un procediment que es crida a si mateix. Ús avançat de les llistes, incloent l'addició d'elements, l'accés a elles, i esborrar la llista. Figura 9-1. El xilòfon, aplicació d'interfície d'usuari

T9 xilofon

Embed Size (px)

Citation preview

TEMA 9 1/16

Xilòfon

És difícil de creure que l'ús de la tecnologia per enregistrar i reproduir música només es remunta a 1878, quan Edison va patentar el fonògraf. Hem arribat molt lluny per descomptat, amb sintetitzadors de música, CD, mostreig i la remescla, telèfons que reprodueixen música, i fins i tot a llarga distància per Internet. En aquest tema, podràs prendre part en aquesta tradició mitjançant la creació d'una aplicació que registra reproduix música de xilòfon.

El que construiràs

• Amb l'aplicació que es mostra a la Figura 9-1 (originalment creada per Liz Looney l'equip de App Inventor), pot:

• Tocar huit notes diferents en tocar botons de colors a la pantalla.

• Premeu un botó de Reproducció per reproduir les notes que ha tocat abans.

• Premeu un botó de Reinici perquè l'aplicació oblidar el que assenyala que ha jugat anteriorment perquè pugui escriure una nova cançó.

El que aprendràs

Aquest tutorial cobreix els següents conceptes:

• L'ús d'un component de so només per tocar diferents arxius d'àudio.

• Utilització del component del rellotge per mesurar i fer complir les demores entre les accions.

• Decidir quan crear un procediment.

• Creació d'un procediment que es crida a si mateix.

• Ús avançat de les llistes, incloent l'addició d'elements, l'accés a elles, i esborrar la llista.

Figura 9-1. El xilòfon, aplicació d'interfície d'usuari

TEMA 9 2/16

Introducció

Connectar-se a la pàgina web de App Inventor i començar un nou projecte. El nom de "Xilofon", i també s'estableix el títol de la pantalla de "Xilòfon". Obriu l'Editor de blocs i connectar al seu telèfon o emulador.

Disseny dels components

Aquesta aplicació té 13 components diferents (8 dels quals componen el teclat), que s'enumeren a la Taula 9-1. Com que hi ha tants, que seria bastant avorrit per crear tots ells abans de començar a escriure el nostre programa, així que anem a analitzar l'aplicació en les seves parts funcionals i construir en forma seqüencial per anar i venir entre el dissenyador i els blocs editor, com ho vam fer en el tema 5.

Taula 9-1. Tots els components de l'aplicació XilòfonComponent Paleta Nom assignat Objectiu

Button Basic Button1 Reproduir tecla C minúscula.

Button Basic Button2 Reproduir tecla D.

Button Basic Button3 Reproduir tecla E.

Button Basic Button4 Reproduir tecla F.

Button Basic Button5 Reproduir tecla G.

Button Basic Button6 Reproduir tecla A.

Button Basic Button7 Reproduir tecla B.

Button Basic Button8 Reproduir tecla C majúscula.

Sound Media Sound1 Reproduir les notes.

Button Basic PlayButton Reproduir la cançó.

Button Basic ResetButton Restablir la memòria de cançons.

Horizontal Arrangement

Screen Arrangement

Horizontal Arrangement1

Col·loqui els botons Play i Reset un al costat de l'altre.

Clock Basic Clock1 Porteu un registre dels retards entre les notes.

Creació del teclat

La nostra interfície d'usuari inclou un teclat de vuit notes per a una pentatònica (de set notes)de escala major que va des de C minúscula a C majúscula. Crearem aquest teclat musical en aquesta secció.

TEMA 9 3/16

La creació dels botons de la primera nota

Comenceu per crear les dues primeres tecles del xilòfon, que anem a aplicar com botons.

1. A la categoria Bàsica, arrossegueu un botó a la pantalla. Deixi el seu nom com Button1. Volem que sigui una barra magenta llarga, com una clau en un xilòfon, així que estableixi les seves propietats així:

a) Canvi de la seva propietat BackgroundColor a Magenta.

b) Canviar la propietat Text en "C".

c) Configuració de la seva propietat Width a "Fill parent" pel que va tot el camí a través de la pantalla.

d) Configuració de la seva propietat Height a 40 píxels.

2. Repetiu el procediment per a un segon botó, denominat Button2, situant per sota de Button1. Utilitzeu els mateixos valors de les propietats Ample i Alçada, però establir la seva propietat BackgroundColor a Roig i la seva propietat Text en "D".

(Més tard, repetirem el pas 2 per als altres sis botons de nota.)

La vista en el Dissenyador de components s'hauria d'assemblar Figura 9-2.

Figura 9-2. Col·locació de botons per crear un teclat

La pantalla del telèfon ha de ser similar, tot i que no hi haurà cap espai buit entre els dos botons de colors.

Afegir el component de so

No podem tenir un xilòfon sense sons, així que cal crear un component de so, deixant el seu nom com Sound1. Canvieu la propietat MinimumInterval del seu valor predeterminat de 500 mil·lisegons a 0. Això ens permet reproduir el so amb la freqüència que vulgueu, en lloc d'haver d'esperar mig segon (500 milisegons) entre tocs. No estableixi la seva propietat Source, ho configurarem en l'editor de blocs.

Carregueu els arxius de so 1.wav i 2.wav de la carpeta Recursos 9 del tema 9 . Al contrari que en els temes anteriors, on estava bé per canviar els noms dels arxius de Media, és important utilitzar aquests noms exactes per raons que aviat es faran evidents. Pots carregar els restants sis arxius de so ara.

TEMA 9 4/16

Connexió dels sons als botons

El comportament que necessitem en el programa és per a un arxiu de so per reproduir quan el corresponent botó és premut. En concret, si es fa clic a Button1, ens agradaria reproduir 1.wav, si es fa clic a Button2, ens agradaria reproduir 2.wav, i així successivament. Podem configurar això en l'Editor de blocs, com es mostra a la Figura 9-3 de la següent manera:

1. Des de la pestanya My Blocs i el calaix Button1, arrossegament el bloc Button1.Click.

2. Del calaix Sound1, arrossegueu i establiu el bloc Sound1.Source, col·locant-lo en el bloc Button1.Click.

3. Tecleja "text" per crear un bloc de text. (Això és més ràpid que anar a la fitxa integrada i després al calaix de text, tot i que podria funcionar també.) Establir el valor de text a "1.wav" i el col·loca-lo en el bloc Sound1.Source.

4. Afegir un bloc Sound1.Play.

Figura 9-3. Reproduir un so quan es prem un botó

Podríem fer el mateix per Button2, com es mostra a la Figura 9-4 (només canviar el valor de text), però el codi seria terriblement repetitiu.

Figura 9-4. L'addició de més sons

Un codi repetitiu és un bon senyal que s'ha de crear un procediment, que ja ho ha fet en el joc del tema 3 i el tema 5. En concret, crearem un procediment que pren un nombre com a argument, estableix el Source de Sound1 a l'arxiu corresponent, i es reprodueix el so. Aquest és un altre exemple de refactorització de millora de la implementació d'un programa sense canviar el seu comportament, un concepte introduït al tema 3. Podem utilitzar el calaix del bloc de text “join”(una versió alternativa de make text) per combinar el nombre (per exemple, 1) i el text ".wav" per crear el nom de fitxer adequat (per exemple, "1.wav").

TEMA 9 5/16

Aquests són els passos per crear el procediment que necessitem:

1. Sota la fitxa integrada, aneu al calaix Definition i arrossegueu el bloc de procediment.

2. Tornar al calaix Definition i arrossegueu un bloc de nom "arg" al socket to procedure.

3. Feu clic a l'extrem dret "nom" i establir el nom de "number".

4. Feu clic a procediment i establir el nom de "PlayNote".

5. Arrossegueu el bloc de Sound1.Source Button1.Click a PlayNote a la dreta de la paraula "do". El bloc Sound1.Play es mourà amb ella.

6. Arrossegueu el bloc 1.wav en el pot d'escombraries.

7. Del calaix del text, arrossegueu el bloc join en el sòcol Sound1.Source.

8. Escriu "number" i es mouen al sòcol esquerra del bloc join (si no està ja allà).

9. Des del calaix de text, arrossegueu el bloc de text en el sòcol dreta del bloc join.

10.Canvieu el valor de text a ".wav". (Recordeu que no heu d'escriure les cometes).

11.A la pestanya My Blocks, aneu al My Definitions i arrossegueu un bloc call PlayNote en el cos buit de Button1.Click.

12.Escriviu "1" i el poseu-lo al sòcul del "number".

Ara, quan es fa clic en Button1, el procediment PlayNote s'anomena, amb el seu argument de nombre que té el valor 1. S'ha d'establir Sound1.Source a "1.wav" i reproduir el so.

Creeu un bloc Button2.Click similar amb una crida a PlayNote amb un argument de 2. (Podeu copiar el bloc PlayNote existent i avançar en el cos de Button2. Feu clic, de manera que assegureu-vos de canviar l'argument.) El programa ha de ser similar a la Figura 9-5.

Figura 9-5. Creació d'un procediment per executar una nota

TEMA 9 6/16

Android per carregar els sons

Si vas provar l'anterior PlayNote, pots haver estat decebut per no escoltar el so que s'esperava o en experimentar un retard inesperat. Això és perquè Android necessita carregar sons en temps d'execució, el que porta el seu temps, abans que puguin ser reproduïts. Aquest problema no va sorgir abans, perquè els noms d'arxiu col·locats en propietat Source d'un component de so en el Dissenyador es carreguen automàticament en iniciar el programa. Com que no s'estableix Sound1.Source fins que el programa s'ha iniciat, el procés d'inicialització no es realitza. Hem de carregar explícitament els sons quan el programa s'inicia, com es mostra a la Figura 9-6.

Figura 9-6. Carregant sons quan l'aplicació s'inicia

Posa a prova la teva app. Ara bé, si reinicia l'aplicació fent clic a " Connect

to Device..." a l'Editor de blocs, les notes han de reproduir-se sense demora. (Si no es sent res, assegureu-vos que el volum dels Media al telèfon no està en silenci.)

L'aplicació de les notes restants

Ara que ja tenim els dos primers botons i notes executades i en funcionament, afegir els restants sis notes per tornar al Dissenyador i carregar els arxius de so3.wav, 4.wav, 5.wav, 6.wav, 7.wav i 8.wav. A continuació, crear sis nous botons, seguint els mateixos passos com ho va fer abans, però l'establiment del seu text i les seves propietats BackgroundColor de la següent manera:

• Botó3 (“E”, Rosa)

• Botó4 (“F”, Taronja)

• Botó5 (“G”, Groc)

• Botó6 (“A”, Verd)

• Botó7 (“B”, Cyan)

• Botó8 (“C”, Blau)

També pots voler canviar la propietat de Button8, TextColor, a Blanc com es mostra a la Figura 9-7, pel que és més llegible.

TEMA 9 7/16

Figura 9-7. Posar els botons restants i sons en el Dissenyador de components

De nou a l'Editor de blocs, feu clic a Crea blocs per a cada un dels nous botons amb trucades apropiades a PlayNote. De la mateixa manera, afegir cada arxiu de so nou per Screen.Initialize, com es mostra a la Figura 9-8.

Posa a prova la teva app. Ara ha de tenir tots els botons, i cada un toca una nota diferent quan es fa clic.

Figura 9-8. Programació dels esdeveniments del botó clic per correspondre a totes les tecles del teclat

TEMA 9 8/16

Enregistrament i reproducció de notes

La reproducció de notes amb botons és divertit, però ser capaç de gravar i reproduir cançons és encara millor. Per dur a terme la reproducció, haurem de mantenir un registre de les notes tocades. A més de recordar les tonades (arxius de so) que es van reproduint, també ha de registrar la quantitat de temps entre les notes, o no serem capaços de distingir entre dues notes tocades en successió ràpida i dues reproduïdes amb un silenci de 10 segons entre ells.

La nostra aplicació mantindrà dues llistes, cadascuna de les quals tindrà una entrada per a cada nota que s'ha tocat:

• Notes, que contindrà els noms dels arxius de so en l'ordre en què van ser reproduïts.

• Els temps que es registren els punts en el temps en què les notes van ser reproduïdes.

Nota. Abans de continuar, és possible que vulgueu revisar llistes, que cobrim en el tema 8.

Podem obtenir la informació de temps a partir d'un component del rellotge, que també s'utilitzarà per cronometrar correctament les notes per a la reproducció.

Afegir els components

Al dissenyador, hauràs d'afegir un component Rellotge i els botons Play i Reset, que posarem en un HorizontalArrangement:

1. Arrossegueu un component del rellotge. Apareixerà en la secció "components no visibles". Desmarqueu la propietat TimerEnabled perquè no volem que el seu temporitzador s'apagui fins que nosaltres li diguem que durant la reproducció.

2. Anar a la categoria disposició de la pantalla i arrossegueu un component HorizontalArrangement sota el botó existent. Indiqueu la propietat Width a "Fill parent".

3. A la categoria Bàsica, arrossegueu un botó. Canviar el nom PlayButton i estableixi la seva propietat Text en "Play".

4. Arrossegueu un altre botó, col·locant-lo a la dreta de PlayButton. Canvieu el nom del nou botó per ResetButton i estableixi la seva propietat Text en "Reset". La vista de disseny ha de ser similar a la Figura 9-9.

TEMA 9 9/16

Figura 9-9. Afegir components per a la gravació i reproducció de sons

Gravació de notes i horaris

Ara hem d'afegir el comportament correcte a l'Editor de blocs. Haurem de mantenir una llista de les notes i els temps i afegir a la llista cada vegada que l'usuari prem un botó.

1. Crea una nova variable anant a la pestanya Built-In i arrossegant un bloc def variable al calaix Definition.

2. Feu clic a "variable" i canviar a "notes".

3. Obriu el calaix Lists i arrossegueu un bloc make a list, col·locant en el sòcul de def notes.

Això defineix una nova variable anomenada "notes" a una llista buida. Repetiu els passos per l'altra variable, que li doneu el nom de "times". Aquests nous blocs ha de ser similar a la Figura 9-10.

Figura 9-10. Establiment de les variables per gravar notes

TEMA 9 10/16

Com funcionen els blocs

Cada vegada que es toca una nota, hem de salvar tant el nom de l'arxiu de so (per les notes de la llista) i l'instant en el moment en què es va tocar (als temps de la llista). Per registrar l'instant de temps, utilitzarem el bloc Clock1.Now, que retorna l'instant actual al temps (per exemple, 12 de març de 2011, 08:33:14 AM), amb una precisió de mil·lisegons. Aquests valors, obtinguts a través dels blocs Sound1.Source i Clock1.Now, s'ha d'afegir a les llistes de notes i times, respectivament, com es mostra en la figura 9-11.

Figura 9-11. Afegint els sons que es reprodueixen a la llista

Per exemple, si toques "Row, Row, Row Your Boat" [C C C D E], les llistes que acaben de tenir cinc entrades, que poden ser:

• Notes: 1.wav, 1.wav, 1.wav, 2.wav, 3.wav

• Temps [dates omeses]: 12:00:01, 12:00:02, 12:00:03, 12:00:03.5 12:00:04,

Quan l'usuari prem el botó Reset, volem que les dues llistes tornen al seu estat original i buits. Atès que l'usuari no veurà cap canvi, és bo afegir un bloc Sound1.Vibrate petit, pel que sap que el clic de les tecles es va registrar. La figura 9-12 mostra els blocs per aquest comportament.

Figura 9-12. Proporcionar informació quan l'usuari reinicia l'aplicació

TEMA 9 11/16

Reproducció de notes

Com experiment, primer anem a buscar la manera de posar en pràctica la reproducció de la nota sense haver de preocupar-se pel temps. Podríem fer això mitjançant la creació d'aquests blocs, com es mostra a la Figura 9-13:

• Una variable count per fer un seguiment del que fem.

• Un nou procediment, PlayBackNote, que reprodueix aquesta nota i passa a la següent.

• Codi a executar quan es prem PlayButton que fica el count a 1 i crida PlayBackNote llevat que no hi haja notes guardades.

Com funcionen els blocs

Aquesta pot ser la primera vegada que heu vist un procediment de fer una crida a si mateix. Encara que a primera vista això pot semblar fals, és en realitat un concepte important en programació de gran abast, la crida recursiva.

Per tenir una millor idea de com funciona la recursivitat, anem pas a pas el que succeeix quan un usuari toca tres notes (1.wav, 3.wav i 6.wav) i després prem el botó Play. En primer lloc, PlayButton.Click comença a funcionar. Com que la longitud de les notes de la llista és 3, que és més gran que 0, el recompte s'estableix en 1, i PlayBackNote es cridat:

1. La primera vegada que PlayBackNote es crida, count = 1

a) Sound1.Source s'estableix en el primer element de notes, que és 1.wav.

b) Sound1.Play es cridat, reproduint aquesta nota.

c) Ja que count (1) < la longitud de les notes (3), count s'incrementa a 2. PlayBackNote es crida de nou.

TEMA 9 12/16

Figura 9-13. Reproducció de les notes gravades

2. La segona vegada que PlayBackNote es crida, count = 2:

a) Sound1.Source s'estableix en el segon element de notes, que és 3.wav.

b) Sound1.Play es crida, reproduint aquesta nota.

c) Ja que count (2) < la longitud de les notes (3), count s'incrementa a 3. PlayBackNote es crida de nou.

3. La tercera vegada que PlayBackNote es crida, count = 3:

a) Sound1.Source s'estableix en el tercer element de notes, que és 6.wav.

b) Sound1.Play es crida, reproduint aquesta nota.

c) Ja que count (3) no és menor que la longitud de les notes (3), no passa res més, i es completa la reproducció.

Nota. Encara que la recursió és eficaç, també pot ser perillós. Com experiment mental, pregunteu-vos què hauria passat si el programador haguera oblidat inserir als blocs en PlayBackNote que incrementara el comptador.

Si bé la recursió és correcta, no és un problema diferent amb l'anterior exemple: gairebé no passa temps entre una crida a Sound1.Play i la següent, de manera que cada nota es veu interromput per la nota següent, a excepció de l'última. Cap nota (excepte l'últim) se li permet completar abans que el Source de Sound1 es canvia i es torna a cridar Sound1.Play. Per obtenir el comportament correcte, hem d'aplicar un retard entre les cridades a PlayBackNote.

TEMA 9 13/16

Reproducció de Notes amb retards adequats

Anem a aplicar la demora d'ajustar el temporitzador en el rellotge per la quantitat de temps entre la nota actual i la següent nota. Per exemple, si la nota següent es reprodueix 3.000 mil·lisegons (3 segons) després de la nota actual, establirem Clock1.TimerInterval a 3.000, després de les quals PlayBackNote hauria de ser cridat de nou. Feu els canvis que es mostren a la Figura 9-14 per al cos del bloc if en PlayBackNote, i crear i omplir el controlador d'esdeveniments Clock1.Timer, que diu el que ha de passar quan el temporitzador s'apaga.

Figura 9-14. Afegir els retards entre les notes

TEMA 9 14/16

Com funcionen els blocs

Suposem el següent contingut de les dues llistes:

• Notes: 1.wav, 3.wav, 6.wav

• Temps: 12:00:00, 12:00:01, 12:00:04

Com mostra la Figura 9-14, PlayButton.Click estableix count a 1 i crida a PlayBackNote.

1. La primera vegada que PlayBackNote es cridat, count = 1:

a) Sound1.Source s'estableix en el primer element de notes, que és "1.wav".

b) Sound1.Play es crida, reproduint aquesta nota.

c) Ja que count (1) < la durada de les notes (3),

Clock1.TimerInterval s'estableix en la quantitat de temps entre el primer (00:00:00) i el segon element en els temps (00:00:01): 1 segon.

count s'incrementa a 2.

Clock1.Timer està activat i comença el compte enrere.

Només passa durant 1 segon, en el qual Clock1.Timer s'acabi el temps, desactivar temporalment el temporitzador i cridant PlayBackNote.

2. La segona vegada que PlayBackNote es crida, count3 = 2:

a) Sound1.Source s'estableix en el primer element de notes, que és "1.wav".

b) Sound1.Play es crida, reproduint aquesta nota.

c) Ja que count (2) < la durada de les notes (3),

Clock1.TimerInterval s'estableix en la quantitat de temps entre la segona (00:00:01) i el tercer element en els temps (00:00:04): 3 segons.

count s'incrementa a 3.

Clock1.Timer està activat i comença el compte enrere.

Només passa durant 3 segon, en el qual Clock1.Timer s'acabi el temps, desactivar temporalment el temporitzador i cridant PlayBackNote.

3. El PlayBackNote tercera vegada que es diu, compte = 3:

a) Sound1.Source s'estableix en el tercer element de notes, que és "6.wav".

b) Sound1.Play es crida, reproduint aquesta nota.

c) Ja que count (3) < la durada de les notes (3),no passa res més.

La reproducció s'ha completat.

TEMA 9 15/16

Variacions

Aquests són alguns dels escenaris alternatius per explorar:

• Actualment, no hi ha res que impedeixi que un usuari faci clic ResetButton durant la reproducció, el que farà que el programa es bloquegi. (Es pot saber per què?). Modificar PlayButton.Click pel que desactiva ResetButton. Per tornar a activar quan la cançó estigui completa, canviar el bloc if en PlayButton.Click en un bloc ifelse, i tornar a habilitar ResetButton en la part "else".

• De la mateixa manera, l'usuari pot fer clic en l'actualitat PlayButton mentre una cançó està reproduint-se. (Pots imaginar el que passarà si ho fa?) Que sigui inhabilitat PlayButton.Clic PlayButton desactiva i canvia el seu text a "reproduint ..." Es pot tornar a activar i restablir el text en un bloc de ifelse, com es descriu en el punt anterior.

• Afegiu un botó amb el nom d'una cançó, com "Per a Elisa". Si l'usuari fa clic, omplir les llistes notes i times amb els valors corresponents, estableixi count a 1, i cridar a PlayBackNote. Per establir el moment adequat, trobareu el bloc CLOCK1.MakeInstantFromMillis útil.

• Si l'usuari prem una nota, va i fa una mica més, i torna a aparèixer hores més tard i prem una nota addicional, les notes seran part de la mateixa cançó, que probablement no és el que l'usuari tenia previst. Millorar el programa de gravació de parada (1) després d'un interval de temps raonable, com ara un minut, o (2) posar un límit a la quantitat de temps utilitzat per Clock1.TimerInterval usant el bloc màxim del calaix Math.

• Indicar visualment quina nota està reproduint-se en canviar l'aparença del botó - per exemple, mitjançant el canvi del seu text, BackgroundColor, o ForegroundColor.

TEMA 9 16/16

Resum

Aquestes són algunes de les idees que hem cobert en aquest tutorial:

• Pot reproduir diferents arxius d'àudio d'un component de so només canviant la seva propietat Source. Això ens ha permès tenir un component de so en lloc de huit. Només heu de carregar els sons en la inicialització per evitar demores (Figura 9-6).

• Les llistes poden oferir un programa amb la memòria, amb un registre d'accions de l'usuari emmagatzemades a la llista i després recuperat i reprocessat. Utilitzem aquesta funció per gravar i reproduir una cançó.

• El component del rellotge pot ser utilitzat per determinar l'hora actual. Restar dos valors de temps ens dóna la quantitat de temps entre dos esdeveniments.

• La propietat del rellotge TimerInterval es pot establir dins del programa, com ara la manera com s'estableix la durada de temps entre les arrencades de dues notes.

• No només és possible, de vegades desitjable per a un procediment el fer-se una crida a si mateixa. Aquesta crida recursiva és una tècnica de gran abast. En escriure un procediment recursiu, assegureu-vos que hi ha un cas de referència en què el procediment acaba, en lloc de cridar a si mateix, o el programa es repetirà infinitament.