tipos de datos en java

22
FUNDAMENTOS DE PROGRAMACION SEMESTRE OTOÑO/2007 INSTITUTO PROFESIONAL PROVIDENCIA ESCUELA DE TECNOLOGÍA E INFORMÁTICA Conversión de tipos de datos en Java 24/08/2022 1

Upload: api-3735749

Post on 07-Jun-2015

18.208 views

Category:

Documents


5 download

DESCRIPTION

Importante para ver hoy

TRANSCRIPT

Page 1: Tipos de Datos en Java

FUNDAMENTOS DE PROGRAMACION SEMESTRE OTOÑO/2007

INSTITUTO PROFESIONAL PROVIDENCIAESCUELA DE TECNOLOGÍA E INFORMÁTICA

Conversión de tipos de datos en Java

12/04/2023 1

Page 2: Tipos de Datos en Java

FUNDAMENTOS DE PROGRAMACION SEMESTRE OTOÑO/2007

Conversiones posibles entre los tipos de datos primitivos en Java,

byte -> short -> int -> long -> float -> doublechar -> int -> long -> float -> double

Tome la siguiente clase y pruebe la conversión entre los tipos de datos.

// byte -> short -> int -> long -> float -> double// char -> int -> long -> float -> double

class conversiontipos{

public static void main(){ byte enterobit = 127; short enteroCorto = 0; int entero; long enteroLargo; float puntoFlotante; double decimal; char numeroCaracter = '9' ; // Conversiones entre números // Convierto de Byte a short enteroCorto = (short) enterobit; // Convierto de Short a int entero = (int) enteroCorto; // Convierto de int a long enteroLargo = (long) entero; // Convierto de long a float puntoFlotante = (float) enteroLargo; // Convierto de float a Double decimal = (double) puntoFlotante; // Conversiones desde char entero = (int) numeroCaracter; // Convierto de int a long enteroLargo = (long) entero; // Convierto de long a float puntoFlotante = (float) enteroLargo; // Convierto de float a Double decimal = (double) puntoFlotante;

12/04/2023 2

Page 3: Tipos de Datos en Java

FUNDAMENTOS DE PROGRAMACION SEMESTRE OTOÑO/2007

}

}

Formateo de Números y Monedas

Los programas almacenan y operan con números de una forma independiente de la Localidad. Antes de mostrar o imprimir un número el programa debe convertirlo a un String que esté en un formato sensible a la Localidad. Por ejemplo, en Francia, el número 123456.78 debería ser formateado como 123 456,78, y en Alemania debería aparecer como 123.456,78. En esta lección, aprenderás como hacer que tus programas sean idependientes de las convenciones de la localidad para los puntos decimales, los separadores de millares, y otras propiedades de formateo.

Utilizar Formatos Predefinidos

Utilizando los métodos de factoría proporcionados por la clase NumberFormat, se pueden obtener formatos específicos de la localidad para números, monedas y porcentajes.

Llamando a los métodos de la clase NumberFormat se pueden formatear números, monedas y porcentajes de acuerdo a la Localidad. Sin embargo, hay un error: NumberFormat podría no soportar la Localidad especificada. Para conocer las definiciones de Locale soportadas por NumberFormat, llamamos al método getAvailableLocales.

Locale[] locales = NumberFormat.getAvailableLocales();

Si NumberFormat no soporta la localidad que necesitamos, podemos crear nuestro propio formateador. Explicaremos este procedimiento en la siguiente sección, Formatear con Patrones.

El siguiente material muestra como obtener formateadores específicos de la localidad para números, monedas y porcentajes. Los códigos de ejemplo son de un programa llamado NumberFormatDemo.java.

Números

Se pueden utilizar los métodos de factoria de NumberFormat para formatear números de tipos de datos primitivos, como double, y sus correspondientes objetos, como Double.

En el siguiente fragmento de código, formatearemos un Double de acuerdo a la Localidad. Primero, obtendrémos un ejemplar de NumberFormat específico de la Localidad, llamando a getNumberInstance. Luego llamamos al método format con el Double como argumento. El método format devuelve el número formateado en un String, que está listo para ser mostrado.

Double amount = new Double(345987.246);NumberFormat numberFormatter;

12/04/2023 3

Page 4: Tipos de Datos en Java

FUNDAMENTOS DE PROGRAMACION SEMESTRE OTOÑO/2007

String amountOut;

numberFormatter = NumberFormat.getNumberInstance(currentLocale);amountOut = numberFormatter.format(amount);System.out.println(amountOut + " " + currentLocale.toString());

La salida de este ejemplo muestra como el formato del mismo número varía con la Localidad.

345 987,246 fr_FR345.987,246 de_DE345,987.246 en_US

Monedas

Si estás escribiendo apliaciones de negocios, necesitarás formatear y mostrar valores en monedas. Las monedas se formatean de la misma forma que los números, excepto en que se llama a getCurrencyInstance para crear el formateador. Cuando se llama al método format , devuelve un String que incluye el número formateado y el signo de moneda apropiado.

El siguiente código muestra como formatear moneda de una forma específica de la Localidad.

Double currency = new Double(9876543.21);NumberFormat currencyFormatter;String currencyOut;

currencyFormatter = NumberFormat.getCurrencyInstance(currentLocale);currencyOut = currencyFormatter.format(currency);System.out.println(currencyOut + " " + currentLocale.toString());

La salida genera por las líneas precedentes sería esta.

9 876 543,21 F fr_FR9.876.543,21 DM de_DE$9,876,543.21 en_US

A primera vista, esta salida podría parecer errónea, porque los valores numéricos son iguales. Por supesto, 9 876 543,21 F no es equivalente a 9.876.543,21 DM. Sin embargo, recuerda que la clase NumberFormat no puede cambiar monedas. Los métodos pertenecientes a la clase NumberFormat formatean monedas, pero no las convierten.

Porcentajes

Támbien se pueden utilizar los métodos de la clase NumberFormat para formatear porcentajes. Para obtener el formateador específico de la localidad se llama al método getPercentInstance. Con este formateador, un fracción como 0.75 se mostrará como 75%.

El siguiente código muetra como formatear porcentajes.

Double percent = new Double(0.75);

12/04/2023 4

Page 5: Tipos de Datos en Java

FUNDAMENTOS DE PROGRAMACION SEMESTRE OTOÑO/2007

NumberFormat percentFormatter;String percentOut;

percentFormatter = NumberFormat.getPercentInstance(currentLocale);percentOut = percentFormatter.format(percent);

Formatear con Patrones

Con la clase DecimalFormat se específica un formato de número con patrón. La clase DecimalFormatSymbols permite modificar los simbolos de formateo como separadores decimales o el signo negativo.

Se puede utilizar la clase DecimalFormat para formatear números decimales en cadenas específicas de la Localidad. Esta clase permite controlar los ceros iniciales y finales, los sufijos y prefijos, separadores (millares), y el separador decimal. Si se quiere cambiar un símbolo del formateo como el saperador decimal, se puede utilizar DecimalFormatSymbols en conjunción con la clase DecimalFormat. Estas clases ofrecen una gran flexibilidad en el formateo de números, pero hacen el código más complejo. Siempre que sea posible, se debería utilizar la clase NumberFormat, que se describió en la sección anterior, en vez de DecimalFormat y DecimalFormatSymbols.

Utilizando ejemplos, las siguientes líneas mostrarán como utilizar las clases DecimalFormat y DecimalFormatSymbols. Los fragmentos de código se han extraido de un programa llamado DecimalFormatDemo.java.

Construir Patrones

Las propiedades de formateo de DecimalFormat se específican con un String patrón. El patrón determina la apariencia del número formateado. Para una descripción completa de la síntaxis de los patrones puedes ver Síntaxis de los Patrones de Formateo de Números.

En el siguiente ejemplo, hemos creado un formateador, pasándole un patrón al constructor de DecimalFormat. Luego, le hemos pasado un valor double al método format, que devuelve un String formateado.

DecimalFormat myFormatter = new DecimalFormat(pattern);String output = myFormatter.format(value);System.out.println(value + " " + pattern + " " + output);

La salida de las líneas de código precedentes se describe en la siguiente tabla. El valor es el número, un double, que será formateado. El Patrón es el String que específica las propiedades de formateo. La Salida, que es un String, representa el número formateado.

Valor Patrón Salida Explicación123456.789 ###,###.### 123,456.789 El signo Almohadilla (#) indica un dígito, la

coma la posición del separador de millares y el punto la posición del separador decimal.

123456.789 ###.## 123456.79 El valor tiene tres dígitos a la derecha del punto decimal, pero el patrón sólo tiene dos. El método format maneja esto

12/04/2023 5

Page 6: Tipos de Datos en Java

FUNDAMENTOS DE PROGRAMACION SEMESTRE OTOÑO/2007

redondeando.123.78 000000.000 000123.780 El patrón específica relleno con ceros,

porque se utiliza el caracter Cero en vez de la almohadilla (#).

12345.67 $###,###.### $12,345.67 El primer carácter del patrón es el signo del dólar ($). Observa que este signo precede inmediatamente al dígito más a la izquierda de la salida formateada.

12345.67 \u00a5###,###.### ¥12,345.67 El patrón específica el signo del Yen Japonés (¥) con su valor Unicode \u00a5.

Formateo Sensible a la Localidad

El ejemplo anterior creaba un objeto DecimalFormat para la Localidad por defecto. Si se quiere un objeto DecimalFormat para una localidad distinta, se ejemplariza un NumberFormat y luego se fuerza a DecimalFormat. Entonces, el objeto DecimalFormat formetará los patrones definidos de una forma sensible a la localidad. Aquí se puede ver un ejemplo.

NumberFormat nf = NumberFormat.getNumberInstance(loc);DecimalFormat df = (DecimalFormat)nf;df.applyPattern(pattern);String output = df.format(value);System.out.println(pattern + " " + output + " " + loc.toString());

Abajo podemos ver el resultado de la ejecución de este código. Los números formateados, en la segunda columna, varían con la Localidad.

###,###.### 123,456.789 en_US###,###.### 123.456,789 de_DE###,###.### 123 456,789 fr_FR

Por eso, los patrones de formateo que hemos utilizado hasta ahora seguían las convenciones del Inglés Norteamericano. Por ejemplo, en el patrón "###,###.##" la coma es el separador de millares y el punto representa el punto decimal. Esta convención está bien, sabiendo que los usuarios finales no están expuestos a ellas. Sin embargo, algunas aplicaciones, como las hojas de cálculo y los generadores de informes, permiten al usuario final definir sus propios patrones de formateo. Para esas aplicaciones, los patrones de formateo especificados por el usuario final deberían utilizar la notación localizada. En estos casos querremos llamar al método applyLocalizedPattern sobre el objeto DecimalFormat.

Modificar los Símbolos de Formateo

Con la clase DecimalFormatSymbols se pueden modificar los símbolos que aparecen en los números formateados porducidos por el método format. Estos símbolos incluyen el punto decimal, el separador de millares, el signo menos, y el signo de porcentaje además de algunos más.

En el siguiente ejemplo podemos ver el uso de DecimalFormatSymbols aplicando un formato inusual a un número. Empezamos ejemplarizando DecimalFormatSymbols sin argumentos, lo que devuelve un objeto para la Localidad por defecto, (Como DecimalFormatSymbols es una clase

12/04/2023 6

Page 7: Tipos de Datos en Java

FUNDAMENTOS DE PROGRAMACION SEMESTRE OTOÑO/2007

sensible a la Localidad, podríamos haber específicado una Localidad cuando llamamos al constructor.) Luego, modificamos el separador decimal y el de millares. Luego específicamos el DecimalFormatSymbols cuando ejemplarizamos la clase DecimalFormat. Sólo para hacer las cosas más complicadas, cambiamos la numero de agrupamiento del formateador de tres a cuatro. Finalmente llamamos al método format.

Aquí tienes el código de Ejemplo.

DecimalFormatSymbols unusualSymbols = new DecimalFormatSymbols();unusualSymbols.setDecimalSeparator('|');unusualSymbols.setGroupingSeparator('^');

String strange = "#,##0.###";DecimalFormat weirdFormatter = new DecimalFormat(strange, unusualSymbols);weirdFormatter.setGroupingSize(4);

String bizarre = weirdFormatter.format(12345.678);System.out.println(bizarre);

Esto es lo que aparecerá cuando imprimamos este extraño número formateado

1^2345|678

Síntaxis de los Patrones de Formateo de Números

Se pueden diseñar patrones personalizados para el formateo de números, siguiendo las siguientes reglas específicas por el diagrama BNF.

patrón := subpatrón{;subpatrón}subpatrón := /javaentero{.fracción}{sufijo}prefijo := '\\u0000'..'\\uFFFD' - CaracteresEspecialessufijo := '\\u0000'..'\\uFFFD' - CaracteresEspecialesentero := '#'* '0'* '0'fracción := '0'* '#'*

La notación utilizada en el diagrama anterior se explica en la siguiente tabla.

Notación DescripciónX* 0 o más ejemplares de X(X | Y) X o YX..Y cualquier caracter de X a Y, inclusivesS - T Los caracteres que estén en S, exceptos los que estén en T{X} X es opcional

En el digrama BNF anteiror, el primer subpatrón especifica el formato para números positivos. El segundo es opcional, específica el el formato para números negativos.

Aunque no está en el diagrama BNF, puede aparecer una coma dentro de la porción "entero".

12/04/2023 7

Page 8: Tipos de Datos en Java

FUNDAMENTOS DE PROGRAMACION SEMESTRE OTOÑO/2007

Dentro de los subpatrones, se específica el formato con símbolos especiales. Esto símbolos se describen en esta tabla.

Símbolo Descripción0 Un dígito# Un dígito, se muestra 0 si no existe. Situación del separador decimal, Situación del separador de millaresE Separa el exponente y la mantisa para formatos exponenciales; Separa formatos- Prefijo negativo por defecto% Multiplica por 100 y lo muestra como porcentaje? Multiplica por 1000 y lo muestra como por mil¤ signo de moneda, reemplazado por un símbolo de moneda; Si es doble, reemplazado

por el símbolo de moneda internacional; si está presente en el patrón, se utiliza el separador decimal monetario en vez de el separador decimal.

X Se puede utilizar cualquier otro caracter como prefijo o sufijo' utilizado para enmarcar caracteres especiales en prefijos o sufijos.

12/04/2023 8

Page 9: Tipos de Datos en Java

FUNDAMENTOS DE PROGRAMACION SEMESTRE OTOÑO/2007

Clase String

Los strings u objetos de la clase String se pueden crear explícitamente o implícitamente. Para crear un string implícitamente basta poner una cadena de caracteres entre comillas dobles. Por ejemplo, cuando se escribe

System.out.println("El primer programa");

Java crea un objeto de la clase String automáticamente.

Para crear un string explícitamente escribimos

String str=new String("El primer programa");

También se puede escribir, alternativamente

String str="El primer programa";

Para crear un string nulo se puede hacer de estas dos formas

String str="";String str=new String();

Un string nulo es aquél que no contiene caracteres, pero es un objeto de la clase String. Sin embargo,

String str;

está declarando un objeto str de la clase String, pero aún no se ha creado ningún objeto de esta clase.

12/04/2023 9

Page 10: Tipos de Datos en Java

FUNDAMENTOS DE PROGRAMACION SEMESTRE OTOÑO/2007

Cómo se obtiene información acerca del string

Una vez creado un objeto de la clase String podemos obtener información relevante acerca del objeto a través de las funciones miembro.

Para obtener la longitud, número de caracteres que guarda un string se llama a la función miembro length.

String str="El primer programa";int longitud=str.length();

Podemos conocer si un string comienza con un determinado prefijo, llamando al método startsWith, que devuelve true o false, según que el string comience o no por dicho prefijo

String str="El primer programa";boolean resultado=str.startsWith("El");

En este ejemplo la variable resultado tomará el valor true.

De modo similar, podemos saber si un string finaliza con un conjunto dado de caracteres, mediante la función miembro endsWith.

String str="El primer programa";boolean resultado=str.endsWith("programa");

Si se quiere obtener la posición de la primera ocurrencia de la letra p, se usa la función indexOf.

String str="El primer programa";int pos=str.indexOf('p');

Para obtener las sucesivas posiciones de la letra p, se llama a otra versión de la misma función

pos=str.indexOf('p', pos+1);

El segundo argumento le dice a la función indexOf que empiece a buscar la primera ocurrencia de la letra p a partir de la posición pos+1.

Otra versión de indexOf busca la primera ocurrencia de un substring dentro del string.

String str="El primer programa";int pos=str.indexOf("pro");

Vemos que una clase puede definir varias funciones miembro con el mismo nombre pero que tienen distinto número de parámetros o de distinto tipo.

12/04/2023 10

Page 11: Tipos de Datos en Java

FUNDAMENTOS DE PROGRAMACION SEMESTRE OTOÑO/2007

Comparación de strings

La comparación de strings nos da la oportunidad de distinguir entre el operador lógico == y la función miembro equals de la clase String. En el siguiente código

String str1="El lenguaje Java"; String str2=new String("El lenguaje Java");

if(str1==str2){System.out.println("Los mismos objetos");

}else{System.out.println("Distintos objetos");

}if(str1.equals(str2)){

System.out.println("El mismo contenido");}else{

System.out.println("Distinto contenido");}

Esta porción de código devolverá que str1 y str2 son dstintos objetos pero con el mismo contenido. str1 y str2 ocupan posiciones distintas en memoria pero guradan los mismos datos.

Cambiemos la segunda sentencia y escribamos

String str1="El lenguaje Java"; String str2=str1;

System.out.prinln("Son el mimso objeto "+(str1==str2);

Los objetos str1 y str2 guardan la misma referencia al objeto de la clase String creado. La expresión (str1==str2) devolverá true.

Asñi pues, el método equals compara un string con un objeto cualquiera que puede ser otro string, y devuelve true cuando dos strings son iguales o false si son distintos.

String str="El lenguaje Java";boolean resultado=str.equals("El lenguaje Java");

La variable resultado tomará el valor true.

La función miembro comapareTo devuelve un entero menor que cero si el objeto string es menor (en orden alfabético) que el string dado, cero si son iguales, y mayor que cero si el objeto string es mayor que el string dado.

String str="Tomás";int resultado=str.compareTo("Alberto");

La variable entera resultado tomará un valor mayor que cero, ya que Tomás está después de Alberto en orden alfabético.

String str="Alberto";int resultado=str.compareTo("Tomás");

12/04/2023 11

Page 12: Tipos de Datos en Java

FUNDAMENTOS DE PROGRAMACION SEMESTRE OTOÑO/2007

La variable entera resultado tomará un valor menor que cero, ya que Alberto está antes que Tomás en orden alfabético.

Extraer un substring de un string

En muchas ocasiones es necesario extraer una porción o substring de un string dado. Para este propósito hay una función miembro de la clase String denominada substring.

Para estraer un substring desde una posición determinada hasta el final del string escribimos

String str="El lenguaje Java";String subStr=str.substring(12);

Se obtendrá el substring "Java".

Una segunda versión de la función miembro substring, nos permite extraer un substring especificando la posición de comienzo y la el final.

String str="El lenguaje Java";String subStr=str.substring(3, 11);

Se obtendrá el substring "lenguaje". Recuérdese, que las posiciones se empiezan a contar desde cero.

Convertir un número a string

Para convertir un número en string se emplea la función miembro estática valueOf (más adelante explicaremos este tipo de funciones).

int valor=10;String str=String.valueOf(valor);

La clase String proporciona versiones de valueOf para convertir los datos primitivos: int, long, float, double.

Esta función se emplea mucho cuando programamos applets, por ejemplo, cuando queremos mostrar el resultado de un cálculo en el área de trabajo de la ventana o en un control de edición.

Convertir un string en número

12/04/2023 12

Page 13: Tipos de Datos en Java

FUNDAMENTOS DE PROGRAMACION SEMESTRE OTOÑO/2007

Cuando introducimos caracteres en un control de edición a veces es inevitable que aparezcan espacios ya sea al comienzo o al final. Para eliminar estos espacios tenemos la función miembro trim

String str=" 12 ";String str1=str.trim();

Para convertir un string en número entero, primero quitamos los espacios en blanco al principio y al final y luego, llamamos a la función miembro estática parseInt de la clase Integer (clase envolvente que describe los números enteros)

String str=" 12 ";int numero=Integer.parseInt(str.trim());

Para convertir un string en número decimal (double) se requieren dos pasos: convertir el string en un objeto de la clase envolvente Double, mediante la función miembro estática valueOf, y a continuación convertir el objeto de la clase Double en un tipo primitivo double mediante la función doubleValue

String str="12.35 ";double numero=Double.valueOf(str).doubleValue();

Se puede hacer el mismo procedimiento para convertir un string a número entero

String str="12";int numero=Integer.valueOf(str).intValue();

La clase StringBuffer

En la sección dedicada a los operadores hemos visto que es posible concatenar cadenas de caracteres, es, decir, objetos de la clase String. Ahora bien, los objetos de la clase String son constantes lo cual significa que por defecto, solamente se pueden crear y leer pero no se pueden modificar.

Imaginemos una función miembro a la cual se le pasa un array de cadenas de caracteres. Los arreglos (arrays) se estudiarán en la siguiente página.

12/04/2023 13

Page 14: Tipos de Datos en Java

FUNDAMENTOS DE PROGRAMACION SEMESTRE OTOÑO/2007

// Estimados Alumnos Trabajemos con los metodos que tiene la clase String // Profesor : Pedro González Tapia// int length () Devuelve el número de caracteres de la cadena// char charAt (int pos) Devuelve el caracter que se encuentra en la posición pos// equals (String otra) Determina si la cadena es igual al String otra// int compareTo (String otra) Comparación lexicográfica. Devuelve 0 si los dos String son iguales, un número negativo si el String que invoca a comparteTo es menor que el String quese pasa como argumento y un número positivo en caso contrario. Elvalor devuelto es la diferencia entre las representaciones enteras del primercarácter que es diferente en cada String. // String substring crea unnuevo objeto String copiando parte de un objeto String existente. String (int), String (int, int)// String concat (String otra) Concatena dos String y devuelve un nuevo objeto String que contiene los caracteresde los dos String originales. // S1.concat (s2) añade los caracteres del String s2 al final de s1.S1 y s2 no se modifica // String replace (char, char) genera un objeto String en el que cada ocurrencia del primer carácter en elstring con que se invoca se substituye por el segundo carácter. Sino hubiera coincidencias se regresa una copia del string original. // String toUpperCase ( ) Regresa un objeto de la clase String igual pero cuyas caracteres son todos mayúsculas// String toLowerCase () Regresa un String con todos los caracteres en minúsculasclass cadenasMetodo { public static void main() { largoCadena(); devuelvePosicion(); comparaCadenas(); comparaLexico(); subCadena(); concatena(); adicionaCadena(); reemplaza(); mayusculas(); minusculas(); } static void largoCadena () { String Alumnos = "Alumnos del IPP"; System.out.println ("El largo de la cadena es : " + Alumnos.length()); } static void devuelvePosicion() { String Alumnos = "Alumnos del IPP"; System.out.println ("El largo de la cadena es : " + Alumnos.charAt(10)); } static void comparaCadenas() { String cadena1 = "Hola", cadena2 = "Chao"; if (cadena1.equals(cadena2)) { System.out.println("Son iguales"); } else { System.out.println("No son iguales"); } } static void comparaLexico() {

12/04/2023 14

Page 15: Tipos de Datos en Java

FUNDAMENTOS DE PROGRAMACION SEMESTRE OTOÑO/2007

String cadena1 = "Hola", cadena2 = "Chao"; if (cadena1.compareTo(cadena2) == 0) { System.out.println("Son iguales"); } else { System.out.println("No son iguales"); } } static void subCadena () { String Alumnos = "Alumnos del IPP"; System.out.println ("El largo de la cadena es : " + Alumnos.substring(0,5)); } static void concatena () { String cadena1 = "Soy Alumno"; String cadena2 = " Del IPP"; System.out.println ("El largo de la cadena es : " + cadena1.concat(cadena2)); } static void adicionaCadena () { String cadena1 = "Soy Alumno"; String cadena2 = " Del IPP"; System.out.println ("El largo de la cadena es : " + cadena1.concat(cadena2)); }

static void reemplaza () { String cadena1 = "Soy Alumno"; String cadena2 = " Del IPP"; System.out.println ("El largo de la cadena es : " + cadena1.replace('o', 'a')); } static void mayusculas () { String cadena1 = "Soy Alumno"; System.out.println ("El largo de la cadena es : " + cadena1.toUpperCase()); } static void minusculas () { String cadena1 = "Soy Alumno"; System.out.println ("El largo de la cadena es : " + cadena1.toLowerCase()); }}

12/04/2023 15

Page 16: Tipos de Datos en Java

FUNDAMENTOS DE PROGRAMACION SEMESTRE OTOÑO/2007

Bibliografía

http://www.programacion.net

http://www.janeg.ca/scjp/oper/conversions.html

12/04/2023 16