Quantcast
Channel: Planeta Código
Viewing all 2698 articles
Browse latest View live

Picando Código: Elastic 7.13.0: Actualizaciones de los clientes oficiales Elasticsearch y Enterprise Search

$
0
0

El martes pasado se publicó la versión 7.13.0 de Elastic: Las mejoras clave incluyen búsqueda con buena relación costo-efectividad en más datos a través de snapshots buscables y el nivel congelado, mejoras de datos impulsados por analistas sobre la marcha con campos de tiempo de ejecución y más integraciones con Microsoft (muchos más detalles en el enlace). Como en cada nueva versión del Stack, esto significó también que en mi equipo publicamos los clientes oficiales para Elasticsearch y Elastic Enterprise Search.

Clientes Elasticsearch

Tenemos clientes oficiales para Elasticsearch en Ruby, Python, PHP, Perl, JavaScript, .NET, Rust, Go y Java. Soportamos todas las APIs de Elasticsearch y tenemos todo un sistema de testeo contra la especificación lo que nos asegura compatibilidad completa. La mayoría de los clientes ya están disponibles en la versión 7.13.0 en sus respectivos sistemas de dependencias e instalación de paquetes. Pueden leer más sobre los clientes en este enlace.

Elastic 7.13.0

Clientes Enterprise Search

El proyecto de Elastic Enterprise Search empezó con los clientes Ruby y Python, y de a poco se irán sumando más lenguajes. Una de las novedades de la versión 7.13.0 es que se publica la primera versión estable del cliente Elastic Enterprise Search para PHP. Ha sido genial trabajar en equipo con mis compañeros del equipo de Clientes y el equipo Enterprise Search. La suerte que tuve de terminar en este trabajo es algo que no doy por sentado. Tenemos un equipo políglota trabajando en código abierto en tecnologías interesantes y con gente que sabe muchísimo y es muy buena gente.

En el post Elastic Enterprise Search – cliente oficial en Ruby explico más qué son Elastic Enterprise Search, Workplace Search y App Search, así como detalles de la implementación del cliente en Ruby.

En cuanto a las novedades técnicas, hay varias cosas nuevas interesantes en la API 7.13.0 de Enterprise Search, particularmente en lo que respecta a Workplace Search:

Nuevos métodos de autenticación en Workplace Search

El sistema soporta autenticación Básica HTTP y autenticación a través de tokens Elasticsearch a partir de esta versión. La API también, así que el cliente lo soporta también. Todos los APIs de Workplace Search soportan ambos métodos de autenticación y tokens de administración de Workplace Search (la autenticación que se podían usar hasta ahora), pero todavía necesitamos pasar por el proceso de OAuth para Búsqueda y Analítica.

El código funciona así:

host = 'https://id.ent-search.europe-west2.gcp.elastic-cloud.com'
basic_auth = { user: 'enterprise_search', password: 'changeme' }

workplace_search_client = Elastic::EnterpriseSearch::WorkplaceSearch::Client.new(
  host: host,
  http_auth: basic_auth
)

Y en el caso de tokens, en vez de un hash con usuario y contraseña, pasamos un String con el token ya sea en la inicialización o seteándolo como propiedad.

Nuevas APIs

Particularmente interesantes las APIs que nos permiten gestionar fuentes de contenido “content sources”. Workplace Search funciona en base a fuentes de contenido que se unen en una misma experiencia de búsqueda, y ahora podemos integrar una fuente nueva desde nuestro código Ruby. Si tenemos las credenciales de autenticación básica HTTP, ya no necesitamos crear las fuentes de contenido desde la interfaz web:

  • document: Obtener un documento por ID de una fuente de contenido específica.
  • delete_all_documents: Elimina todos los documentos de una fuente dada.
  • content_source: Obtiene una fuente de contenido por ID
  • create_content_source: Crea una fuente.
  • delete_content_source: Elimina una fuente por ID.
  • list_content_sources: Lista todas las fuentes.
  • put_content_source: Actualiza una fuente de contenidos.

Un ejemplo de código:

# Crear una fuente de contenido:
client.create_content_source(name: 'picando-codigo')

# Obtener una fuente de contenido por ID:
content_source_id = client.create_content_source(name: 'libros').body['id']
client.content_source(content_source_id)

# Eliminar una fuente de contenido por ID:
client.delete_content_source(content_source_id)

# Obtener una lista de todas las fuentes de contenido:
client.list_content_sources

# Actualizar una fuente de contenido:
body = {
  name: new_name,
  schema: { title: 'text', body: 'text', url: 'text' },
  display: { title_field: 'title', url_field: 'url', color: '#f00f00' },
  is_searchable: true
}
client.put_content_source(id, body: body)

La verdad ambos productos se están poniendo cada vez mejor, y hay mucha cosa nueva e interesante en el horizonte para futuras versiones!
Si tienen cualquier duda sobre el cliente para Elasticsearch o Elastic Enterprise Search, estoy a las órdenes para intentar ayudar 🙂

El post Elastic 7.13.0: Actualizaciones de los clientes oficiales Elasticsearch y Enterprise Search fue publicado originalmente en Picando Código.

Blog Bitix: Cómo ordenar arrays y colecciones de objetos en Java

$
0
0

Al implementar un algoritmo es común querer iterar los elementos de una colección en un orden según un criterio, por ejemplo, si se trata de números de menor a mayor, si se trata de fechas de menor a mayor y si se trata de personas por orden alfabético del nombre, de menor a mayor edad o de menor a mayor antigüedad en la empresa, también es posible la necesidad de iterar en orden inverso. El JDK de Java proporciona interfaces para implementar la ordenación de objetos y que ya implementan algunos de los algoritmos de ordenación conocidos.

Java

Entre las clases proporcionadas en el JDK de Java se proporciona un amplio conjunto de clases dedicadas a colecciones que son el fundamento de muchos algoritmos de programación y programas. Las clases de colecciones sirven para almacenar referencias a objetos, algunas colecciones no tiene un orden definido como Set y Map y otras definen un orden en la iteración de la colección como List pero no un orden entre los elementos, otras colecciones como TreeSet y TreeMap guardan los elementos ordenados según un criterio manteniéndose ordenada incluyendo al realizar inserciones y eliminaciones de elementos.

Hay varios algoritmos de ordenación conocidos como la ordenación por burbuja o bubble-sort, por inserción, merge-sort o quicksort cada uno con diferentes propiedades de complejidad o consumo de memoria. Normalmente no es necesario implementar estos algoritmos, sino que ya están implementados en las bibliotecas y en el caso de Java en las clases del JDK.

El usar colecciones ordenadas por un orden es una funcionalidad común al implementar programas lo único que es necesario es utilizar la colección adecuada y únicamente crear una clase que implemente la interfaz Comparator que determina el orden entre dos elementos, aplicando la comparación a los elementos de la colección con el algoritmo de ordenación ser ordena la colección.

Algoritmo de ordenación bubble-sortAlgoritmo de ordenación merge-sort

Algoritmo de ordenación bubble-sort y merge-sort

Contenido del artículo

La interfaz Comparator

La interfaz Comprator es una interfaz funcional, por tener un único método a implementar, que recibe dos argumentos y devuelve un entero. Los argumentos son los dos objetos a comparar y el resultado indica cual es el orden de los elementos entre sí.

Si el resultado es un -1 se indica que el argumento a tiene un orden menor que b, si devuelve un 0 el orden de los elementos es el mismo y si devuelve un 1 el argumento a tiene un orden superior a b.

Estas son implementaciones de Comparator utilizando referencias de métodos.

1
2
Comparator<Person>ageComparator=Comparator.comparing(Person::getAge);Comparator<Person>hireComparator=Comparator.comparing(Person::getHired);
Comparators.java

Para ordenar cadenas alfabéticamente también es necesario crear un comparador, sin embargo, la ordenación de cadenas alfabéticamente no es tan simple como utilizar el método comprateTo de la clase String. Para ordenar cadenas alfabéticamente en Java hay de tener en cuenta letras con tildes, mayúsculas y minúsculas que varían según el idioma de las palabras, el método comprteTo que podría usarse para crear un Comprator no es válido y puede producir resultados inesperados ya que el String.compareTo ordena según el código de los caracteres sin tener en cuenta tildes ni mayúsculas ni minúsculas.

Esta es la implementación de un Comparator que ordena cadenas en orden ascendente de forma alfabética utilizando la clase Collator.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
privatestaticclassNameComparatorimplementsComparator<Person>{    privateCollatorcollator;    publicNameComparator(){        this.collator=Collator.getInstance(newLocale("es"));        collator.setStrength(Collator.TERTIARY);    }    @Override    publicintcompare(Persono1,Persono2){        returncollator.compare(o1.getName(),o2.getName());    }}
NameComparator.java

Con la clase Comparator es posible ordenar cualquier clase, en este ejemplo de clase Person se ordenan los objetos según su edad, fecha de contratación y nombre. Como en este caso es posible tener varias implementaciones de Comprator para una misma clase para ordenar los objetos por diferentes criterios.

La interfaz Comparable

Otra interfaz relacionada con la ordenación es la interfaz Comparable, es una interfaz que pueden implementar los objetos, la ordenación que se establece en la ordenación se le denomina el orden natural.

A diferencia de la clase Comparator de la que es posible crear varias implementaciones, las clases sólo pueden implementar una vez la interfaz Comparable.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
privatestaticclassPersonimplementsComparable<Person>{    privateStringname;    privateintage;    privateLocalDatehired;    publicPerson(Stringname,intage,LocalDatehired){        this.name=name;        this.age=age;        this.hired=hired;    }    ...    @Override    publicintcompareTo(Persono){        if(age<o.getAge()){            return-1;        }elseif(age>o.getAge()){            return1;        }else{            return0;        }    }}
Person-comparable.java

Cómo ordenar los elementos un array

La clase Arrays contiene varios métodos de utilidad entre ellos varios dedicados a la ordenación de los elementos de un array tanto para elementos primitivos como para objetos. Hay métodos que utilizan el la ordenación natural de la interfaz Comparable y hay métodos en los que es posible indicar la clase Comparator con el orden deseado entre los elementos.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
packageio.github.picodotdev.blogbitix.javasort;...publicclassMain{    publicstaticvoidmain(String[]args){        int[]array=newint[]{64,47,33,82,91,1,45};        List<Integer>list=Arrays.stream(array).boxed().collect(Collectors.toList());        List<Person>persons=List.of(                newPerson("Juan",56,LocalDate.of(1982,3,26)),                newPerson("María",24,LocalDate.of(2018,8,7)),                newPerson("Marisa",63,LocalDate.of(2021,4,17)),                newPerson("Antonio",41,LocalDate.of(2020,5,2))        );        Comparator<Person>nameComparator=newNameComparator();        Comparator<Person>ageComparator=Comparator.comparing(Person::getAge);        Comparator<Person>hireComparator=Comparator.comparing(Person::getHired);        ...    }    ...}
Main.java
1
2
3
4
5
System.out.println();System.out.println("Array (sorted)");int[]arraySorted=Arrays.copyOf(array,array.length);Arrays.sort(arraySorted);Arrays.stream(arraySorted).forEach(i->System.out.println(i));
Array-sort.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
Array(unsorted)6447338291145...Array(sorted)1334547648291...
System.out-array

Cómo ordenar los elementos de una colección

Las clase Collections es el equivalente de la clase Arrays para las colecciones, también tiene métodos de utilidad en este caso para las colecciones. Tiene un método sort para ordenar los elementos de una lista según el orden natural y para ordenar los elementos de la lista según el criterio de un Comparator.

A tener en cuenta que tanto los métodos sort de Arrays como de Collections no devuelven una nueva instancia de array o colección ordenada sino que modifican la instancia de array o colección que se proporciona para ordenar.

1
2
3
4
5
System.out.println();System.out.println("List (sorted)");List<Integer>listSorted=newArrayList<>(list);Collections.sort(listSorted);listSorted.stream().forEach(i->System.out.println(i));
List-sort.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
System.out.println();System.out.println("Persons (sorted, natural)");List<Person>personsSortedNatural=newArrayList<>(persons);Collections.sort(personsSortedNatural);personsSortedNatural.stream().forEach(i->System.out.println(i));System.out.println();System.out.println("Persons (sorted, name)");List<Person>personsSortedName=newArrayList<>(persons);Collections.sort(personsSortedName,nameComparator);personsSortedName.stream().forEach(i->System.out.println(i));System.out.println();System.out.println("Persons (sorted, age)");List<Person>personsSortedAge=newArrayList<>(persons);Collections.sort(personsSortedAge,ageComparator);personsSortedAge.stream().forEach(i->System.out.println(i));System.out.println();System.out.println("Persons (sorted, hired)");List<Person>personsSortedHired=newArrayList<>(persons);Collections.sort(personsSortedHired,hireComparator);personsSortedHired.stream().forEach(i->System.out.println(i));
Person-sort.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
List(unsorted)6447338291145Persons(unsorted)Person(name=Juan,age=56,hired=1982-03-26)Person(name=María,age=24,hired=2018-08-07)Person(name=Marisa,age=63,hired=2021-04-17)Person(name=Antonio,age=41,hired=2020-05-02)...List(sorted)1334547648291Persons(sorted,natural)Person(name=María,age=24,hired=2018-08-07)Person(name=Antonio,age=41,hired=2020-05-02)Person(name=Juan,age=56,hired=1982-03-26)Person(name=Marisa,age=63,hired=2021-04-17)Persons(sorted,name)Person(name=Antonio,age=41,hired=2020-05-02)Person(name=Juan,age=56,hired=1982-03-26)Person(name=María,age=24,hired=2018-08-07)Person(name=Marisa,age=63,hired=2021-04-17)Persons(sorted,age)Person(name=María,age=24,hired=2018-08-07)Person(name=Antonio,age=41,hired=2020-05-02)Person(name=Juan,age=56,hired=1982-03-26)Person(name=Marisa,age=63,hired=2021-04-17)Persons(sorted,hired)Person(name=Juan,age=56,hired=1982-03-26)Person(name=María,age=24,hired=2018-08-07)Person(name=Antonio,age=41,hired=2020-05-02)Person(name=Marisa,age=63,hired=2021-04-17)
System.out-collection

Invertir el orden

La interfaz Comprable establece un orden ya sea ascendente o descendente según el criterio que implementa, si en un caso se desea el orden inverso del comprador la propia interfaz Comparator permite obtener un Comparator con el orden inverso al de la instancia. También es posible obtener un comprador que ordene las referencias nulas al principio si es que hay alguna en la colección.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
System.out.println();System.out.println("Array (sorted descending)");Integer[]arraySorted=Arrays.stream(array).boxed().toArray(Integer[]::new);Arrays.sort(arraySorted,Collections.reverseOrder());Arrays.stream(arraySorted).forEach(i->System.out.println(i));System.out.println();System.out.println("List (sorted descending)");List<Integer>listSortedNatural=newArrayList<>(list);Collections.sort(listSortedNatural,Comparator.<Integer>naturalOrder().reversed());listSortedNatural.stream().forEach(i->System.out.println(i));System.out.println();System.out.println("Persons (sorted descending, age)");List<Person>personsSortedAge=newArrayList<>(persons);Collections.sort(personsSortedAge,ageComparator.reversed());personsSortedAge.stream().forEach(i->System.out.println(i));
Sort-reverse.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Array(sorteddescending)9182644745331List(sorteddescending)9182644745331Persons(sorteddescending,age)Person(name=Marisa,age=63,hired=2021-04-17)Person(name=Juan,age=56,hired=1982-03-26)Person(name=Antonio,age=41,hired=2020-05-02)Person(name=María,age=24,hired=2018-08-07)
System.out-reverse
Terminal

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando siguiente comando:
./gradlew run

Blog Bitix: Herramientas de línea de comandos para monitorizar GNU/Linux

$
0
0

A veces un proceso del sistema consume gran cantidad de procesador, memoria o realiza muchas operaciones de lectura o escritura en el almacenamiento, simplemente se desea obtener o monitorizar cierta información del sistema. Hay varias herramientas en GNU/Linux para monitorizar los procesos del sistema, en almacenamiento, la red y temperatura de componentes, otros comandos permiten obtener infomación de los principales componentes hardware y software de la computadora.

Linux

En GNU/Linux hay una colección de herramientas de línea de comandos para obtener información y monitorizar el estado del sistema. Estas herramientas permiten dar respuesta a las preguntas ¿qué porcentaje del procesador están usando los procesos?, ¿cuánta memoria están usando los procesos y cuanta queda libre?, ¿cual es el espacio de almacenamiento usado y cuanto espacio de almacenamiento queda libre?, ¿cual es la tasa de transferencia para el disco y red? o ¿que temperatura tiene el procesador?.

Otra información que es posible conocer es cuanta memoria tiene el sistema, cuánto almacenamiento tiene el sistema en total, cual es el modelo de procesador, cuál es el modelo de tarjeta gráfica o cual es el entorno de escritorio.

Las siguientes herramientas permiten monitorizar en tiempo real el estado del sistema y obtener información del mismo, tanto para los procesos, almacenamiento y red.

Contenido del artículo

Monitorizar procesos del sistema

Estas herramientas permiten monitorizar los procesos del sistema, principalmente en consumo de procesador y memoria.

top

Esta herramienta permite monitorizar los procesos del sistema en tiempo real, ver cuánto porcentaje de procesador se está usando, cuanta memoria se está usando y qué procesos lo están haciendo además de conocer qué cantidad de memoria total tiene el sistema.

Es una herramienta que está entre la colección de herramientas instaladas por defecto en la mayoría de sistema GNU/Linux.

Com la tecla h se accede al panel de configuración en el que es posible personalizar los colores, ver las teclas de acceso para mostrar información y otras opciones de configuración que se mantienen entre diferentes ejecuciones del programa.

1
2
$ top -u picodotdev

top.sh

Comando top

Comando topComando top

Comando top

htop

htop es una herramienta con el mismo propósito que top pero un poco más avanzada mostrando algo más de información, permite ver los procesos del sistema, consumo de procesador y memoria que están usando. Permite ver el uso del procesador por núcleo de CPU.

Al igual que top permite ordenar la lista de procesos por uso de procesador, uso de memoria, o tipos de CPU consumidos en orden descendente o en orden ascendente. Ofrece integración con el comando lsof.

Con la tecla F1 es posible ver las opciones de configuración de la utilidad.

1
2
$ sudo pacman -S htop
$ htop
htop.sh

Comando htopComando htop

Comando htop

ps

El comando ps permite obtener información del estado de los procesos del sistema en el instante que se ejecuta. Posee varias opciones para filtrar los procesos que devuelve y su información de estado.

1
2
$ ps

ps.sh

Comando ps

Comando ps

bpytop

bpytop es una herramienta similar a top y htop que muestra información del sistema en tiempo real pero incluyendo también tráfico de red y almacenamiento además del procesador, memoria, procesos. Algunas estadísticas las muestra en formato gráfica utilizando texto para ver más rápidamente el porcentaje de utilización del recurso.

Con la tecla M se accede al menu del programa donde configurar los diferentes paneles de información que muestra el programa.

1
2
$ sudo pacman -S bpytop
$ bpytop
bpytop.sh

Comando bpytop

Comando bpytopComando bpytop

Comando bpytop

free

El comando free permite ver la memoria física del sistema y la cantidad de memoria virtual o swap.

1
2
$ free -h

free.sh

Comando free

Comando free

Monitorizar almacenamiento

Las siguientes herramientas permiten monitorizar el almacenamiento del sistema. Permiten ver cuál es la capacidad de todas las unidades conectadas, cuanto espacio de almacenamiento queda libre en cada una de ellas y cual es la tasa de transferencia de almacenamiento que está utilizando el sistema tanto en lectura como en escritura.

df

El comando df permite ver información del almacenamiento de las unidades conectadas al sistema en el momento de ejecutar el comando. Permite ver en cada una de ellas su capacidad total y espacio libre restante que le queda, dispositivo hardware, sus particiones y puntos de montaje. Con la opción -h muestra los datos en unidades más comprensibles como KiB, MiB y GiB en vez de en bytes.

1
2
$ df -h

df.sh

Comando df

Comando df

iotop

El comando iotop permite ver en tiempo real la tasa de transferencia de lectura y escritura que están empleando los procesos del sistema. Se puede ordenar los procesos por cantidad de lectura o cantidad de escritura.

Esta herramienta requiere permisos de superusuario en su ejecución.

1
2
$ sudo pacman -S iotop
$ sudo iotop
iotop.sh

Comando iotop

Comando iotop

lsof

El comando lsof permite conocer cuales son los archivos abiertos por los procesos del sistema en el momento de ejecutar el comando.

1
2
$ sudo pacman -S lsof
$ lsof
lsof.sh

Comando lsof

Comando lsof

Monitorizar red

Las siguientes herramientas permite monitorizar la entrada y salida del trafico red.

netstat

El comando netstat permite ver cuales son las conexiones de red establecidas por los procesos del sistema y su estado. Con la opción -c monitoriza el tráfico de red en tiempo real o de forma continua.

1
2
$ sudo pacman -S netstat-nat
$ netstat-nat
netstat.sh

tcpdump

El comando tcpdump permite capturar el tráfico de red de una interfaz de red, para un puerto de red o para un nombre de host como origen o destino específico. Con la opción -c se limita la captura a un número de paquetes determinado. También es posible guardar la captura a un archivo para analizarlo una vez terminada la captura con la opción -w.

1
2
3
4
5
6
7
$ sudo pacman -S tcpdump
$ sudo tcpdump -i any -c5 -nn port 80
$ sudo tcpdump -i any -c5 -nn src 192.168.1.6
$ sudo tcpdump -i any -c5 -nn dst 192.168.1.6

$ sudo tcpdump -i any -c10 -nn -w webserver.pcap port 80
$ tcpdump -nn -r webserver.pcap
tcpdump.sh

Comando tcpdump

Comando tcpdump

Otras herramientas de monitorización

uptime

El comando uptime permite ver cuánto tiempo lleva en funcionamiento el sistema desde su último apagado o reinicio.

1
2
$ uptime

uptime.sh

Comando uptime

Comando uptime

iostat

El comando iostat muestra información de entrada y salida del sistema agrupando la información por dispositivo de almacenamiento. A diferencia de iotop no muestra cual es el proceso que está realizando la operación de entrada y salida.

1
2
$ sudo pacman -S sysstat
$ iostat
iostat.sh

Comando iostat

Comando iostat

sensors

El comando sensors permite obtener información de la temperatura que incorporan varios de los componente de las computadoras. Este comando muestra la temperatura del procesador para cada uno de sus núcleos, también del dispositivo de almacenamiento NVMe.

1
2
$ sensors

sensors.sh

Comando sensors

Comando sensors

watch

El comando sensors no muestra la temperatura en tiempo real, únicamente en el momento de su ejecución. El comando watch permite ejecutar un comando según el intervalo de tiempo deseado, utilizado con el comando sensors permite dotarle a este de monitorización casi en tiempo real configurando el intervalo de ejecución cada un segundo.

1
2
$ watch -n 1 sensors

watch.sh

Comando watch

Comando watch

neofetch

El comando neofetch muestra la información básica del sistema en el que se ejecuta. Aunque la información no es muy detallada contiene la descripción del los componentes de hardware y software principales del sistema como procesador, memoria, tarjeta gráfica, kernel, distribución de GNU/Linux, entorno de escritorio, número de paquetes instalados y algunas informaciones adicionales menos relevantes.

1
2
$ sudo pacman -S neofetch
$ neofetch
neofetch.sh

Comando neofetch

Comando neofetch

hwinfo

Aunque el comando hwinfo no es un comando de monitorización permite conocer diversa y detallada información del hardware del sistema. La información incluye datos sobre el modelo de procesador, modelo de placa base, unidad de almacenamiento y tarjeta gráfica. Esta información es útil en caso de necesitar algún paquete ya que algunos son específicos según el hardware del sistema por ejemplo los controladores de la tarjeta gráfica.

1
2
$ sudo pacman -S hwinfo
$ hwinfo --cpu
hwinfo.sh

Comando hwinfoComando hwinfo

Comando hwinfo

Variable not found: Enlaces interesantes 446

$
0
0
Enlaces interesantes

Ahí van los enlaces recopilados durante la semana pasada, con muchas novedades de la Build 2021. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

ASP.NET Core / ASP.NET / Blazor

Azure / Cloud

Conceptos / Patrones / Buenas prácticas

Data

Machine learning / IA / Bots

Web / HTML / CSS / Javascript

Visual Studio / Complementos / Herramientas

Xamarin / Maui

Otros

Publicado en Variable not found.

Picando Código: rvm-prompt: muestra la versión actual de Ruby en el prompt de tu terminal

$
0
0

rvm-prompt es una herramienta que muestra la versión actual de Ruby. Podemos usarla para mostrar esta información en nuestro prompt en la terminal:

rvm-prompt
Para agregarlo, en nuestro archivo de configuración ~/.bashrc, ~/.profile o lo que sea, tenemos que agregar el comando a la variable PS1. El ejemplo de la documentación:

PS1=”\$(~/.rvm/bin/rvm-prompt) $PS1″

Para el resultado de la imagen con los colores, la rama de GitHub y demás, yo uso en mi ~/.bashrc:

PS1=’\[\033[01;32m\]\u\[\033[01;34;10m\] \[\033[01;34m\]\w\[\033[01;33m\] \e[31m`rvm-prompt`\e[0m\[\033[01;36m\]$(__git_ps1)\n\[\033[01;34m\]\$\[\033[00m\] ‘

Como podemos leer en la documentación, hay varios parámetros que le podemos pasar al comando para mostrar el intérprete (i), versión (v), nivel de parche (p), gemset actual (g), revisión (r), arquitectura (a), un caracter unicode representando el intérprete (u) y la salida de imprimir “system” en Ruby (s). No tengo ni idea de dónde viene el caracter unicode. Con Ruby MRI muestra ⦿ y para JRuby ☯.

Me resulta bastante útil saber en qué versión de Ruby estoy trabajando, y también me recuerda actualizarla si me quedo en una versión patch antigua.

El post rvm-prompt: muestra la versión actual de Ruby en el prompt de tu terminal fue publicado originalmente en Picando Código.

Variable not found: Un vistazo a los patrones relacionales y combinadores, lo nuevo de C# 9 para exprimir el pattern matching

$
0
0
.NET Core

Desde C# 7 podemos emplear patrones en expresiones is o bloques switch para especificar las condiciones que deseamos comprobar, y cada nueva versión del lenguaje sigue introduciendo novedades al pattern matching, haciéndolo cada vez más sencillo y cómodo de utilizar.

En particular, C# 9 ha añadido un montón de características interesantes destinadas a facilitar el uso de patrones, pero en este post vamos a centrarnos en las dos más importantes: los combinadores de patrones y los patrones relacionales.

Los patrones relacionales permiten especificar restricciones utilizando los operadores relacionales<, <=, >, y >= para comparar el valor de la expresión a comprobar con constantes de los tipos soportados (sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, nint, y nuint).

Podemos ver un ejemplo sencillo de su uso en el siguiente bloque switch, donde, en lugar de introducir valores constantes en los casos, usamos los operadores relacionales para especificar las condiciones a cumplir en cada uno de ellos:

string result;
switch(i)
{
case 1:
result = "One";
break;
case < 3:
result = "Less than 3";
break;
case < 5:
result = "Less than 5";
break;
case >= 5:
result = "Equal or greater than 5";
break;
};

Ciertamente, en este código la forma de expresar las condiciones es concisa y fácilmente legible, aunque el bloque switch tradicional es demasiado verboso. Por ello, sería mejor replantear el código anterior con una expresión switch, lo que reducirá significativamente la cantidad de código a emplear (de 15 a 6 líneas), manteniendo la funcionalidad intacta:

var result = i switch
{
1 => "One",
< 3 => "Less than 3",
< 5 => "Less than 5",
>= 5 => "Equal or greater than 5",
};

Por otra parte, los combinadores de patrones introducen las nuevas las palabras clave and y or, que permiten evaluar condiciones compuestas por más de un patrón, y not, cuyo objetivo es negar la evaluación de un patrón. Combinando estos nuevos operadores podemos expresar de forma sencilla y fácilmente legible restricciones mucho más complejas que en versiones anteriores del lenguaje.

Por ejemplo, observad lo claro que resulta el siguiente bloque de código, imposible de crear antes de C#9:

var result = i switch
{
10 or 11 => "10-11",
>= 0 and <= 3 => "0-3",
<= 4 and <= 6 => "4-6",
>= 7 => "7-",
};

El compilador analizará las restricciones y será capaz de arrojarnos un error cuando existan ambigüedades o errores, como en el siguiente ejemplo:

var result = i switch
{
>= 0 and <= 3 => "0-3",
>= 2 and <= 3 => "2-3", // No compila, está incluido en el anterior
_ => "Otros"
};

Este mismo tipo de condiciones pueden utilizarse en bloques if a través del operador is:

if (i is 9 or 8) { ... }
if (i is >= 3 and <= 8) { ... }

En cuanto al combinador not, probablemente, uno de los ejemplos más claros de su uso lo vimos ya hace unos días, utilizándolo para determinar cuándo un objeto no es nulo:

if(invoice is not null)  { ... }

También podríamos usarlo en construcciones más complejas, donde ganamos bastante en legibilidad si lo comparamos con las versiones anteriores de C#. Veamos varios ejemplos.

En primer lugar, imaginad que necesitamos comprobar que un objeto no sea nulo, ni de un tipo determinado. Así es como se podría implementar en las dos últimas versiones del lenguaje:

// C# 8:
if(!(obj is null) && !(obj is Invoice))
{
// Si obj no es nulo, pero tampoco es un Invoice
}

// C# 9:
if (obj is not null and not Invoice)
{
// Sin comentarios, ¡el código se entiende solo!
}

Veamos ahora cómo determinar si un entero es distinto a un conjunto de valores determinados (en este caso, los impares en el rango 0-10):

// C# 8:
if(num != 1 && num != 3 && num != 5 && num != 7 && num != 9)
{
// Num no es 1, 3, 5, 7, ni 9
}

// C# 9:
if (num is not (1 or 3 or 5 or 7 or 9))
{
// Num no es 1, 3, 5, 7, ni 9
}

Fijamos que en este caso hemos utilizado paréntesis para introducir prioridades en la expresión. Es algo, también introducido en C# 9, que potencia aún más las capacidades de este tipo de construcciones.

El mismo nivel de concisión y elegancia podríamos lograrlo también al operar con enums, lo cual nos resolvería un escenario bastante frecuente:

// C# 9:
if (result.StatusCode is not (HttpStatusCode.OK or HttpStatusCode.Created))
{
// También con enums
}

¿Interesante, verdad? En definitiva, creo que estas incorporaciones al lenguaje son bastante potentes y probablemente acabarán popularizando definitivamente el uso de patrones en C#, que hasta ahora era bastante limitado.

Como ocurre siempre que hay cambios de este tipo, tendremos que acostumbrarnos al uso de una nueva sintaxis, pero estoy seguro de que el pequeño esfuerzo valdrá la pena y al final saldremos ganando porque en muchas ocasiones podremos expresar lo mismo en menos espacio, y ganando en claridad :)

Publicado en Variable not found.

info.xailer.com: Importantes novedades en Xailer Profesional

$
0
0

Después de haber convertido en un producto completamente gratuito nuestra versión base de Xailer y haber sido un completo éxito debido a su estupenda acogida. Ahora llega el turno de promocionar la versión profesional para hacerla muchísimo más interesante.

A partir de la publicación de este artículo Xailer Profesional recibe dos importantes novedades:

  • La inclusión de muchos controles que hasta ahora estaban presentes únicamente en la versión ‘Enterprise’, como son:
    • Acceso nativo a servidores de bases de datos MySQL, MariaDB y SQLite.
    • Acceso a escáner WIA.
    • Acceso al editor de imágenes.
  • Una importantísima reducción en su precio, que pasa de 395 € a 245 €

Y además como oferta de lanzamiento de esta nueva versión. Ofrecemos Xailer Profesional a precio de actualización, es decir, 145 € hasta el 30 de junio de 2021.

Se acabaron las excusas para no empezar a utilizar bases de datos SQL y abandonar definitivamente los ficheros DBF. Además los DataControls de Xailer, incluidos en la versión profesional hacen que el proceso sea muy fácil e intuitivo. Nunca es tarde para hacer el cambio.

Puede realizar su pedido directamente desde este enlace:

https://www.xailer.com/wp/pedido-de-xailer/

Comparativa de las distintas versiones de Xailer

XailerPersonalProfesionalEnterprise
Librería de clases y funciones para Windows
Entorno integrado de desarrollo
Documentación eletrónica completa y en español
Soporte técnico no preferencial
Soporte técnico preferencial mediante foro privado
Un año de soporte técnico y actualizaciones
Código fuente de las clases que integran la librería gráfica, excepto algunos componentes internos
Acceso a escaner WIA
Acceso a editor de imágenes
Componentes DataSets para acceso a distintos formatos de datos, DBF, ADS y SQL
Soporte de componentes ActiveX
Soporte nativo para MySQL y MariaDB
Soporte nativo para MySQlite
Soporte de bases de datos cifradas para MySQlite
Soporte para descargas desde internet mediante multihilos
Soporte de multihilos
Control Web browser nativo basado Webkit
Control Web browser nativo basado Microsoft Edge
Acceso a bases de datos externas via WEB
Controles avanzados y con estilo Windows 10
Animaciones avanzadas en controles

Header Files: Apple M1 y productividad

$
0
0

Ayer comienzó la WWDC 2021, la conferencia de desarrolladores de Apple y, como no, también tuvo lugar la tan esperada keynote en la que se anunciaron las siguientes versiones de sus principales sistemas operativos (aún estoy digiriendo todo lo presentado).

En la WWDC 2020 Apple también anunció que dejaría de usar los procesadores de Intel para migrar a sus propios chips (los que luego se llamarían M1), basados en su experiencia con el desarrollo de procesadores para iPhone, iPad, Apple Watch, etc. Estos procesadores cuentan con un diseño tipo SoC (system on a chip), es decir, que integran en un única bloque gran cantidad de componentes como puede ser la CPU, GPU, controlador de memoria, controlador de disco, etc. Además, en lo que concierne a la CPU, consta de cuatro núcleos de alto rendimiento (llamados Firestorm🔥), y cuatro de alta eficiencia energética (Icestorm🧊); los primeros son mucho más potentes pero consumen 10 veces más energía (13,8 W vs 1,3 W).

Los M1 logran superar con diferencia a las versiones más potentes de los i5 e i7 de Intel, e incluso llegan a igualar a los i9 en algunas pruebas de rendimiento. Tradicionalmente estos benchmarks miden la potencia bruta de un sistema (tales como operaciones por segundo, tiempo en tareas sintéticas), y al final resumen los resultados en un único valor fácilmente comparable. Ahora bien, de las cosas más impresionantes no es sólo que los M1 son rápidos, muy rápidos en estos tests sintéticos, sino que además parecen rápidos, y esto es el núcleo de este artículo (😉).

El día a día de la gran mayoría de los usuarios no es llevar el sistema al límite todo el tiempo, tal y como hacen estos benchmarks. El usuario no suele medir cuántas cosas puedo hacer en X segundos, sino más bien cuánto tiene que esperar para que lo que está haciendo termine. El flujo más habitual se parece a un conjunto de ráfagas pico en medio de valles más largos de menos exigencia computacional. Y es precisamente en la transición de valle a pico donde el usuario percibe la velocidad del sistema, donde la juzga y, hasta cierto punto, donde le importa: que su equipo puede con lo que se le pide. Podemos tener 11 aplicaciones abiertas tranquilamente, pero es cuando abrimos la número 12, o accedemos a un vídeo en el navegador, o guardamos un documento, o aplicamos un efecto a una imagen, es en el pico cuando decimos que el sistema no puede más😰.

Acá es cuando el sistema operativo, macOS Big Sur (y el ayer anunciado macOS Monterey), toma la potencia bruta y el diseño del M1 y los convierte en experiencia de usuario: siempre que puede trata de tener los Firestorm (núcleos de alto rendimiento) libres, sin hacer nada, mientras que los Icestorm llevan toda la carga. ¡Y es perfecto! porque esos núcleos tienen capacidad de sobra para gestionar las tareas de los valles (y consumiendo muy poca energía), a la vez que dejan a los titanes libres para reaccionar rápidamente ante cualquier demanda inesperada. Con esto, el sistema no sólo es rápido, sino que lo parece, responde al usuario cuando lo necesita, lo mantiene con tiempo de espera 0 👍🏼.

Hace poco leí un artículo muy interesante sobre gestión de proyectos que trataba un problema parecido (dejo el enlace al final): personalmente todos tenemos 11 tareas entre manos, y vamos bien, hasta que una de ellas entra en un pico: un problema difícil de resolver o que requiere un estudio más profundo, una reunión inesperada, un e-mail delicado, un bug de última hora, un ticket que se ha complicado y generado 7 nuevas tareas. Y a nivel de equipo pasa lo mismo: todos con varias responsabilidades, deadlines, funcionalidades que añadir, errores que resolver. Cuando nosotros o nuestro equipo estamos siempre al 100% (o más, que no es raro) no tenemos margen de maniobra y colapsamos: retraso en las tareas anteriores, estrés, impacto negativo en otros miembros del equipo). Como he dicho, esto aplica tanto a nivel de equipo (existen Icestorm y Firestorm para distintas tareas) como a nivel personal.

Cuando se planifica un proyecto a largo plazo es normal dejar un margen de maniobra, un colchón de recursos (tiempo, dinero, personal) para imprevistos. ¿Por qué, entonces, esta estrategia se diluye y desaparece cuando pasamos a las tareas específicas y su planificación a corto plazo? 😳

En estas situaciones de saturación el equipo tampoco puede dar un poquitico más porque simplemente no tiene tiempo para tonterías y tiene que hacer otras cosas antes de que se vaya a casa. Ese poquitico más es lo que muchas veces diferencia a lo mediocre de lo bueno, y a lo bueno de lo excelente, lo que marca la diferencia. Y terminan considerándose tonterías porque no son importantes, lo importante es estar a tope.

Por último, hay que tener en cuenta que nuestra eficacia y eficiciencia no es uniforme: cada persona tiene sus ritmos, sus fortalezas y debilidades, la productividad cambia durante el día, cambia dependiendo de la tarea que estemos haciendo, de cuál hayamos hecho, de la reunión de la que venimos o la que vamos a tener y que nos tiene ocupado un hilo en segundo plano. Estar a tope hace que no podamos organizar nuestras tareas de la forma más adecuada, con tiempo para despejarnos, limpiar el escritorio el mental, re-organizar ideas, reiniciar el sistema (y sí, hablo también del ordenador, que no pocos requieren un borrón y cuenta nueva de vez en cuando también para funcionar mejor).

Si dejamos que el equipo no esté al 100% será mucho más productivo, se sentirá mejor, tendrá más empodaramiento sobre sus tareas, no habrá retrasos porque se habrá planificado sobre ese sub-100%, se podrán adelantar trabajos, hacer tonterías que den valor añadido, innovar en ideas para las que nunca hay tiempo y que pueden ser el siguiente hit.

¿Cómo planificamos la gestión de nuestros núcleos? ¿Los usamos todos a tope para todo? ¿O dejamos que los Icestorm del equipo y personales estén disponibles para, entonces sí, darlo todo 💪🏼?

Para quien quiera profundizar en este tema os recomiendo la lectura de Exigir el 100% de ocupación de las personas esta destruyendo la eficiencia de tu equipo y organización .


Blog Bitix: Me cambio del ADSL a la fibra de Pepephone

$
0
0

El ADSL me ha sido suficiente para mis necesidades y era una opción algo más barata que la fibra. He retrasado el paso del ADSL a fibra todo lo que he podido hasta que por motivos de la compañía de mi servicio de internet me ha obligado. Las compañías están sustituyendo el par de cobre de teléfono con el que funciona el ADSL por la fibra. La fibra ofrece posibilidades que el ADSL no es capaz de ofrecer y el precio ligeramente superior de la fibra compensa para aquellos usuarios que quieran un ancho de banda notablemente superior. He estado varios años con el ADSL de Pepephone y ahora seguiré con la fibra de Pepephone.

Pepephone

Llevo casi cinco años con el servicio de internet con ADSL de Pepephone, durante todo este tiempo no he tenido ninguna incidencia importante ni con el servicio ni con el router. Contraté ADSL porque en el momento que lo hice no tenía posibilidad de fibra y el ADSL era algo más barato, aunque tuve que realizar el pago inicial incluyendo el coste de instalación y el coste del router.

El ADSL me ha servido para mis necesidades con suficiencia en navegación por internet, servicios de vídeo como YouTube, en las descargas de varios gigas no teniendo prisa usando torrent o por descarga directa e incluso me ha servido para teletrabajar.

Salvo por ciertos momentos puntuales en las que realizó alguna descarga de algún archivo que si quería que fuese más rápida pero sobre todo en la subida de datos, el ADSL es más que suficiente para navegar y ver vídeos de YouTube o Twitch a 1080p. En la descarga los 20 Mbps de bajada del ADSL se quedan en 1 MB/s, en la subida el ADSL se queda en unos reducidos 100 K/s.

La lenta velocidad de descarga del ADSL no me ha sido problema, es cuestión de dejar el programa torrent abierto, esperar un poco en la descarga de las actualizaciones de Arch Linux o de la consola PlayStation 4 y tener algo de paciencia. En la subida se nota más la falta de ancho de banda ya que los 100 KB/s son muy escasos incluso para subir fotos y otros datos, aún así como no es una tarea que realizo habitualmente en grandes cantidades no me era demasiado molesto.

A pesar de todo, por los motivos que comento a continuación he tenido que cambiar del servicio de ADSL a fibra.

Contenido del artículo

Motivo del cambio

La razón del motivo del cambio de ADSL a fibra no ha sido por necesidad sino por obligación del servicio de internet que me ofrece mi compañía Pepephone. Las compañías de internet ya solo ofrecen ADSL cuando no hay posibilidad de fibra, y a los clientes de ADSL cuando hay posibilidad de fibra les ofrecen cambiar a fibra a medida que se van cerrando centrales de par de cobre telefónico.

La razón es que la fibra tiene varias ventajas sobre el ADSL, la fibra tiene un ancho de banda mucho mayor tanto en bajada de datos pero sobre todo en la subida. Es un servicio más fiable al utilizar un medio que no es vulnerable a interferencias electromagnéticas ni tienen tanta atenuación con la distancia a la central. La fibra tiene menos costes de servicio que el par de teléfono que usa el ADSL y es un servicio que seguramente les deja más margen de beneficios a las compañías al tener un precio algo mayor que el ADSL. También les permite ofrecer servicios adicionales como televisión de pago o alquiler de películas que por otro lado les proporciona ingresos adicionales.

Por ello las compañías en los lugares que hay servicio de fibra ofrecen a los clientes solo fibra y a los existentes cambiarse a fibra, esto les permite a las compañías deshacerse del par de cobre del teléfono y cerrar centrales telefónicas ahorrando costes.

Hace cuestión de un mes recibí una notificación de que Pepephone con motivo de informarme sobre mi servicio de ADSL y unas semanas después he recibido una llamada informándome que el motivo es la necesidad de cambiar a fibra para la continuidad del servicio.

El proceso de instalación de fibra es muy rápido, al día siguiente ya tenía cita con el técnico para realizar la instalación y la instalación se realiza en un par de horas. En el proceso de instalación de fibra no se elimina el servicio anterior sino que se añade al existente y posteriormente se da de baja el antiguo. El técnico necesita acceso a los cuadros de telecomunicaciones del portal y al registro de la planta, se encarga de realizar la acometida canalizando el cable hasta el punto donde se desea la roseta de la fibra. Dado que la cita con el técnico es muy rápida, antes de iniciar el proceso es aconsejable tener acceso al cuarto de telecomunicaciones pidiendo la llave del armario al presidente de la comunidad o a un vecino si no se posee la llave.

Qué compañía de servicio de internet he elegido

El ADSL lo tenía con Pepephone, desde hace casi cinco años y durante todo este tiempo no he tenido ninguna incidencia que me haya obligado a contactar con su servicio de atención al cliente. He estado muy contento con el servicio y con el precio, el ADSL era de 23,6 € al mes, posiblemente la opción más económica de acceso a internet. Durante todos estos años no he tenido ninguna subida de precio tan habitual cada nuevo año en otras operadoras. No he dudado en ningún momento ni he tenido ninguna otra opinión de a qué compañía cambiarme, más bien seguir con Pepephone como primera opción, pero ahora con su fibra.

Con Pepephone tampoco he tenido molestas llamadas comerciales, ofrecen un servicio con buena calidad, tienen una buena atención al cliente, son claros en sus contratos y política de precios y los precios son muy competitivos. Estos principios no se encuentran en todas las compañías.

Así es como trata Pepephone a sus clientes, y sin que lo reclames.

Características del servicio de fibra

El precio de la fibra de Pepephone es de unos 35 € al mes, con la posibilidad de un descuento si se tiene una línea de teléfono con datos. A diferencia del ADSL la fibra permite que el servicio sea simétrico con la misma velocidad de bajada que de subida y muy superior al ADSL, la fibra de Pepephone básica llega a los 300 Mbits (básica en Pepephone, pero 300 es un ancho de banda muy respetable y superior a la básica de otras compañías) tanto en bajada como en subida que en realidad suele ser superior a lo ofertado para tener un margen de cumplir con el servicio contratado.

Desde hace algún tiempo en Pepephone no hay tiempo de permanencia, ni coste de alta, ni de instalación, ni de baja. El único punto a tener en cuenta es que el router se ofrece en modo cesión, que en caso de baja del servicio hay que devolverlo o adquirirlo en propiedad con un coste, la devolución es gratuita y se puede hacer en una oficina de correos.

El ONT y router ZTE

Al realizar la instalación los técnicos me han proporcionado un router ZTE sin ONT integrado, hubiese preferido que el router tuviese el ONT integrado ya que es un aparato menos, menos cables y una toma de energía menos en la regleta.

El modelo del router es un ZTE ZXHN H367A, con cuatro puertos gibagit, WIFI 5 o ac y un puerto USB 3.0 para hacer funciones de red para compartición de archivos, sin ONT integrado, es más grande que mi anterior router Asus DSL-N14U y tiene un formato vertical con las antenas WIFI ocultas. Dado que el ONT no está integrado en el router para que ocupe algo menos de espacio me he buscado una solución para conseguir que al menos quede «semintegrado» con un poco de celo.

Router fibra ZTE ZXHN H367ARouter fibra ZTE ZXHN H367ARouter fibra ZTE ZXHN H367A

Router fibra ZTE ZXHN H367A

ONT semintegrado en el router

ONT «semintegrado» en el router

Su panel de administración es muy sencillo pero con las funciones habituales, como abrir puertos, ocultar la WIFI, cambiar su nombre y las credenciales de acceso. Una cosa que me ha gustado es que permite crear varias redes WIFI con distintos nombres y contraseñas, a parte de eso el panel de administración me gustaba más el de Asus, quizá sea cuestión de acostumbrarme las raras ocasiones que deba entrar en él. Una de las primeras cosas que he hecho es cambiar la contraseña de inicio de sesión y poner la WIFI oculta por seguridad.

Panel de administración router ZTE

Panel de administración router ZTE

La instalación de la fibra requiere instalar una roseta a la que se conecta el cable de fibra que proviene del edificio, de la roseta sale otro cable de fibra que se conecta al ONT o al router si el router tiene el ONT integrado cosa que no es mi caso. El ONT se conecta al router con un cable ethernet.

Roseta fibra

Roseta fibra

Que ofrece la fibra respecto al ADSL

Lo que ofrece la fibra es un mucho mayor ancho de banda tanto de bajada como de subida, en la navegación por páginas web la diferencia entre el ADSL y fibra no me ha parecido tan notable, sin embargo, si se nota en las descargas directas y sobre todo en momentos puntuales de subidas de datos como fotos, en las descargas por torrent la velocidad en ningún momento me ha importando esperar algunos minutos u hora hasta que la descarga se completase esperando algo de tiempo.

Pasar de ADSL a fibra es un cambio muy significativo, no tanto en la navegación por internet sino como en el acceso a servicios que con el ADSL no son posibles. El ancho de banda que ofrece la fibra permite tener acceso a servicios que con el ADSL no es posible. Por ejemplo, con el ADSL ver un vídeo a una resolución de 2K o 4K el ancho de banda no es suficiente, la fibra permite ver sin parones los vídeos de YouTube a 2K en el monitor monitor Benq PD2700 que tengo.

También posibilita servicios de suscripción como televisión de pago, servicios de películas como Netflix, HBO, Disney+ entre otros servicios de vídeo. También permite acceder a servicios de juegos en la nube como Stadia que quizá sustituya como plataforma de juegos a la siguiente generación de consolas de la PS5 y la Xbox X/S. Otra de sus posibilidades permitir hacer streaming de juegos u otro tipo de contenido, dado que normalmente se hace subiendo un vídeo en alta resolución con buena calidad que necesita más ancho de banda de la que permite el ADSL.

El ancho de banda de bajada y subida es posible comprobarlo en la siguiente página web de prueba de velocidad o ancho de banda y latencia. Aunque la fibra contratada es de 300 Mb en la práctica es una de 600 Mb.

Prueba de velocidad ADSLPrueba de velocidad fibra

Prueba de velocidad ADSL y fibra

La fibra también tiene una latencia menor de entre 10 ms y 20 ms cuando el ADSL tiene una latencia de más de 40 ms.

Latencia ADSLLatencia fibra

Comparación de latencia entre ADSL y fibra

Navegapolis: El 90% de la energía humana depende del compromiso, no del cumplimiento.

$
0
0

Las empresas enfocadas en mejorar los objetivos de las personas y los departamentos, desarrollan culturas "naranjas" con tensiones competitivas y ambientes de trabajo tóxicos.

Las que trabajan para mejorar el sistema en su conjunto, desarrollan culturas más planas con relaciones igualitarias. Resultan menos eficientes y crean ambientes sociales de buenrollismo, pero con resultados pobres.

Lo curioso es que ambas teorías tienen sentido, y sin embargo ninguna funciona.

La primera se basa en la teoría de equilibrio general de Gerard Debreu, premio nobel de economía de 1983: "Si tienes agentes autointeresados con información privada sobre su tipo, su esfuerzo y su entorno, la única forma de incentivarlos es mediante KPIs. Mediante compensaciones relativas a sus objetivos sectoriales".

La segunda se basa en la teoría de la agencia de Jean Tirole, premio Nobel de economía de 2014 y afirma lo contrario: "Tienes que optimizar el sistema. No uses KPIs porque la optimización de los subsistemas, desoptimiza el sistema".

Este dilema, según explica Fred Kofman en su conferencia magistral del CIEE 2018(1), no tiene solución y no se puede resolver en el ámbito en el que se analiza: en el del cumplimiento de objetivos; sin embargo se puede gestionar en el ámbito del compromiso de las personas. Si te interesa el tema, no te puedes perder la conferencia completa: Fred Kofman, Conferencia Magistral CIIE 2018, de la que estos 3 minutos son un sabroso aperitivo:

 

(1) Congreso Internacional de Innovación Educativa 2018. Instituto Tecnológico y de Estudios Superiores de Monterrey.

 

 

Picando Código: Repaso de Nintendo en el E3 2021

$
0
0

Nintendo E3 2021

Terminó el E3 de este año, y por mi parte quedé conforme con las noticias de Nintendo. En el pasado 7 días en el Picandoverso comentaba algunas predicciones que me resultaban relativamente seguras, y con algunas acerté:

algún luchador de Smash Bros., algún adelanto más de Splatoon 3 o la secuela a The Legend Of Zelda: Breath Of The Wild. Sería sorpresa ver algo de Metroid Prime 4 (o la trilogía Prime que tanto se viene rumoreando para Switch), o que revivan alguna de las propiedades intelectuales que llevan tiempo descansando como Star Fox o F-Zero. La mejor sorpresa sería que Breath Of The Wild 2 tenga fecha de lanzamiento en 2021

Nintendo – con sus anfitriones Shinya Takahashi y Yoshiaki Koizumi– anunció varios títulos nuevos y algunos que ya conocíamos en su ya clásico formato de Nintendo Direct. No vimos nada de Splatoon 3, pero sí se anunció a Kazuya de la saga Tekken para Super Smash Bros. Ultimate.Va a haber más información en una presentación a cargo del genio ídolo mundial de Masahiro Sakurai, el 28 de junio a las 15:00 Edimburgo / 16:00 Madrid / 09:00 Ciudad de México / 11:00 Montevideo. Por más que no tengas interés en el juego o el luchador, éstas presentaciones valen la pena ver simplemente por la pasión y dedicación de Sakurai.

Se mostró Worms Rumble, un nuevo título de la saga Worms en 3D que parece muy entretenido para jugar con más gente.

Uno de los juegos nuevos anunciados que había visto antes del Nintendo Direct fue Guardians of the Galaxy. Se ve muy bien y me interesó bastante, pero tenía poca esperanza de verlo en Switch. Sin embargo apareció sorpresivamente durante el Nintendo Direct. Inicialmente mi reacción fue de entusiasmo. “Seguramente podría andar en Nintendo Switch con un poco de magia como hizo Panic Button con Doom”, pensé. Pero lamentablemente se trata de la versión “Cloud”, una forma de estafa que nos permite jugar desde nuestro Switch en otra computadora por internet, como lo que hace Google Stadia. Me pareció de cuarta que no especificaran en el Direct que era la versión Cloud, y tanto Google Stadia como las versiones Cloud en Switch me parecen una robada de plata gigante. De todas formas vale la pena mirar el trailer. Entre éste y el trailer de He-Man, Bonnie Tyler está cobrando buenas regalías este año 😆

Super Monkey Ball fue un juego que tuvo bastante éxito en la época del Game Cube. Para celebrar su vigésimo aniversario, Sega va a publicar Super Monkey Ball: Banana Mania, un compilado de remasters de niveles de juegos de la serie. Y en la misma onda de “remasters”, Nintendo va a publicar Mario Party Superstars, disponible el 29 de octubre. En principio pensé que era un DLC para Mario Party de Switch, pero se trata de un título nuevo que trae de vuelta 5 tableros clásicos de los juegos Mario Party de Nintendo 64. Incluye 100 minijuegos de los títulos de Nintendo 64 y GameCube, con juego online incluido y soporte para controles con los botones (no necesariamente controles de movimiento).

No mostraron nada de Metroid Prime 4, pero fue mencionado por Shinya Takahashi: “actualmente estamos trabajando mucho en el último título en la serie Metroid Prime: Metroid Prime 4, anunciado previamente. Pero hoy nos gustaría presentarles otra entrada nueva en la franquicia de Metroid“. Así se presentó Metroid Dread, uno de los títulos que más expectativa me generaron de esta presentación:

YouTube Video

Se trata del primer Metroid 2D en aproximadamente 19 años, un juego de acción basado en la exploración. El concepto nació hace 15 años, pero por falta de tecnología, se fue dejando de lado. Finalmente, tras trabajar en conjunto con Mercury Steam Entertainment en el desarrollo de Metroid: Samus Returns para Nintendo 3DS, decidieron implementarlo. Podemos ver más sobre la historia de su desarrollo en el video Metroid Dread – Development History.

La historia pretende cerrar el arco iniciado en el primer título Metroid para NES, continuado por Metroid II: Return of Samus, seguido de Super Metroid, y finalmente Metroid Fusion para Game Boy Advance. La idea es que a medida que avanza la historia, los jugadores nos preguntemos qué significa esto del “final de la historia”. Pero a pesar de hacer hincapié en que la historia es importante, el juego está enfocado tanto a seguidores de la saga como a jugadores nuevos. Incluye un prólogo que va a informar sobre todo por lo que ha pasado Samus hasta ahora a todas aquellas personas que no hayan jugado un Metroid antes.

El gameplay se basa en y mejora la idea original con algunas características nuevas. Entre otras cosas el traje de Samus cuenta con un dispositivo de camuflaje, la posibilidad de deslizarse al mejor estilo Mega Man en sus primeros títulos de NES y un imán para pegarse a paredes. El juego sale el 8 de octubre de 2021, va tener una edición especial con artbook, cartas con arte holográfico y más (estoy esperando que suban a la tienda oficial de Nintendo por estos lados para pre-ordenarlo). También va a estar acompañado de un set de dos amiibo (Samus y E.M.M.I). Increíble que Nintendo siga apostando por amiibo. Personalmente me gustan por lo coleccionable y la calidad es bastante buena, pero rara vez los uso con los juegos.

Cruis’n Blast, un juego de carreras licenciado por Nintendo para las maquinitas (o arcades) en la saga Cruis’n originalmente desarrollada por Midway para Nintendo Ultra 64. Más de 30 pistas, hasta 4 jugadores a la vez, y las imágenes muestran una pista con dinosaurios, así que puede estar interesante…

DLC para Doom Eternal: The Ancient Gods Part One, un juego que no ha tenido versión física para Nintendo Switch, y ocupa unos cuantos gigas en su versión digital. No lo he comprado por esto mismo, me niego a comprarlo en versión digital… Pero me encantó Doom 2016 y me pareció un excelente port en Nintendo Switch a pesar de los gráficos inferiores en relación a otras consolas más poderosas. Ojalá con el DLC disponible, eventualmente saquen una versión física donde el cartucho incluya todo el contenido.

Se mostró también Tony Hawk’s Pro Skate 1 + 2, un juego que ya tengo pre-ordenado y sale el 25 de junio. Se ve excelente, ni siquiera necesito esos gráficos mejorados para querer jugarlo en Switch. Si lo sacaban con los gráficos y el soundtrack originales, igual lo iba a comprar 😬 . Es irracional frustrarme porque gastaran tiempo en mostrar juegos que ya habían mostrado, pero es el momento, y si no mostraron más es porque no querían mostrar otras cosas. De esa misma forma mostraron algo de Mario + Rabbids Sparks of Hope. Me compré el primer Mario + Rabbids para Switch y lo terminé cambiando por otro juego porque me aburrió, así que no le di mucha atención a éste título.

Una noticia bastante interesante es que vuelve Advance Wars, una saga que pensé que Nintendo tenía abandonada (¡lo que implica que todavía hay esperanza para F-Zero y Star Fox!). En diciembre vamos a poder jugar los primeros dos títulos de esta serie con Advance Wars 1 + 2 Re-Boot Camp en Nintendo Switch.

Finalmente llegamos al último segmento del Nintendo Direct con lo que muchos esperábamos: Zelda. Este año se celebran 35 años de la leyenda, y hace como 2 años que vimos por primera y última vez algo de la secuela a uno de los mejores juegos de la historia: The Legend Of Zelda: Breath of the Wild. Era obvio que Nintendo nos iba a hacer sufrir para verlo, y primero nos mostró un poco del contenido descargable de Hyrule Warriors: Age Of Calamity, la precuela de BOTW. Lo que vi me dieron ganas de volver a jugarlo. Creo que le dediqué unas pocas horas en su momento y no lo volví a tocar. El 18 de junio se publica el primer DLC que entre otras cosas nos permite usar a un Guardian y a Zelda en una moto!

Acto seguido, Eiji Aonuma nos mostró un poco de The Legend Of Zelda: Skyward Sword HD, disponible el 16 de julio en Nintendo Switch. Siguió con un Game & Watch especial que conmemora los 35 años de La Leyenda de Zelda. Incluye los primeros dos juegos de NES: The Legend Of Zelda, Zelda 2: The Adventure of Link, la versión original de Game Boy de The Legend Of Zelda: Link’s Awakening (¡mi primer Zelda! ❤), un juego original de Game & Watch con Link y ¡UN RELOJ!

Finalmente, por fin pudimos ver un poco de material de la secuela a The Legend Of Zelda: Breath of the Wild:

YouTube Video

Link está cambiado, ya veremos cuántos años han pasado. Parece tener un brazo poseído por la malicia de Ganon que le permite usar las runas desde el brazo. La princesa Zelda está en problemas (la vemos caer a un pozo), así que dudo que sea un personaje jugable como muchos fans vienen pidiendo. Hay una conexión con Skyward Sword, además de andar por Hyrule, el mundo se expande a los cielos y de las primeras escenas que vemos es Link cayendo por los cielos. Parece haber algún tipo de manipulación del tiempo, vemos una gota de agua retrocedes en el tiempo y la música que parece en ese segmento tiene voces en reversa.

El trailer termina con unas notas de Zelda’s Lullaby y Eiji Aonuma nos pide que esperemos un poco más y que la fecha esperada es 2022. Por mi parte me quedo bastante contento de poder jugarlo en 2022. El original me dió muchísimas horas de entretenimiento y todavía hoy puedo volver y pasar unas horas de corrido recorriendo este nuevo Hyrule. Así que no tengo tanto apuro por jugarlo, Hyrule me espera…

Otros dos títulos que personalmente me interesaron bastante del E3, pero fueron anunciados previamente fueron la secuela de River City Girls: River City Girls 2 y River City Girls Zero, un port del título Shin Nekketsu Koha: Kunio-tachi no Banka de Super Famicom publicado en 1994 con un nuevo opening anime, escenas manga y nueva canción, localizado por primera vez fuera de Japón y disponible en su gloria de 16-bits para Nintendo Switch este año. Ambos juegos van a estar disponibles en formato físico a través de Limited Run Games, lo que va a hacer crecer mi colección de juegos de Limited Run Games (creo que hasta ahora TODOS del género beat ’em up).

Otros títulos anunciados durante el Nintendo Direct que o ya habían sido anunciados o en lo personal no me llaman tanto la atención como para comentarlos específicamente:

Life is Strange Remastered Collection (más tarde este año), Life is Strange True colors (Sep 10), Dear Villagers, Two Point Campus, un Just Dance (¿sigue saliendo para Wii este juego?), Dragon Ball Z: Kakarot + A new power Awakens set – un RPG de acción que se ve bastante bien y seguro sea el sueño de seguidores de la saga, Mario Golf Super Rush, Monster Hunter Stories 2: Wings of Ruin, WarioWare: Get it together! (me encantaban los Wario Land, pero éste tipo de juego de Wario no me resulta tan entretenido), Shin Megami Tensei V, Danganropa, Fatal Frame: Maiden of Black Water, Strange Brigade.

El post Repaso de Nintendo en el E3 2021 fue publicado originalmente en Picando Código.

Picando Código: Siete días en el Picandoverso: Arriba de una montaña

$
0
0

Entre los destaques a nivel personal de los últimos siete días, el sábado pasado escalé dos munros más de Escocia. Con un amigo nos tomamos un tren a las 7 de la mañana hasta Glasgow y después Bridge of Orchy. De la estación de tren caminamos y escalamos ambas Beinn Dòrain (1076m) y Beinn an Dòthaidh (1004m). Hay 282 munros en Escocia y con estas dos llevo 5 en total, me quedan 277 por escalar. La aventura estuvo genial, tuvimos un clima relativamente bueno hasta que llegamos a ambas cimas donde la vista estaba completamente cubierta por las nubes. Pero está muy bueno alcanzar el objetivo y brindar con un tradicional trago de whisky dentro de una nube al llegar a la cima. Seguiré escalando montañas ⛰

💉 Otro hecho a destacar es que me di la primera dosis de la vacuna contra el COVID. La vacunación viene bastante bien en Escocia y seguramente antes de fin de año hayan vacunado a toda la población. Entre el buen clima y que las restricciones se siguen flexibilizando, estoy saliendo más, tratando de aprovechar los fines de semana para dejar Edimburgo (¡estuve más de un año sin salir! 😱) y evitando usar la computadora y el teléfono. Sigo cada tanto la buena práctica de poner el teléfono en modo avión cuando ando paseando por ahí, ¡recomendado!

El E3 fue de lo que más mantuvo mi atención en lo que respecta a información esta semana, particularmente las noticias de Nintendo, pero ya lo comenté en mi repaso de Nintendo en el E3 2021. Voy entonces a los pocos temas que estuve leyendo esta semana:

7 días en el Picandoverso: Up on a mountain

Ruby

💎 Se publicó JRuby 9.2.19.0, una versión de correcciones para un problema con el flag --dev y un problema con zonas horarias en Windows.

💎 Se publicó Rubocop 1.17 que corrige un error que hacía que Rubocop fallara usando el bot Layout/HashAlignment, soporte para pattern matching de Ruby 2.7 y mucho más.

💎 El jueves de la semana que viene, 24 de junio es el último jueves del mes, así que hay meetup online de Ruby Galaxy. Está abierto el llamado a charlas. Veremos qué charlas se vienen en esta edición.

Televisión

⚔ Vuelve He-Man en Masters of the Universe: Revelation. Es la primera vez que vemos la animación y el trailer está excelente. ¡Buena decisión musical! Me pregunto si el trailer habrá sido editado por Kevin Smith mismo:

YouTube Video

Se estrena en Netflix el 23 de julio. El cómic por Dark Horse que conecta la serie original de Filmation con la serie nueva sale el 7 de julio (¡mi cumpleaños!), a tiempo para ir adentrándonos en el mundo de Eternia.

👿 Los miércoles se estrenan episodios nuevos de Loki, la nueva serie del Universo Cinematográfico de Marvel, en Disney+. El primer episodio el miércoles pasado estuvo genial, se viene con todo esta serie. Viajes en el tiempo, líneas de tiempo alternativas, full Marvel. Veremos qué tal el episodio de hoy.

Dinosaurios

🦖 Se confirmó que algunos dinosaurios en Jurassic World: Dominion (la tercera película de la nueva trilogía de Jurassic Park) van a tener plumas. Esto los hace un poquito más científicamente precisos.
El paleontólogo Steve Brusatte (autor de El Auge y Caída de los Dinosaurios) estuvo trabajando en la producción de la película, ayudando a hacer que los dinosaurios fueran un poco más precisos. Tuvo una conversación en Twitter que me resultó suficientemente interesante como para reproducirla:
“Van a tener que esperar y ver. Y recuerden es una película de taquilla y no un documental científico. La narración lleva muchos ángulos” dijo Steve. La otra persona respondió con más escepticismo y el odioso “veo mucha gente razonablemente preocupada por los efectos en el público” (¿qué gente? ¿”preocupada”? ¡Es una película ficticia sobre dinosaurios!). A lo que el paleontólogo respondió: “El público va a estar bien. A la gente le gusta las historias de origen, y esto es una forma sorprendente de contarlo. ¡Esperen y vean!”. En otro hilo cuenta un poco sobre uno de los dinosaurios nuevos de la película: Moros– un tiranosaurio del tamaño de un humano.

Picando Código

Me pregunto si alguien llegará a leer hasta acá además de Fernando del futuro que es el lector número uno de este blog…

Otros Siete días en el Picandoverso:

Los posts de Picando Código pueden seguirse por:

También estoy en Twitter y Mastodon, donde además de compartir lo que se publica en el blog publico alguna cosa más.

El post Siete días en el Picandoverso: Arriba de una montaña fue publicado originalmente en Picando Código.

Blog Bitix: Los autómatas del juego de la vida de Conway y la hormiga Langton con su implementación en Java

$
0
0

Algunos procesos que aparentemente son complejos siguen reglas muy simples, y aún siguiendo reglas muy simples dan lugar a muchos posibles comportamientos diferentes. Los sistemas que implementan y aplican estas reglas simples se les conoce como autómatas. Los autómatas no poseen inteligencia artificial, no aprenden ni toman decisiones en base a anteriores resultados, los autómatas simplemente siguen sus reglas de comportamiento en el estado del sistema. Dos autómatas conocidos son el juego de la vida de John Horton Conway publicado en 1970 y la hormiga de Langton de Chris Langton publicado en 1986.

Contenido del artículo

El juego de la vida de Conway

El juego de la vida de Conway es un autómata con unas reglas muy simples que da lugar a múltiples y variados comportamientos. Es un autómata de cero jugadores que se desarrolla por sí mismo en base al estado inicial y las reglas del juego.

El juego es un tablero bidimensional formado por cuadrados o células que poseen dos estados, células muertas o encendidas o células vivas o apagadas. Cada célula está rodeada por 8 células vecinas. El estado de las células evoluciona a lo largo de unidades de tiempo discretas, el estado de todas las células se tiene en cuenta para calcular el estado en el turno siguiente aplicando las reglas del juego. Todas las células se actualizan simultáneamente en cada turno.

Reglas

Las reglas del juego de la vida definido por Conway son las siguientes:

  • Una célula muerta con exactamente 3 células vecinas vivas nace, en el siguiente turno estará viva o encendida.
  • Una célula viva con 2 o 3 células vecinas vivas sigue viva.
  • En cualquier otro caso la célula muere o se apaga, por tener menos o más células adyacentes vivas de las reglas anteriores. Una célula viva muere por soledad o por superpoblación.

Variaciones, con otras reglas

El juego de la vida definido por Conway se representa con la siguiente nomenclatura 23/3, los primeros dos números indican las células necesarias para que una célula siga viva y el tercer número indica las células adyacentes necesarias para que una célula nazca.

Con otro número de células requeridas es posible crear variaciones del juego de la vida. Por ejemplo, 16/6 en el que una célula nace si tiene 6 vivas adyacentes y sigue viva si tiene un número igual a 1 o 6. Otra variación es 23/36 en el que una célula nace si el número de adyacentes vivas es 3 o 6 y sigue viva si el número de células vivas es 2 o 3, este caso es similar al juego de la vida de Conway variando que una célula nace si tiene 6 adyacentes vivas.

Patrones

Dado el estado inicial y las reglas de juego de la vida se observan varios patrones de comportamiento.

  • Osciladores: estos patrones siguen una serie de pasos hasta que un número determinado llega al estado inicial, el patrón se repite de forma cíclica.
  • Vidas estáticas: estas no cambian de estado con el paso del tiempo se mantienen en el mismo estado con el paso del tiempo.
  • Naves espaciales: estos patrones evolucionan dando la sensación de que se trasladan por el tablero de juego de la vida.
  • Matusalenes: son patrones que evolucionan o desaparecen después de un gran número grande de turnos.
  • Cañones: son patrones que generan planeadores o naves espaciales.
  • Locomotoras: son patrones que se desplazan por el tablero dejando un rastro de basura de osciladores, vidas estáticas, planeadores o naves espaciales.
  • Sintetizadores: son patrones que dispuestos de elementos más básicos como gliders producen otro tipos de patrones.

Uno de los patrones destacados del juego de la vida es una nave espacial conocido como glider, este es un patrón importante ya que son fáciles de producir que se pueden hacer colisionar con otros objetos de este modo ser usados para transmitir información. Ocho gliders pueden ser posicionados para que colisionen formando un cañón gosper glider. Otros patrones como bloques, beehives, blinkers, traffic lights son sintetizables con únicamente dos gliders.

Los gliders también son capaces de colisionar para producir otros comportamientos, si dos gliders son lanzados contra un bloque de la forma adecuada el bloque se mueve hacia a la fuente de los gliders. Si tres glider son disparados en la forma correcta el bloque se mueve más aún. Esta memoria de desplazamiento puede ser usada para simular un contador modificable lanzándole gliders. También es posible construir puertas lógicas como AND, OR o NOT usando gliders. Esto es la misma capacidad de computación que una máquina universal de Turing, de modo que usando gliders el juego de la vida es de forma teórica tan capaz como cualquier computadora con memoria ilimitada y sin restricciones de tiempo. Por estas propiedades del glider se ha adoptado como un icono de la cultura hacker.

En esta librería de patrones del juego de la vida de Conway hay una colección de patrones en la que además es posible visualizar su comportamiento.

GliderGlider gunDiehard

Patrones glider, glider gun y diehard

Patrones que crecen indefinidamentePatrones que crecen indefinidamentePatrones que crecen indefinidamente

Patrones que crecen indefinidamente

Otros patrones:

Cómo probar el juego de la vida

En algunas páginas es posible probar el juego de la vida para experimentar con su comportamiento.

La hormiga de Langton

La hormiga de Langton es otro tipo de autómata con unas reglas muy simples pero que da lugar a un comportamiento complejo. Al igual que el juego de la vida de Conway se desarrolla en un tablero de dos dimensiones en el que cada celda del tablero está encendida o apagada.

En está página de la wikipedia se puede probar la hormiga de Langton.

Hormiga de Langton

Patrón generado por la hormiga de Langton después de 10K pasos

Reglas

La hormiga de Langton se basa en las siguientes reglas:

  • Si está sobre un cuadrado encendido, cambia el color del cuadrado, gira noventa grados a la izquierda y avanza un cuadrado.
  • Si está sobre un cuadrado apagado, cambia el color del cuadrado, gira noventa grados a la derecha y avanza un cuadrado.

En el caso de la hormiga de Langton al cabo de unos 10000 turnos crea un patrón que sigue de forma indefinida.

Variaciones, con otras reglas

A la hormiga de Langton también es posible aplicarle otra reglas, por ejemplo añadiendo más estados a las celdas con colores o incluyendo varias hormigas en el tablero.

Implementación del juego de la vida en Java

Esta es la implementación en código con lenguaje Java del juego de la vida de Conway y sus reglas. Estas son las clases principales que implementan el juego, la clase Cell representa una célula con su estado y la clase Board en el método step produce el siguiente estado con las reglas del juego implementadas en los métodos survives, borns y countAliveNeighbours.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
packageio.github.picodotdev.blogbitix.javaconwaylangton.conway;publicclassCell{    publicenumStatus{        ALIVE,DEAD    }    privateStatusstatus;    privateintage;    publicCell(){        this(Status.DEAD);    }    publicCell(Statusstatus){        this(status,0);    }    publicCell(Statusstatus,intage){        this.status=status;        this.age=age;    }    publicbooleanisAlive(){        returnstatus==Status.ALIVE;    }    publicvoidsetAlive(){        this.status=Status.ALIVE;        this.age=0;    }    publicbooleanisDead(){        returnstatus==Status.DEAD;    }    publicvoidsetDead(){        this.status=Status.DEAD;        this.age=0;    }    publicintgetAge(){        returnage;    }    publicvoidtick(){        age+=1;    }    publicStatusgetStatus(){        returnstatus;    }        
    publicvoidsetStatus(Statusstatus){        if(this.status!=status){            age=0;        }        this.status=status;    }}
conway/Cell.java
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
packageio.github.picodotdev.blogbitix.javaconwaylangton.conway;...publicclassBoard{    privateCollection<Integer>aliveRules=List.of(2,3);    privateCollection<Integer>bornRules=List.of(3);    privateCell[][]cells;    publicBoard(Stringinitial){        this(initial,160,80);    }    publicBoard(Stringinitial,intwidth,intheight){        initCells(width,height);        loadCells(initial);    }    publicCellgetCell(intx,inty){        if(y<0||y>getHeight()){            returnnull;        }        if(x<0||x>getWidth()){            returnnull;        }        returncells[y][x];    }    publicintgetWidth(){        returncells[0].length;    }    publicintgetHeight(){        returncells.length;    }    publicintgetPopulation(){        intpopulation=0;        for(inty=0;y<getHeight();++y){            for(intx=0;x<getWidth();++x){                if(getCell(x,y).isAlive()){                    population+=1;                }            }        }        returnpopulation;    }    publicvoidstep(){        Cell[][]cells=newCell[getHeight()][getWidth()];        for(inty=0;y<getHeight();++y){            for(intx=0;x<getWidth();++x){                CelloldCell=getCell(x,y);                CellnewCell=newCell(oldCell.getStatus(),oldCell.getAge());                cells[y][x]=newCell;                intaliveNeighbours=countAliveNeighbours(x,y);                Cell.Statusstatus=(survives(oldCell,aliveNeighbours)||borns(oldCell,aliveNeighbours))?Cell.Status.ALIVE:Cell.Status.DEAD;                newCell.setStatus(status);            }        }        this.cells=cells;    }    privatebooleansurvives(Cellcell,intaliveNeighbours){        returncell.isAlive()&&aliveRules.contains(aliveNeighbours);    }    privatebooleanborns(Cellcell,intaliveNeighbours){        returncell.isDead()&&bornRules.contains(aliveNeighbours);    }    privateintcountAliveNeighbours(intx,inty){        return(int)getNeighbours(x,y).stream().filter(Cell::isAlive).count();    }    privateCollection<Cell>getNeighbours(intx,inty){        Collection<Position>positions=newArrayList<>();        for(intj=y-1;j<y+2;++j){            for(inti=x-1;i<x+2;++i){                if(i==x&&j==y){                    continue;                }                if(i<0||i>getWidth()-1||j<0||j>getHeight()-1){                    continue;                }                positions.add(newPosition(i,j));            }        }        returnpositions.stream().map(p->getCell(p.getX(),p.getY())).filter(Objects::nonNull).collect(Collectors.toList());    }    privatevoidinitCells(intwidth,intheight){        this.cells=newCell[height][width];        for(inty=0;y<height;++y){            for(intx=0;x<width;++x){                this.cells[y][x]=newCell(Cell.Status.DEAD);            }        }    }    privatevoidloadCells(Stringinitial){        intwidth=Arrays.stream(initial.split("\\n")).max(Comparator.comparing(s->s.length())).orElseGet(()->"").length();        intheight=initial.split("\\n").length;        intx=(getWidth()/2)-(width/2);        inty=(getHeight()/2)-(height/2);        for(inti=0,a=0,b=0;i<initial.length();++i){            Characterc=initial.charAt(i);            if(c=='\n'){                a=0;                b+=1;            }elseif(c!=' '){                Cellcell=getCell(x+a,y+b);                cell.setStatus(Cell.Status.ALIVE);                a+=1;            }else{                a+=1;            }        }    }}
conway/Board.java

Implementación de la hormiga de Hormiga de Langton en Java

Esta es la implementación en lenguaje Java de la hormiga de Langton y las reglas propias del juego. La clase Turmite representa la hormiga, el método step aplica la lógica del autómata de la hormiga en función del estádo de la celda en la que está. Los metodos turnLeft, turnRight y forward cambian el estado de la hormiga haciéndola cambiar de dirección y avanzando a otra celda.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
packageio.github.picodotdev.blogbitix.javaconwaylangton.langton;publicclassTurmite{    publicenumDirection{        UP,DOWN,LEFT,RIGHT    }    privateintx;    privateinty;    privateDirectiondirection;    publicTurmite(){        this(80,24,Direction.UP);    }    publicTurmite(intx,inty,Directiondirection){        this.x=x;        this.y=y;        this.direction=direction;    }    publicintgetX(){        returnx;    }    publicintgetY(){        returny;    }    publicPositiongetPosition(){        returnnewPosition(x,y);    }    publicbooleanisAt(intx,inty){        returnthis.x==x&&this.y==y;    }    publicvoidstep(Boardboard){        Cellcell=board.getCell(x,y);        if(cell==null){            return;        }        if(cell.isOn()){            cell.setOff();            turnLeft();            forward();        }elseif(cell.isOff()){            cell.setOn();            turnRight();            forward();        }    }    publicvoidforward(){        switch(direction){            caseUP:                this.y-=1;                break;            caseDOWN:                this.y+=1;                break;            caseLEFT:                this.x-=1;                break;            caseRIGHT:                this.x+=1;                break;        }    }    publicvoidturnLeft(){        switch(direction){            caseUP:                this.direction=Direction.LEFT;                break;            caseDOWN:                this.direction=Direction.RIGHT;                break;            caseLEFT:                this.direction=Direction.DOWN;                break;            caseRIGHT:                this.direction=Direction.UP;                break;        }    }    publicvoidturnRight(){        switch(direction){            caseUP:                this.direction=Direction.RIGHT;                break;            caseDOWN:                this.direction=Direction.LEFT;                break;            caseLEFT:                this.direction=Direction.UP;                break;            caseRIGHT:                this.direction=Direction.DOWN;                break;        }    }}
langton/Turmite.java
Terminal

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub.

Variable not found: Creando gráficas estadísticas en Blazor con los componentes visuales de Syncfusion

$
0
0
Syncfusion

Hace algunas semanas echamos un vistazo rápido a Blazor UI Components, la suite de componentes profesionales para Blazor proporcionada por Syncfusion.

Como vimos, se trata de una completa colección que soluciona las necesidades más habituales durante la creación de la interfaz de usuario de aplicaciones Blazor, tanto Server como WebAssembly. Más de 70 componentes que incluyen controles de entrada de datos, botones, calendarios, layouts, rejillas de datos o gráficas estadísticas, entre otros. Y lo mejor es que, aunque se trata de un producto comercial, su generosa licencia community permite que muchos podamos utilizarlos de forma totalmente gratuita.

Hoy vamos a profundizar un poco en los componentes de presentación de datos estadísticos, o Chart Components, que por su potencia, versatilidad y calidad del resultado merece un post en sí mismos.

Nota: lo que estáis leyendo es un post patrocinado por Syncfusion, pero en ningún momento han revisado previamente o condicionado de alguna forma su contenido.

¿Qué son los componentes Blazor Chart de Syncfusion?

Se trata de componentes para Blazor Server y WebAssembly que permiten visualizar datos usando más de treinta tipos de gráficas distintas, desde los más clásicos y simples diagramas de líneas, barras o áreas, hasta otros más complejos como gráficos financieros, radares, histogramas, tartas, etc.

Los tipos de gráficas soportados son los siguientes:

  • Line
  • Step line
  • Stacked line
  • 100% stacked line
  • Spline
  • Area
  • Range Area
  • Stacked Area
  • 100% Stacked Area
  • Step Area
  • Spline Area
  • Column
  • Range Column
  • Stacked Column
  • Bar Charts
  • Stacked Bar
  • 100% Stacked Bar
  • Scatter
  • Bubble
  • Polar
  • Radar
  • Hilo
  • High Low Open Close
  • Candle
  • Box and Whisker
  • Waterfall
  • Histogram
  • Error Bar
  • Vertical Chart
  • Pareto
  • Pie & Doughnut
  • Pyramid
  • Funnel

Puedes verlos en acción, junto con algunas de sus configuraciones específicas, en la página de demostraciones de Syncfusion.

Los componentes están diseñados para mostrar rápidamente grandes cantidades de datos; por ejemplo, en esta página puede verse un ejemplo de renderización de una gráfica de líneas con 100.000 valores en poco más de un segundo. Además, se adaptan a interfaces móviles y webs responsive, mostrando los datos con una pequeña animación, lo que hace que el resultado sea espectacular:

Gráficas con animaciones

Adicionalmente, es interesante destacar que las gráficas pueden ser interactivas. Es posible configurarlas de forma que el usuario puede pasear el ratón sobre ellas para visualizar información detallada en forma de tooltip, hacer zoom o pan sobre los datos, seleccionar rangos o incluso editar datos en tiempo real. También pueden exportarse como imagen o PDF, o ser enviados directamente a la impresora.

Cómo utilizar los Charts en nuestras aplicaciones Blazor

Los componentes Blazor de Syncfusion se distribuyen de forma individual en paquetes NuGet, por lo que sólo incluiremos en nuestras aplicaciones lo que realmente vayamos a necesitar. En este caso, dado que queremos incluir los componentes para crear Charts, instalaremos el paquete Syncfusion.Blazor.Charts.

A continuación, en la página contenedora de la aplicación Blazor (es decir, _Host.cshtml o index.html dependiendo de si usamos Blazor Server o WebAssembly), incluiremos una referencia hacia el tema visual. En el siguiente ejemplo usamos el tema bootstrap4, aunque podría ser cualquier otro de los suministrados.

También debemos incluir en ella una referencia hacia la biblioteca Lodash, un popular conjunto de helpers utilizado de forma interna por los mecanismos de interoperación con JS de los componentes. Esto lo conseguimos insertando la siguiente etiqueta <script>:

<head>
...
<link href="_content/Syncfusion.Blazor.Themes/bootstrap4.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"
integrity="sha512-90vH1Z83AJY9DmlWa8WkjkV79yfS2n2Oxhsi2dZbIv0nC4E6m5AbH8Nh156kkM7JePmqD6tcZsfad1ueoaovww=="
crossorigin="anonymous"></script>
</head>

A continuación, debemos registrar los servicios en el sistema de inyección de dependencias de .NET, introduciendo el siguiente código en el método ConfigureServices() de la clase Startup en Blazor Server, o en el método Main() de Program.cs en Blazor WebAssembly:

services.AddSyncfusionBlazor();

En el caso de Blazor Server, para evitar problemas, es conveniente también modificar el tamaño de los paquetes de datos para e

services.AddSignalR(e => { e.MaximumReceiveMessageSize = 65536; });

// O, alternativamente, si usamos Azure SignalR:
services.AddSignalR(e => { e.MaximumReceiveMessageSize = 65536;})
.AddAzureSignalR();

Por último, es buena idea añadir el espacio de nombres del componente al archivo _Imports.razor del proyecto, de forma que éste esté disponible en cualquier vista o página de la aplicación:

...
@using Syncfusion.Blazor.Charts

Hecho esto, ya podemos insertar una instancia de <SfChart>, el componente responsable de mostrar gráficas, en cualquier página o componente de nuestra aplicación. Por verlo rápidamente, probamos a hacerlo en Index.razor de la siguiente manera:

@page "/"
<h1>Hello, Blazor Chart!</h1>

<SfChart />

Y si ejecutamos la aplicación, veremos que ya tenemos el diagrama en la página. Obviamente está vacío porque no le hemos pasado datos, pero ya podemos comprobar que todos los pasos anteriores los hemos hecho correctamente... o casi:

Licencia inválida

El mensaje de error aparecerá en la zona superior de la pantalla siempre que utilicemos un componente Synfusion sin licencia. ¿Cómo podemos solucionarlo?

¿De dónde saco la licencia y cómo la incluyo en el proyecto?

Como ya comentamos en su momento, lo primero que necesitaréis para instalar y utilizar los componentes para Blazor de Syncfusion es disponer de unas claves de licencia del producto.

Si no las tenéis todavía, podéis seguir las indicaciones que dábamos entonces para descargar la free trial o reclamar una licencia community, que permite la utilización de componentes Syncfusion sin límite si cumplís unos requisitos bastante razonables.

Una vez registrados, sólo tenéis que acceder a vuestro dashboard y usar el enlace "Get License Key" para obtener una clave de licencia.

Una vez en vuestro poder, el siguiente paso es registrarla durante el arranque de nuestra aplicación. Lo más sencillo es hacerlo en el Program.cs:

using Syncfusion.Licensing;
...
public class Program
{
public static void Main(string[] args)
{
SyncfusionLicenseProvider.RegisterLicense("YOUR-LICENSE-KEY-HERE");
...
}
}

Hecho esto, si ejecutáis la aplicación veréis que el aviso de la licencia ha desaparecido.

Continuemos con el Chart...

Vamos a suministrarle datos al Chart algunos datos para ver que esto funciona. En primer lugar crearemos un servicio simple que nos proporcione los datos; en este caso, será una simple clase que nos ofrecerá un método para obtener datos sobre el país de origen de los visitantes de Variable Not Found durante los dos últimos años. Por simplificar, haremos que los datos se encuentren hardcodeados en el servicio, aunque obviamente podríamos leerlos de una base de datos, una API o cualquier otro origen:

public class CountryData
{
public int Year { get; set; }
public string Country { get; set; }
public decimal Percent { get; set; }
}

public static class VisitServices
{
private static readonly CountryData[] _data = new CountryData[]
{
new CountryData() {Year = 2019, Country = "Mexico", Percent = 25.1m},
new CountryData() {Year = 2019, Country = "Spain", Percent = 17.9m},
new CountryData() {Year = 2019, Country = "Colombia", Percent = 10.64m},
new CountryData() {Year = 2019, Country = "Argentina", Percent = 7.4m},
new CountryData() {Year = 2019, Country = "Peru", Percent = 8.51m},
new CountryData() {Year = 2019, Country = "Chile", Percent = 5.84m},
new CountryData() {Year = 2020, Country = "Mexico", Percent = 23.24m},
new CountryData() {Year = 2020, Country = "Spain", Percent = 17.5m},
new CountryData() {Year = 2020, Country = "Colombia", Percent = 11.3m},
new CountryData() {Year = 2020, Country = "Argentina", Percent = 9m},
new CountryData() {Year = 2020, Country = "Peru", Percent = 8.6m},
new CountryData() {Year = 2020, Country = "Chile", Percent = 8.6m}
};

public static IEnumerable<CountryData> GetVisits(int year)
=> _data.Where(d => d.Year == year);
}

Vayamos ahora a la página Index.razor, e introduzcamos una serie de datos en la gráfica que ya habíamos insertado allí. Para ello, añadimos en el interior de <SfChart>:

  • Un componente <ChartPrimaryXAxis> para describir el eje X.
  • Un componente <ChartPrimaryYAxis> para describir el eje Y.
  • Y, por último, un <ChartSeriesCollection> para definir las series de datos, en cuyo interior usamos <ChartSeries> para especificar los datos (la fuente de datos y los campos de donde obtener los valores, XName y YName) y la forma en que queremos mostrarlos (Type, en este caso, como gráfica de columnas).
@page "/"
<h1>Hello, Blazor Chart!</h1>

<SfChart>
<ChartPrimaryXAxis Title="Country" ValueType="Syncfusion.Blazor.Charts.ValueType.Category" />
<ChartPrimaryYAxis Title="Percent" ValueType="Syncfusion.Blazor.Charts.ValueType.Double" />
<ChartSeriesCollection>
<ChartSeries DataSource="@visits2020" Type="ChartSeriesType.Column"
XName="Country" YName="Percent" />
</ChartSeriesCollection>
</SfChart>
@code {
IEnumerable<CountryData> visits2020;
protected override void OnInitialized()
{
visits2020 = VisitServices.GetVisits(2020);
}
}

El resultado en tiempo de ejecución es el siguiente. No está mal para unas pocas líneas, ¿eh?

Gráfica simple de columnas

¿O quizás preferiríamos verlo en forma de líneas? Pues basta con modificar en la serie, el componente <ChartSeries>, el tipo de gráfica a ChartSeriesType.Line, y el resultado sería el mostrado justo a continuación:

<ChartSeriesCollection>
<ChartSeries DataSource="@visits2020" Type="ChartSeriesType.Line"
XName="Country" YName="Percent" />
</ChartSeriesCollection>

Gráfica simple de líneas

Bueno, no está quedando mal la cosa, pero aún podemos mejorarlo. Por ejemplo, podemos añadir un título a la gráfica y activarle un tooltip de ayuda

<SfChart Title="variablenotfound.com visits by country">
<ChartTooltipSettings Enable="true" />
...
</SfChart>

Podemos hacer también que se muestren cada uno de los puntos representados, acompañándolos por su valor, lo que conseguiremos introduciendo un objeto <ChartMarker> en la definición de la serie. De paso, modificaremos el color y grosor de la línea, con lo que quedará un resultado más contundente.

<ChartSeries ...>
<ChartMarker Width="10" Height="10" Shape="ChartShape.Circle" Visible="true">
<ChartDataLabel Visible="true" />
</ChartMarker>
</ChartSeries>

El código completo del componente quedaría así, y luciría como en la captura mostrada justo abajo:

<SfChart Title="variablenotfound.com visits by country">
<ChartPrimaryXAxis Title="Country" ValueType="Syncfusion.Blazor.Charts.ValueType.Category" />
<ChartPrimaryYAxis Title="Percent" ValueType="Syncfusion.Blazor.Charts.ValueType.Double" />
<ChartTooltipSettings Enable="true" />
<ChartSeriesCollection>
<ChartSeries Fill="red" Width="3" DataSource="@visits2020"
XName="Country" YName="Percent" Type="ChartSeriesType.Line">
<ChartMarker Width="10" Height="10" Shape="ChartShape.Circle" Visible="true">
<ChartDataLabel Visible="true" />
</ChartMarker>
</ChartSeries>
</ChartSeriesCollection>
</SfChart>

Gráfica de líneas algo más elaborada

¿Y si queremos comparar las visitas de 2020 y 2019 sobre la misma gráfica? Pues sin problema, puesto que, como se puede intuir, <SfChart> permite la visualización de múltiples series al mismo tiempo. Lo único que tendríamos que hacer es cargar otro componente <ChartSeries>, alimentado apropiadamente a través de su atributo DataSource.

Fijaos que en este caso hemos establecido el tipo de cada serie para que los aparezcan en columnas para que luzcan mejor, pero en realidad podrían ser series de distinto tipo; es decir, podríamos mostrar una serie con líneas y otras como columnas, si nos interesara por algún motivo.

@page "/"

<h1>Hello, Blazor Chart!</h1>

<SfChart Title="variablenotfound.com visits by country">
<ChartPrimaryXAxis Title="Country" ValueType="Syncfusion.Blazor.Charts.ValueType.Category" />
<ChartPrimaryYAxis Title="Percent" ValueType="Syncfusion.Blazor.Charts.ValueType.Double" />
<ChartTooltipSettings Enable="true" />
<ChartSeriesCollection>
<ChartSeries Name="2020" Fill="red" Width="3" DataSource="@visits2020"
XName="Country" YName="Percent" Type="ChartSeriesType.Column">
<ChartMarker Width="10" Height="10" Shape="ChartShape.Circle" Visible="true">
<ChartDataLabel Visible="true" />
</ChartMarker>
</ChartSeries>
<ChartSeries Name="2019" Fill="Blue" Width="3" DataSource="@visits2019"
XName="Country" YName="Percent" Type="ChartSeriesType.Column">
<ChartMarker Width="10" Height="10" Shape="ChartShape.Circle" Visible="true">
<ChartDataLabel Visible="true" />
</ChartMarker>
</ChartSeries>
</ChartSeriesCollection>
</SfChart>
@code {
IEnumerable<CountryData> visits2020;
IEnumerable<CountryData> visits2019;
protected override void OnInitialized()
{
visits2020 = VisitServices.GetVisits(2020);
visits2019 = VisitServices.GetVisits(2019);
}
}

Gráfica mostrando dos series numéricas distintas

Aparte de las más de treinta opciones que podemos elegir como valor para el atributo Type de <ChartSeries>, existe un componente adicional que nos permite mostrar datos acumulados en forma de tarta o donut, pirámide o funnel. El componente en cuestión se denomina <SfAccumulationChart>.

Su uso es muy similar al visto anteriormente. En el interior de un componenet <SfAccumulationChart> usamos subcomponentes como <AccumulationChartTooltipSettings> para habilitar el tooltip, o <AccumulationChartSeriesCollection> para definir las series de datos:

<SfAccumulationChart Title="2020 variablenotfound.com visits by country">
<AccumulationChartTooltipSettings Enable="true" />
<AccumulationChartSeriesCollection>
<AccumulationChartSeries DataSource="@visits2020" XName="Country" YName="Percent">
</AccumulationChartSeries>
</AccumulationChartSeriesCollection>
</SfAccumulationChart>

Y el bonito resultado se visualizará, animación mediante, como se muestra en la siguiente captura de pantalla:

Gráfico de tarta mostrando la distribución de visitantes por país

¡Y hasta aquí hemos llegado! Espero que este post os haya sido de utilidad para ver, al menos a alto nivel, el potencial de los componentes de Syncfusion para la creación de gráficas en Blazor, que la verdad es que están bastante bien.

Si os quedáis con dudas sobre si es o no lo que andáis buscando, dedicad unos minutos a echar un vistazo a las demos de la página oficial del producto para ver todas sus posibilidades y poder evaluar si el coste que tiene os compensa. Y también recordad que si encajáis en los requisitos de su licencia community, podréis usarlo de forma gratuita.

Publicado en Variable not found.

Picando Código: Siete días en el Picandoverso – 4ta semana de Junio 2021 – 14 años después

$
0
0

Pasen, pónganse cómodos y cómodas y sírvanse una taza de su brebaje de preferencia que esta semana estamos de festejo. Esta edición de siete días en el Picandoverso empieza referenciando el Big Bang, la precuela a esta saga de posts, el inicio del universo Picando Código:

Siete días en el Picandoverso - 4ta semana de Junio 2021 - 14 años después

Picando Código

El 21 de junio se cumplieron 14 años desde que un joven Fernando empezaba a publicar posts sobre programación, software libre y más en un nuevo proyecto web. No sé si me hubiera imaginado que 14 años después este proyecto iba a seguir por acá*, pero esta semana lo festejamos. Iba a escribir un post aparte al respecto, pero creo que bastante autoreferencial vengo con estos posts de 7 días y otros. Así que lo festejamos así. Catorce años es bastante tiempo, me asombro a mí mismo de haber mantenido este blog como constante a pesar de habiendo vivido tantos cambios, reboots y remakes a lo largo de esta etapa.

* El concepto de “acá” es relativo, el primer hosting del blog estuvo en Blogger, seguido de Linux Uruguay y finalmente me conseguí un servidor propio. Aunque creo que todo pasó en los primeros meses de vida del blog. Y de todas formas el “espacio virtual” que me imagino es este blog sigue siendo el mismo, se hostee donde se hostee…

El año que viene se cumplen 15 años del blog, vamos a tener que hacerle una fiesta como es tradicional. O sorteo, o alguna otra cosa que logre de alguna forma generar más interacción o comunidad. Se aceptan sugerencias.

Ruby

💎Julie Jones, desarrolladora autodidacta, viene publicando en Twitter varios piques de Ruby bajo la premisa de 100 Days Of Code. Lleva publicados 30 días, y entre sus tweets podemos encontrar piques bastante buenos sobre bloques, Procs, y varias cosas más de Ruby. Podemos ver los tweets en este enlace y seguirla en Twitter en @codewithjulie.

💎 Nat Friedman, CEO de GitHub, twiteó que GitHub procesa 2.8 miles de millones de pedidos a su API por día, con un pico de 55.000 pedidos por segundo. La aplicación es un monolito Rails, confirmado por Raffaele Di Fazio (del equipo de plataforma de GitHub) con la biblioteca Ruby resque para procesos en segundo plano. También hacen deploy a producción entre 20 y 30 veces por día. Son datos bastante interesantes y confirman lo que ya sabemos: Ni Ruby ni Rails están muertos, y Rails sí puede escalar…

💎Una discusión en reddit plantea que “Ruby y Rails no habían tenido nada como Shopify hasta ahora” en lo que se refiere a soporte empresarial. Si bien tienen equipos dedicados tanto a Ruby como a Rails, otras empresas como GitHub, Stripe y Heroku (que le paga el sueldo al mismísimo Matz) también vienen dándole mucho soporte a Ruby. Pero lo interesante es que en el hilo de Reddit comentaron Peter Zhu (Ruby committer que trabaja en Shopify) y Richard Schneeman (contribuye a Rails, mantiene Puma y Sprockets, trabaja en Heroku) entre otros. Del lado de Shopify, Peter Zhu comenta que los proyectos Ruby principales en Shopify actualmente son: YJIT (más información por acá) y Variable Width Allocation (VWA) para MRI y TruffleRuby, una implementación alternativa de Ruby. También comenta que han colaborado directamente con GitHub tanto en Ruby como en Rails. Si bien es difícil medir el aporte de cada empresa, lo importante es que muchas empresas están trabajando y colaborando para hacer Ruby mejor, lo cual le asegura un futuro interesante y sano a mi lenguaje de programación favorito.

💎 De este último hilo también un artículo interesante: Peter Zhu publicó un artículo sobre Garbage Collection en Ruby, además de tener varios artículos interesantes más sobre Ruby en su blog.

💎 Y cuanto más compiladores JIT tengamos mejor (?). Hace tiempo Chris Seaton programó uno para Ruby, hecho en Ruby. Nunca se motivó para terminarlo, pero decidió liberarloen GitHub. Sirve como material didáctico, en el README del proyecto mismo dice “Se supone que lo leas, no que lo uses”. Tiene varios experimentos y documentos, así que nos puede ayudar a entender cómo funciona un JIT y aprender más de Ruby y el compilador.

💎Textbringer es nada más y nada menos que un editor de texto inspirado en Emacs, escrito en Ruby. Dos de las mejores cosas del mundo combinadas: Emacs y Ruby 🙇

💎 Mañana es el último jueves del mes, y hay meetup de Ruby Galaxy. Van a hablar Ramón Huidobro y Megan Tiu. En Twitter lo publican como: “MINASWAN” (Matt is nice and so we are nice – Matz es bueno así que somos buenos) ha sido parte de la comunidad Ruby desde su fundación, y una de las cosas más lindas que puedes hacer es entrenar y mentorear a alguien. Este jueves a las 19:00 UTC vamos a estar hablando con dos expertos en entrenamiento y amabilidad. Como siempre, se transmite a través de Twitch.

Programación/Tecnología

🗣NotPinkCon es una conferencia de seguridad informática impartida por mujeres y realizada anualmente en la Ciudad de Buenos Aires, Argentina. El evento posee un enfoque técnico y la entrada es libre y gratuita para todas las personas que deseen formar parte. Abrieron su llamado a charlas para la cuarta edición de la conferencia, que va a realizarse online el sábado 25 de setiembre.

👔 Graham King escribió un artículo (sátira) sobre un día en la vida de un ingeniero de software profesional: “Si eres estudiante en entrevista para un trabajo en software y preguntándote cómo es un día típico, acá van algunas notas de lo que hice el martes pasado. Fue un día bastante típico”. El artículo sigue contando tareas ridículas como dar vuelta una lista enlazada porque el turno de la noche la había puesto al revés. Por suerte tenía un pizarrón a mano para resolver el problema. Sigue burlándose de otras tantas pruebas inútiles que nos hacen en las entrevistas de trabajo. No me acuerdo dónde vi el enlace, pero el artículo es de Diciembre de 2020.

🐳 En el sitio FAQForge se publica una referencia de comandos Docker que puede venir a mano para recordar comandos.

📚 Humble Bundle tiene un paquete de ebooks de Data Science y Data Analytics (o Ciencia de Datos y Analítica de Datos). El paquete de Mercury Publishing incluye libros como Big Data Using Hadoop and Hive, Natural Language Processing and Machine Learning for Developers, Python 3 for Machine Learning, Artificial Intelligence, Machine Learning and Deep Learning y muchos más. Nuestro aporte apoya a las caridades Girls Who Code y Whale & Dolphin Conservation. Visita el paquete.

📚 Otro paquete de Humble Bundle interesante: Advanced AI de Morgan & Claypool. Incluye libros como Deep Learning Systems, Efficient Processing of Deep Neural Networks, Introduction to Graph Neural Networks, Introduction to Logic Programming y más. Nuestro aporte ayuda a la caridad “It Gets Better Project”, cuya misión es comunicar a la juventud lesbiana, gay, bisexual y transgénero alrededor del mundo que las cosas se ponen mejor, y crear e inspirar los cambios necesarios para mejorar las cosas. Visita el paquete.

Café

☕En Slashdot publican que un estudio sugiere que tomar café puede reducir el riesgo de enfermedad crónica del hígado. Me alegra esta noticia, cuanto más lo estudian, más se demuestra que el café es lo mejor 🙌🏻. Asumo que en mi organismo la alta cantidad de café consumido contrarresta el daño al hígado generado por la alta cantidad de alcohol consumida…

Cómics

💬 Esta semana empieza Gamma Flight, la serie escrita por Al Ewing salida de las páginas de Immortal Hulk. También voy a recibir el primer número del segundo volúmen de Norse Mythology, el cómic de Dark Horse basado en el libro Norse Mythology de Neil Gaiman que se atrasó la semana pasada, y algunos títulos más. Una noticia interesante es que ya se anunció que la serie actual de Amazing Spider-Man por Nick Spencer termina en Setiembre con un número 74 (875 en la numeración original) final gigante. No he sido muy fan del escrito en esta serie, y si bien tuvo números buenos, estoy ansioso de ver quién va a seguir con el título después de Spencer. ¡Mi escritor ideal sería Chip Zdarsky!

Y hasta acá llegamos a la vigesimosegunda semana contínua de esta saga de posts. Espero lo hayas disfrutado leer al menos tanto como yo disfruté escribiéndolo.

Otros Siete días en el Picandoverso:

Los posts de Picando Código pueden seguirse por:

También estoy en Twitter y Mastodon, donde además de compartir lo que se publica en el blog publico alguna cosa más.

El post Siete días en el Picandoverso – 4ta semana de Junio 2021 – 14 años después fue publicado originalmente en Picando Código.

Blog Bitix: Hemeroteca #19

$
0
0

Blog Bitix

Ya son casi 600 artículos los que he escrito en el blog, con este número de artículos en alguna ocasión al escribir un nuevo artículo a veces tengo que mirar si ya he escrito sobre ello o algo muy similar para no escribir lo mismo con otras palabras. Estos últimos meses muchas semanas solo he escrito un artículo en vez de dos, un poco por no dedicar tanto tiempo al blog pero más por falta de ideas que no me requieran mucho tiempo de investigación, ideas sobre cosas que me gustaría aprender y compartir tengo pero algunas de ellas para poder escribir me requerirían primero una buena cantidad de tiempo de investigación. Y algunos de esos temas sobre los que me gustaría aprender más son cosas muy específicas ni demasiado populares con lo que para el objetivo de seguir haciendo que el blog tenga más visitas no son los más adecuados.

El trabajo de meses anteriores en los que escrito artículos con ese objetivo de hacer que el blog tenga más visitas se está notando ahora, este marzo ha sido el mejor mes en cuanto a visitas del blog hasta el momento, algunos artículos se han posicionado bien y son artículos sobre los que se hacen muchas búsquedas, ambas cosas combinadas hace que esos artículos contribuyan a aumentar el número de visitas. Haber estado publicando dos artículos durante buena parte del 2020 se ve recompensado ahora. Estos meses han sido el mejor registro de visitas y de ingresos en un mes de época no navideña, los meses de octubre, noviembre y diciembre. Los meses vacacionales siempre suelen bajar algo las visitas con lo que hasta septiembre la métrica de las visitas solo es comparable con los mismos meses de años anteriores.

Los ingresos por publicidad de AdSense se han recuperado también e incluso superado comparado con los primeros meses de pandemia llegando a casi un 1 € diario lo que al final de mes llega a algo más de 30 € de forma holgada. Comparado con los 3 primeros años de vida del blog que no llegaba a los 5 € al mes es un aumento significativo, aún así seguro que es una cifra baja comparada con otros sitios. En el caso de mi blog en gran medida los ingresos dependen de AdSense y esto depende del número de visitas.

Una cosas que me sorprende es que no son pocos los correos electrónicos que recibo con la intención de preguntar, querer insertar enlaces patrocinados en algún artículo o publicar un artículo ya redactado. Aunque no todos llegan a materializarse, también es otra forma de ingreso, aunque más esporádica e irregular que AdSense que continúa siendo la forma principal de ingresos. Sin embargo, alguno ya he rechazado también directamente, si el artículo patrocinado trata sobre apuestas o juegos azar son temas que tengo en mi lista de rechazados por el tema controvertido en sí y porque no están relacionados con los temas principales del blog. Aún así quizá en la siguiente solicitud de estos temas tantee a ver cuánto están dispuestos a ofrecer.

No solo ha sido escribir nuevos artículos, también he realizado algunas pequeñas mejoras en el blog para mantenerlo actualizado. Para cargar las imágenes bajo demanda usaba la librería lozad, lo he cambiado para usar la forma estandarizada que ofrece HTML con el atributo loading=“lazy”. He actualizado las librerías con las que está construido el blog, principalmente Bootstrap para los estilos y jQuery para cierta lógica pasando a las versiones 5 y 3.6. También he realizado mejoras en la accesibilidad, alguna corrección de errores de los que informa Google Console como content layout shift. He añadido una nota informativa a los artículos en aquellos que tienen enlaces de afiliación para informar del hecho.

Como ya comenté en hemerotecas anteriores tengo pendiente comprar un dominio propio y migrar a un hosting distinto de GitHub Pages. En caso de tener que migrar ya tengo más o menos analizado cual sería la opción, en este momento me decantaría por un servidor cloud en Linode con Nginx más Cloudflare como CDN. Esta infraestructura me permitiría aprender algunas cosas de administración de servidores, Ansible, Terraform y Lets Encrypt, quizá algo más. Pero de momento no he llegado al límite de GitHub Pages ni he recibido ninguna notificación de que deba cambiar, aún no tengo ninguna necesidad de cambiar con lo que quizá siga en GitHub Pages hasta que me lo notifiquen.

También he seguido haciendo algunas mejoras en el script de instalación de Arch Linux. A petición de un usuario que quería soporte para el entorno de escritorio Deepin y como no es mucho esfuerzo añadir un nuevo escritorio lo he añadido. Ahora es posible configurar los módulos de mkinitcipio. Con la versión 6.0.0 del gestor de paquetes pacman de Arch Linux se le ha añadido el soporte para la descarga en paralelo de paquetes, alis ya lo soporta. Añadido paru como utilidad para los paquetes de AUR. También algunas corrección de errores y typos.

Esta es la lista de los artículos que he publicado durante los seis primeros meses del 2021.

Artículos sobre Java y programación.

Artículos sobre juegos.

Artículos sobre GNU/Linux o software libre.

Otros.

Picando Código: Semantic Logger – framework de logueo enriquecido para Ruby y Rails

$
0
0

Semantic Logger es un framework enriquecido de logueo que permite producir resultados legibles para humanos y para máquinas 🤖
Entre las características principales listan:

  • Archivos de log con texto coloreado para que los humanos lo podamos leer.
  • Archivos de log JSON con toda la información semántica para alimentar a las máquinas.
  • Escribir a múltiples destinos a la misma vez
  • Enviar los logs a un sistema centralizado de logueo, via JSON o adaptadores incluidos.

Como implementa la interfaz estándar de logueo de Ruby, se puede reemplazar el log normal con Semantic Logging. Lo probé con el cliente oficial de Elasticsearch para ver qué tal, sólo hay que pasarlo como parámetro al inicializador:

require 'elasticsearch'
require 'semantic_logger'

SemanticLogger.default_level = :debug
SemanticLogger.add_appender(file_name: 'desarrollo.log', formatter: :color)
logger = SemanticLogger['elasticsearch-ruby'] #nombre de la aplicación
client = Elasticsearch::Client.new(logger: logger)
client.cluster.health

El archivo desarrollo.log generado por la biblioteca se muestra con colores en la terminal al leerlo con cat.

Tiene también un Appender para Elasticsearch (que usar el cliente oficial Ruby Elasticsearch), lo que nos permite redirigir los logs directamente a Elasticsearch a un índice del formato “nombre-fecha” (por defecto "semantic_logger-"%Y.%m.%d""). Podemos especificar el nombre del índice, formato de fecha y más.

SemanticLogger.add_appender(
  appender: :elasticsearch,
  url: 'http://localhost:9200',
  index: 'desarrollo-ruby'
)
logger = SemanticLogger['desarrollo-ruby']
logger.info('¡Hola Mundo!')

Con esto, podría usar el logger para una aplicación que usa el cliente Elasticsearch y redirigir los logs del cliente Elasticsearch a un clúster Elasticsearch a través del adaptador Elasticsearch que usa el cliente Elasticsearch y leer los logs con el cliente Ruby de Elasticsearch…

Yo dawg I heard you like Elasticsearch logging

Hay muchas cosas más para aprender de Semantic Logging, lo podemos hacer en su sitio web, o visitar el código fuente en GitHub.

El post Semantic Logger – framework de logueo enriquecido para Ruby y Rails fue publicado originalmente en Picando Código.

Variable not found: Enlaces interesantes 450

$
0
0
Enlaces interesantes

Ahí van los enlaces recopilados durante la semana pasada. Espero que os resulten interesantes. :-)

Por si te lo perdiste...

.NET Core / .NET

ASP.NET Core / ASP.NET / Blazor

Azure / Cloud

Conceptos / Patrones / Buenas prácticas / Arquitectura

Data

Machine learning / IA / Bots

Web / HTML / CSS / Javascript

Visual Studio / Complementos / Herramientas

Xamarin / Mobile

Otros

Publicado en Variable not found.

Picando Código: Mini-Pique: Bashrc PS1 generator – genera el código para tu prompt bash con una interfaz drag & drop

$
0
0

El sitio web basrchgenerator nos ofrece una interfaz gráfica amigable para crear el código para nuestro prompt de Bash de manera bastante sencilla:

bash rc generator

http://bashrcgenerator.com/

Arrastramos los elementos de la izquierda al espacio del medio, y a la derecha vemos un preview y el código generado. Una vez generado, lo copiamos y lo pegamos en el archivo .bashrc en nuestro directorio home, y listo. Una herramienta bastante práctica, faltaría poder elegir colores para los distintos elementos y estaría súper completa.

El post Mini-Pique: Bashrc PS1 generator – genera el código para tu prompt bash con una interfaz drag & drop fue publicado originalmente en Picando Código.

Variable not found: Expresiones new con el tipo de destino en C# 9

$
0
0
.NET Core

Me encanta que el lenguaje C# vaya introduciendo características que consiguen que cada vez tengamos que escribir menos para conseguir lo mismo, y, sobre todo, si la legibilidad posterior del código no se ve comprometida.

Uno de estos casos son los recientes target-typed new expressions, o expresiones new con el tipo del destino, que básicamente permite evitar la introducción del tipo de datos al usar el constructor de una clase, siempre que el compilador sea capaz de inferirlo por su contexto.

Vamos a echarle un vistazo en este post.

Redundancy.... redundancy everywhere...

Redundancia... redundancia por todas partes...

En las primeras versiones de C# era obligatorio indicar el tipo de las variables al declararlas, incluso cuando las inicializábamos directamente. Antes de C# 3.0, teníamos que usar instrucciones como las siguientes para asignar nuevas instancias a variables en el interior de un bloque de código:

Invoice invoice = new Invoice(123);
Dictionary<string, Person> people = new Dictionary<string, Person>();

Está claro que en las asignaciones del bloque anterior hay mucha redundancia: si ya sabemos que la variable invoice es de tipo Invoice o que people es un diccionario porque estamos usando su constructor, ¿para qué es necesario indicar el tipo de las variables?

Esto se solucionó en 2007 con la llegada de C# 3, que entre otras muchas maravillas, introdujo las variables locales de tipado implícito. Esto nos permitió aprovechar la inferencia de tipos para simplificar el código sin restar legibilidad:

var invoice = new Invoice(123);
var people = new Dictionary<string, Person>();

Sin embargo, aún quedaban escenarios similares por mejorar, por ejemplo en la declaración de campos o propiedades de una clase, donde también encontramos tradicionalmente mucha redundancia:

public class MyClass
{
private Invoice invoice = new Invoice(123);
private Dictionary<string, Person> people = new Dictionary<string, Person>();
...
}

Pues hemos tenido que esperar hasta C# 9 para ver simplificadas estas construcciones, y alguna más que veremos a continuación.

¡Bienvenidas, target-typed new expressions!

Las target-typed new expressions permiten obviar el nombre de la clase al usar su constructor, siempre que el compilador pueda inferir de forma inequívoca el tipo de que se trata. Así pues, podemos escribir el código como el siguiente:

public class MyClass
{
private Invoice invoice = new (123);
private Dictionary<string, Person> people = new ();
...
}

Como podéis ver, bastaría con utilizar la palabra reservada new() y, en su caso, los parámetros del constructor. No hace falta repetir el tipo de dato, ya que está claramente identificado en la definición del campo, por lo que el resultado es un código menor verboso y, por tanto, más legible.

Por supuesto, esto sería aplicable también a variables locales, por lo que tendríamos ya tres fórmulas distintas para realizar asignaciones a nuevas instancias:

Invoice invoice = new Invoice(123); // C# < 3
var invoice = new Invoice(123); // C# < 9
Invoice invoice = new (123); // C# >= 9

Además de en la declaración de variables o campos, esta capacidad de omitir el tipo de datos al usar el constructor puede utilizarse en todas aquellas expresiones en las que tenga sentido instanciar objetos, como en la invocación de métodos:

// Antes: DoSomething(new Person("Pedro"));
DoSomething(new ("Pedro")); // Ok, el compilador inferir el tipo Person
...
public void DoSomething(Person person) { ... }

Fijaos que el ejemplo anterior es un uso posible de esta nueva característica, aunque, en esta ocasión, viendo la llamada a DoSomething(new ("Pedro")) no podemos intuir de qué tipo de objeto se trata simplemente viendo su constructor. En este caso creo sería más conveniente usar el constructor de forma tradicional.

También podemos usarlo en expresiones throw como la siguiente, donde se asumirá que estamos instanciando un objeto Exception:

throw new("Cachis!");

O cuando aprovechemos la instanciación para inicializar propiedades:

Invoice inv = new() { Id = 1, CustomerId=99, Amount=1000 };
Dictionary<string, Person> people = new()
{
["1234"] = new("Pedro"),
["5678"] = new("Juan"),
};

En cambio, no será posible su uso en otros escenarios como los siguientes, aunque los motivos son bastante razonables:

dynamic d = new();                // new dynamic() tampoco está permitido
string[] = new(); // ¿Con qué tamaño se inicializaría?
var x = new { Property = new() }; // No se puede inferir el tipo

En definitiva, como podéis ver, se trata de una interesante característica que utilizada apropiadamente puede aumentar la legibilidad de nuestro código y ahorrarnos muchas pulsaciones de tecla que, como bien nos recuerda a menudo Scott Hanselman, son limitadas ;)

Publicado en Variable not found.

Viewing all 2698 articles
Browse latest View live