Weblogs Código

Variable not found

Ver el código fuente generado por source generators

abril 13, 2021 06:05

.NET Core

A raíz de los posts sobre generadores de código (como éste y éste), un amigo del blog me escribió para ver si de alguna forma era posible examinar el código fuente generado para poder depurarlo con mayor facilidad.

Y en efecto, es posible. Pero en vez de responderle directamente, he pensado que sería mejor compartirlo por aquí, de forma que pueda resultar de utilidad para alguien más :)

Por defecto, los archivos añadidos al proyecto por los generadores no llegan a tocar tierra, pues se gestionan directamente en memoria. Sin embargo, podemos forzar su escritura a disco, basta con añadir la siguiente sección al archivo .csproj del proyecto consumidor del generador:

<PropertyGroup>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<CompilerGeneratedFilesOutputPath>$(BaseIntermediateOutputPath)\GeneratedFiles</CompilerGeneratedFilesOutputPath>
</PropertyGroup>

Según esta configuración, los archivos generados serán depositados en la carpeta /obj/GeneratedFiles del proyecto. En esa carpeta, a su vez, encontraremos una carpeta por cada ensamblado generador incluido en el proyecto y, dentro de ésta otra subcarpeta específica para cada generador.

Espero que os sea de utilidad :)

» Leer más, comentarios, etc...

Variable not found

Enlaces interesantes 439

abril 12, 2021 06:05

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

Data

Machine learning / IA / Bots

Web / HTML / CSS / Javascript

Visual Studio / Complementos / Herramientas

Xamarin

Otros

Publicado en Variable not found.

» Leer más, comentarios, etc...

Blog Bitix

Las clases y librerías básicas de Java para bases de datos relacionales

abril 09, 2021 05:00

Las aplicaciones suelen delegar el guardado del estado y de los datos que tratan en sistemas especializados en almacenar datos. Las bases de datos relacionales son sistemas que han probado su eficacia y utilizad durante las últimas décadas de la computación. Aún con la aparición de múltiples bases de datos NoSQL alternativas las bases de datos relacionales se seguirán utilizando o incluso combinando diferentes tipos de bases de datos en un mismo sistema. Java proporciona desde sus primeras versiones el paquete java.sql con varias clases para el acceso a bases de datos relacionales, aunque el acceso a las bases de datos relacionales se suele utilizar a través de librerías es útil conocer estas clases de Java que constituyen los conceptos fundamentales de acceso a base de datos y que las librerías internamente son las que usan.

Java

La mayoría de las aplicaciones usan una base de datos para guardar persistir, consultar datos o guardar el estado de la aplicación. Las bases de datos son los sistemas especializados en guardar la información de las aplicaciones.

Dentro de la categoría de bases de datos las relacionales son unas de las más utilizadas por sus propiedades ACID y el potente lenguaje de consultas SQL. Las bases de datos relacionales siguen siendo adecuadas para muchos usos y propósitos aún con la aparición de las bases de datos NoSQL también útiles cuando existe ciertos requerimientos.

Contenido del artículo

Clases del JDK para acceso a base de datos relacionales

Java ofrece soporte para las bases de datos relacionales desde prácticamente las primeras versiones del JDK hasta día de hoy incorporando un conjunto de clases en el paquete java.sql en la denominada API en Java de Java Database Connectivity o JDBC.

Las principales clases de la API de JDBC son las clases Statement y PreparedStatement que representan la sentencia SQL ya sea de inserción, actualización, eliminación o consulta así como las sentencias DDL para la creación de tablas, índices, campos o procedimientos almacenados. Normalmente se utiliza la clase PreparedStatement ya que tiene beneficios en cuanto a rendimiento al ejecutarse de forma repetida y utilizada correctamente permite evitar el grave problema de seguridad de SQL injection común en las aplicaciones que construyen de forma dinámica con concatenaciones sentencias SQL utilizando datos procedentes de fuentes no confiables como parámetros de una petición HTTP, de JSON u otras fuentes externas a la aplicación.

La clase ResultSet es la clase que proporciona el acceso a los datos cuando se ejecuta una sentencia SQL de consulta, la clase se itera en los resultados y se obtienen los datos según los nombres o índices asignados en la consulta para las columnas.

La clase Connection representa una conexión a una base de datos, hay que crear una conexión ya que las bases de datos trabajan con una arquitectura de cliente y servidor, la aplicación actúa de cliente y la base de datos actúa de servidor. A través de la clase Connection se inicia una transacción y finaliza con el commit o el rollback. Para crear la conexión de la base de datos se proporcionan las credenciales de usuario y contraseña.

Las bases de datos relacionales soportan transacciones para proporcionar las propiedades ACID para lo que se utilizan las transacciones. Atomicidad donde un grupo de operaciones individuales se ejecutan todas o ninguna, consistencia mediante la cual los cambios son válidos según las reglas incluyendo restricciones, cambios en cascada, y disparadores, aislamiento donde los cambios de una transacción no se ven afectados por los cambios realizados en otras transacciones concurrentes y finalmente durabilidad que garantiza que en caso de completarse la transacción perdura en el tiempo aún cuando el sistema sufra un fallo posterior.

Crear una conexión a una base de datos es costoso, para evitar incurrir en este tiempo de creación y destrucción de conexiones o limitar el número de conexiones que una aplicación utiliza como máximo las aplicaciones utilizan un pool de conexiones. Las conexiones se crean al iniciar la aplicación o bajo demanda según se van necesitando más hasta el límite máximo definido. Cuando la aplicación necesita una conexión la obtiene de forma rápida del pool de conexiones y cuando termina de utilizarla la devuelve al pool de conexiones para que sea reutilizada en posteriores usos.

Cada base de datos utiliza un protocolo diferente de comunicación con los clientes por lo que es necesario un componente que abstrae de las peculiaridades de cada base de datos y proporcione un marco común de trabajo independiente de cada base de datos. Cada base de datos requiere de un Driver compatible también con la versión de la base de datos. Generalmente, son los desarrolladores de la propia base de datos los que proporcionan un driver específico adecuado para el acceso a la base de datos desde Java que cumple con las APIs de JDBC.

En el tutorial sobre SQL con Java se explican los conceptos básicos y fundamentales para usar bases de datos relacionales.

Ejemplo de conexión y consulta a un base de datos relacional con la API de Java

En este ejemplo de código se muestra el uso de las clases fundamentales de Java para usar una base de datos relacional. El primer paso es establecer una conexión con la base de datos, en este caso usando la base de datos H2 en memoria.

Posteriormente se ejecuta una sentencia DDL para crear una tabla, se insertan varias filas con la sentencia insert y se obtienen los datos de la tabla con una sentencia select. Después de las inserciones se realiza un commit que completa una transacción en la base de datos, si en vez del commit se hiciese un rollback al obtener los datos con la consulta posterior la tabla aparecería vacía.

Las clases Connection, Statemente, PreparedStatement y ResultSet al finalizar su uso hay que invocar su método close para liberar los recursos que tienen reservados, especialmente en el caso de las conexiones ya que son un recurso limitado. Estas clases implementan la interfaz AutoCloseable con lo que son adecuadas para las sentencias try-with-resources de Java.

Establecer la conexión a la base de datos

Por defecto después de cada sentencia Java emite un commit, esto no es lo deseado en el caso de querer agrupar la ejecución de varias sentencias en una transacción, para evitarlo hay que usar la opción setAutoCommit a false.

 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
package io.github.picodotdev.blgbitix.javasql;

import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.text.DecimalFormat;
import java.util.Locale;

public class Main {

    public static void main(String[] args) {
        DriverManager.drivers().forEach(d -> {
            System.out.printf("Driver: %s%n", d.getClass().getName());
        });

        try (Connection connection = DriverManager.getConnection("jdbc:h2:mem:database", "sa", "")) {
            connection.setAutoCommit(false);

            ...
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
Main-1.java

Ejecutar una sentencia con Statement

1
2
Statement statement = connection.createStatement();
statement.execute("CREATE TABLE product(id INT IDENTITY NOT NULL PRIMARY KEY, name VARCHAR(255), price DECIMAL(20, 2))");
Main-2.java

Ejecutar una sentencia con PreparedStatement

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO product (name, price) values (?, ?)", new String[] { "id" });

preparedStatement.setString(1, "PlayStation 5");
preparedStatement.setBigDecimal(2, new BigDecimal("499.99"));
preparedStatement.executeUpdate();

ResultSet resultSet1 = preparedStatement.getGeneratedKeys();
while (resultSet1.next()) {
    System.out.printf("Primary key: %s%n", resultSet1.getLong(1));
}
resultSet1.close();

preparedStatement.setString(1, "Xbox Series X");
preparedStatement.setBigDecimal(2, new BigDecimal("499.99"));
preparedStatement.executeUpdate();

ResultSet resultSet2 = preparedStatement.getGeneratedKeys();
while (resultSet2.next()) {
    System.out.printf("Primary key: %s%n", resultSet2.getLong(1));
}
resultSet2.close();

connection.commit();
Main-3.java

Ejecutar una consulta

1
2
3
4
5
6
7
PreparedStatement preparedStatement = connection.prepareStatement("SELECT id, name, price FROM product");

ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
    System.out.printf("Product (id: %s, name: %s, price: %s)%n", resultSet.getLong(1), resultSet.getString(2), DecimalFormat.getCurrencyInstance(new Locale("es", "ES")).format(resultSet.getBigDecimal(3)));
}
resultSet.close();
Main-4.java

Cerrar la conexión de forma explícita

1
2
connection.close();

Main-5.java

Resultado

El resultado del programa en la terminal es el siguiente.

1
2
3
4
5
Driver: org.h2.Driver
Primary key: 1
Primary key: 2
Product (id: 1, name: PlayStation 5, price: 499,99 €)
Product (id: 2, name: Xbox Series X, price: 499,99 €)
System.out

Dependencia con el driver de la base de datos

En el archivo de construcción hay quu añadir la dependencia que contiene el driver para la base de datos a conectarse.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
plugins {
    id 'application'
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'com.h2database:h2:1.4.200'
}

application {
    mainClass = 'io.github.picodotdev.blgbitix.javasql.Main'
}
build.gradle

El problema de seguridad de SQL injection

El problema de seguridad de SQL injection es un grave problema de seguridad que afecta a las aplicaciones que construyen sentencias de forma dinámica a partir de datos provenientes de origen no confiable. Un origen no confiable es cualquier dato proveniente de forma externa a la aplicación, en el caso de las aplicaciones web o servicios REST es un parámetro de la petición o un dato de un JSON.

El SQL injection es un grave problema de seguridad ya que permite al atacante tener acceso a datos de la base de datos, obtener acceso con una cuenta de otro usuario o realizar operaciones sobre los datos de forma no autorizada. El problema se produce en la construcción de forma dinámica de la sentencia SQL mediante la concatenación de cadenas y datos de origen no confiable.

Las siguientes sentencias SQL sufren del problema de SQL injection, en la primera un atacante puede obtener un dato de cualquier columna de la tabla y con la segunda ejecutar una sentencia en este caso para eliminar todas las filas de cualquier tabla.

En la primera cambiando el valor de column se obtiene el dato de cualquier columna de la tabla, por ejemplo el campo password.

1
2
3
"SELECT id, " + column + " FROM users WHERE user_id = " + userId

"SELECT id, password FROM users WHERE user_id = 1
sql-injection-1.sql

En esta sentencia se finaliza la sentencia original con ; y se inicia otra lo que provoca la eliminación de una tabla, con un valor para user_id especialmente construido para ejecutar la sentencia maliciosa de eliminación de la tabla.

1
2
3
"SELECT * FROM users WHERE user_id = " + userId

"SELECT * FROM users WHERE user_id = 105; DROP TABLE users;"
sql-injection-2.sql

La solución al problema de seguridad de SQL injection en Java es no construir la sentencia de forma dinámica mediante concatenación de cadenas utilizando la clase PreparedStatement con argumentos para los datos que se inserten en la sentencia SQL.

1
2
3
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM users WHERE user_id = ?"});
preparedStatement.setInt(1, 1);
preparedStatement.executeUpdate();
sql-injection-prepared-statement.java

Librerías de persistencia en Java

Habitualmente no se utilizan directamente las clases de la API de Java sino que se utilizan otras librerías de más alto nivel. Una de las más conocidas es Hibernate, es un ORM que proporciona acceso a los datos con una correspondencia entre el modelo relacional de las bases de datos y el modelo de objetos de Java. La aplicación trabaja con objetos y relaciones entre los objetos e Hibernate se encarga de transformar esos objetos en el modelo relacional de la base de datos, la aplicación no ejecuta sentencias SQL de forma directa sino que es Hibernate el encargado de emitir las sentencias adecuadas según los cambios realizados en los datos. Es la implementación más utilizada de ORM en Java para la especificación JPA.

Spring Data es una capa de abstracción para el acceso a datos ya sean de un modelo relacional, de bases de datos NoSQL o algunos otros sistemas de datos. Spring Data hace más sencillo el acceso a los datos utilizando de forma subyacente JDBC o JPA. Spring Data proporciona algunas clases e interfaces que la aplicación implementa.

jOOQ también es otra librería de acceso a bases de datos relacionales, proporciona DSL para la construcción de sentencias SQL mediante un API Java. A diferencia de JPA con su lenguaje JPQL, jOOQ soporta características avanzadas del lenguaje SQL como windows functions. Otra ventaja de jOOQ es que al utilizar su DSL el compilador de Java realiza validación de tipos y comprobaciones en la sintaxis de la construcción de la SQL.

Algunas aplicaciones combinan el uso de varias de estas librerías en la misma aplicación según el caso, por ejemplo utilizando Hibernate para el modelo de escritura y jOOQ o Spring Data para el modelo de lectura. También es posible utilizar jOOQ para generar las sentencias SQL y posteriormente ejecutarlas con Hibernate o Spring Data.

Liquibase es otra librería de utilidad que permite lanzar scripts de migración con sentencias SQL para realizar cambios en la base de datos como modificar el esquema de tablas, insertar, actualizar o eliminar datos. Es necesario si los cambios en el código en una nueva versión de la aplicación requiere cambios en el esquema de la base de datos.

Estas no son las únicas librerías existentes pero sí son de las más conocidas y utilizadas.

Hibernate Spring jOOQ

Bases de datos relacionales

Las bases de datos de software libre más utilizadas son PostgreSQL, MariaDB y MySQL que rivalizan con la base de datos Oracle comercial. PostgreSQL es adecuada incluso para organizaciones y proyectos de gran tamaño.

Otras bases de datos relevantes son H2 una base de datos implementada en Java con características avanzadas que es posible utilizar para los teses de integración al no requerir de un servidor y ser posible ejecutarla en memoria. Para realizar las pruebas de integración utilizando la misma base de datos que en producción es posible utilizar Testcontainers que utiliza Docker para iniciar una instancia de la base de datos en un contenedor.

La conexión a la base de datos por seguridad requiere de un usuario y contraseña que la aplicación ha de conocer, para aún mayor seguridad es posible generar las credenciales de conexión a la base de datos de forma dinámica por Vault en una aplicación de Spring.

PostgreSQL MariaDB MySQL

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

» Leer más, comentarios, etc...

Picando Código

Anunciado DLC y un parche con contenido nuevo para Streets Of Rage 4: Mr. X Nightmare

abril 09, 2021 10:00

Dotemu, Guard Crash y Lizard Cube, los desarrolladores del excelente juego beat’em up Streets of Rage 4, anunciaron que este año vamos a tener contenido nuevo para el juego.

YouTube Video

Parte del contenido va a estar disponible como DLC pago e incluye:

  • Nuevo modo de juego “Survival” con desafíos semanales.
  • Movimientos, armas (¡un pez espada!) y enemigos nuevos. Los movimientos mostrados en el video se ven bastante poderosos.
  • Personalización de personajes, los nuevos movimientos nos van a permitir definir el estilo de lucha de los personajes.
  • 3 Personajes nuevos – Al final del trailer muestran 3 siluetas, y los personajes van a estar disponibles para jugar en modo campaña. El primer personaje revelado es Estel Aguirre, una jefa de final de pantalla en la historia principal. Va a estar interesante poder jugar con Estel, le han agregado varios movimientos y la conversión de jefe a personaje jugable debe ser bastante compleja.
  • Música nueva por Tee Lopes (Sonic Mania, Team Sonic Racing, Monster Boy y más).

El DLC va a venir acompañado de un parche con algunas actualizaciones gratuitas para quienes ya poseemos el juego:

  • Nuevas paletas de colores para los personajes.
  • Nuevos modos de juego: entrenamiento y tutoriales.
  • Nueva dificultad “Mania+” (¡paso! 😆)
  • Mejoras del gameplay. No dieron demasiada información respecto a estos cambios, más que arreglos en la dificultad en el último nivel, pero me intriga mucho saber qué más cambiaron…

No está claro si es en el DLC o el parche, pero se van a incluir escenarios o fondos nuevos. En el video se muestran escenarios que no están disponibles en el juego actual, y Lizard Cube dió a entender en Twitter que sí, van a haber escenarios nuevos.

Ya podemos agregar el DLC al wishlist en Steam, pero va a estar disponible en todas las plataformas: Nintendo Switch, PS4, Xbox One, Windows/Mac/Linux

Estas actualizaciones para Street Of Rage 4 van a estar disponibles en algún momento este año, pero todavía no hay fecha específica o información del precio. Por mi parte lo espero con ansias, va a ser una buena excusa para volver a jugar Streets Of Rage 4. Los desarrolladores habían comentado varias veces que querían enfocarse en agregar contenido nuevo, y está bueno ir conociendo qué ideas tenían en mente.

El post Anunciado DLC y un parche con contenido nuevo para Streets Of Rage 4: Mr. X Nightmare fue publicado originalmente en Picando Código.

» Leer más, comentarios, etc...

Picando Código

Siete días en el Picandoverso – Abril 2021

abril 07, 2021 06:30

Decimoprimera entrega de 7 días en el Picandoverso, en la primera semana de Abril, el cuarto mes del año. En Escocia se empezaron a relajar las medidas de aislamiento y el viernes tengo hora para cortarme el pelo después de 9 meses sin que una tijera o máquina se acercara a mi cuero cabelludo. Por unos días hizo clima de primavera, pero esta semana volvió el frío con nieve y granizo en distintas partes del país.

Vamos al popurrí de contenidos relacionados a Programación, Tecnología, Cómics, Videojuegos y más de estos últimos siete días:

 Siete días en el Picandoverso – Abril 2021

💎 Ruby

🔑 Nuevas actualizaciones de seguridad en Ruby – Se encontraron dos vulnerabilidades:

Debido a esto, se publicaron nuevas versiones de Ruby: 2.5.9 (que ya no está soportada a partir del 31 de marzo, pero de todas formas backportearon el parche de seguridad), 2.6.7, 2.7.3 y 3.0.1.

🐦 @RubyCards es una cuenta de Twitter que nos ayuda a aprender y recordar conceptos de Ruby por medio de flashcards. Muy buena, soy una de las 300 personas que la empezó a seguir en poco tiempo, una de las tantas pruebas de que Ruby no murió…

🐚 Ruby 3.1 agrega compact a Enumerable. Esto nos va a permitir acceder a todos los elementos de un enumerable excepto los que sean nil:

=> enum = [1, nil, 3, nil, 5].to_enum
=> #
=> enum.compact
=> [1, 3, 5]

🎙 Muy interesante entrevista a Jeremy Evans, desarrollador en varios proyectos importantes como Sequel, Roda, Rodauth, además de mantener los ports de Ruby para OpenBSD y ha aportado código tanto en CRuby como JRuby.

Programación y Tecnología

🤯 Microsoft publicó su propia distribución de OpenJDK, una distribución sin costo, con soporte a largo plazo, de código abierto y gratuita. Una noticia que hace 10 años hubiera sido inimaginable… La distribución incluye los binarios para Java 11, está basada en OpenJDK 11.0.10+9, y puede usarse en servidores y desktops x64 para macOS, Linux, y Windows.

☕ Siguiendo con Java, en este enlace se listan las nuevas características en Java desde Java 8 a Java 16.

🐍 Humble Bundle tiene un paquete de ebooks sobre Python, con libros como Data Engineering with Python, Modern Python Cookbook, and Artificial Intelligence with Python

📚 De Humble Bundle también, todavía está vigente el paquete Machine Learning from Zero to Hero, incluyendo libros sobre Inteligencia Artificial, Machine Learning y más.

📝 Como todas las semanas, hay una nueva edición de Emacs News. El sitio tiene un nuevo diseño, con la posibilidad de usar Night Mode. De las cosas que lista, justo había probado good-scroll, una biblioteca que había visto en /r/emacs que mejora el desplazamiento en Emacs y la verdad está bastante bueno.

🍪 En este artículo, Mozilla explica qué son las cookies y las supercookies. Con nuevas versiones de Firefox, tenemos un modo de privacidad “Estricto” que mantiene las cookies en “jarros” separados para cada sitio que visitamos, protegiéndonos de los sitios que comparten nuestra información de navegación entre sí.

Videojuegos

🕹 Nintendo anunció Pac-Man 99, una nueva versión del clásico Pac-Man en modo battle-royale donde nos enfrentamos a 99 jugadores jugando Pac-Man. Me encantan Tetris 99 y Pac-Man, así que definitivamente voy a probar Pac-Man 99. Va a estar disponible para usuarios de Nintendo Switch Online a partir de hoy a las 18:00 hora de la Costa Oeste de Estados Unidos. Es gratis, pero va a incluir contenido pago en forma de modos de juego offline y distintos skins basados en juegos clásicos de Namco.

🎮 Este año vuelve la E3 en formato digital. Se va a realizar del 12 al 15 de junio y entre las empresas que la apoyan están Nintendo, Xbox, Capcom, Konami, Ubisoft, Take-Two, Warner Bros y Koch Media. Puede estar interesante el evento, si es que las empresas se están guardando varios anuncios para darlos a conocer al público en esos 3 días, y no lo usan sólo para promocionar cosas que ya conocemos.

😱 Sinfeld Remastered es una parodia del show de televisión acerca de nada formato acción/horror/comedia con varios estilos de juego inspirado por Resident Evil, Silent Hill y más:
YouTube Video

Cómics

🕸 Uno de los mejores escritores actuales de cómics, Chip Zdarsky, vuelve a escribir a Spider-Man. En Agosto se une al artista Mark Bagley para un anual de Spider-Man: Life Story, el título que cuenta la historia de Spider-Man a través de las décadas en tiempo real.

🔨 La semana pasada comentaba sobre Beta Ray Bill #1, y después de leerlo debo decir que está muy genial. Tanto el arte como la historia, un buen cómic del personaje, ¡recomendado!

Cine y Televisión

📺 El tercer capítulo de The Falcon and the Winter Soldier (o Flacón y Gualtersoldier como le empecé a decir) estuvo tremendo, y sigue estando muy buena la serie. Marvel publicó un nuevo tráiler de la serie Loki, que se empieza a transmitir el 11 de junio en Disney+.

Se publicó también un trailer de la nueva película de Space Jam, y después de muchos años finalmente se actualizó el sitio web de Space Jam que mantenía su estilo desde los 90’s.

El fin de semana miré dos películas que recomiendo. La primera fue Seaspiracy, un documental de Netflix que incluye a mis héroes de Sea Shepherd, y muestra parte del impacto sobre el medio ambiente de la pesca. También volví a mirar They Live de John Carpenter, una muy buena película de finales de los ’80s.

Picando Código

Pueden seguir los posts de Picando Código por RSS, Twitter (cuenta únicamente con posts del blog) y canal de Telegram. También estoy en Twitter y Mastodon, donde además de compartir lo que se publica en el blog publico alguna cosa más.

Otros 7 días en el Picandoverso:

El post Siete días en el Picandoverso – Abril 2021 fue publicado originalmente en Picando Código.

» Leer más, comentarios, etc...

Picando Código

Spotify usa reconocimiento de voz para invadir la privacidad de sus usuarios

abril 06, 2021 04:00

Recientemente Access Now envió una carta a Spotify pidiendo que la empresa abandone la tecnología atada a su patente de reconocimiento de voz. Esta tecnología presenta serias preocupaciones en lo que respecta a privacidad y seguridad. Siempre está activada y afirma poder detectar -entre otras cosas- “estado emocional, genero, edad o acento” para recomendar música. Es tecnología peligrosa, una violación de la privacidad y otros derechos humanos, y debería ser abandonada.

Spotify

Las preocupaciones principales de Access Now son:

  • Manipulación emocional: Monitoreando estado emocional, y haciendo recomendaciones basado en eso, pone a Spotify en una posición de poder muy poderosa en relación al usuario.
  • Discriminación de género: Es imposible inferir género sin discriminar contra personas trans y no-binarias.
  • Violaciones de privacidad: El dispositivo estaría “siempre encendido”, lo que significa que estaría monitoreando constantemente, procesando datos de voz, y probablemente ingiriendo información sensible.
  • Seguridad de los datos: Cosechar datos tan personales podría convertir a Spotify en el blanco de autoridades de gobierno y otras entidades maliciosas buscando información.

Podemos leer más detalles en la carta que enviaron a Spotify.

“No hay absolutamente ninguna razón válida para que Spotify siquiera intente discernir cómo nos sentimos, cuánta gente hay en una habitación con nosotros, nuestro género, edad, o cualquier otra característica que la patente afirma detectar”, dijo Isedua Oribhabor, Analista de Política en EEUU de Access Now. “Las millones de personas que usan Spotify merecen respeto y privacidad, no manipulación y monitoreo encubiertos.” Access Now defiende y extiende los derechos digitales de los usuarios en riesgo alrededor del mundo mediante políticas, activismo, becas y procesos legales.

Esto es una razón más para no usar Spotify. Además de esta potencial invasión de la privacidad de sus usuarios, tienen un modelo de negocio atroz donde la empresa se enriquece mientras los artistas reciben limosnas por cada reproducción en la plataforma.

Como dice el proyecto Tor, los servicios de música no deberían estar usando vigilancia encubierta en sus productos.

El post Spotify usa reconocimiento de voz para invadir la privacidad de sus usuarios fue publicado originalmente en Picando Código.

» Leer más, comentarios, etc...

Variable not found

Enlaces interesantes 438

abril 06, 2021 06:05

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

Data

Web / HTML / CSS / Javascript

Visual Studio / Complementos / Herramientas

Xamarin

Publicado en Variable not found.

» Leer más, comentarios, etc...

Header Files

Huevos de Pascua

abril 04, 2021 03:16

Primero que nada, ¡feliz Pascua de Resurrección! Como viene siendo tradición desde hace muchísimos años, una de las actividades que realizan los pequeños en este domingo es la búsqueda de pequeños (o no tan pequeños) huevos de chocolate que han sido escondidos por diversos lugares, los llamados huevos de Pascua. De forma similar, los huevos de Pascua virtuales son mensajes, detalles o características ocultas en una aplicación, película, etc.

El primer huevo de Pascua informático que se conoce está en el arcade Starship 1 (1977). Pulsando los botones de una forma específica aparecía un mensaje y el jugador ganaba 10 partidas gratis. Este huevo de Pascua tardó 30 años en ver la luz.

El término huevo de Pascua fue acuñado por Steve Wright, director de desarrollo de Atari. Warren Robinett, programador de Atari, introdujo una función secreta en el videojuego Adventure (1979). Al pasar el personaje sobre un punto específico de la pantalla y siguiendo una secuencia de pasos, aparecía un mensaje que decía “Creado por Warren Robinett” (en ese entonces no se incluían los nombres de los programadores en los créditos). Tiempo después se animó a los desarrolladores a introducir más características ocultas de este tipo, y se les llamó huevos de Pascua porque estaban escondidos y los jugadores tenían que encontrarlos.

warren_robinett

Los huevos de Pascua no son exclusivos de los videojuegos. Por ejemplo (y aunque parezca que soy un dinosaurio) Microsoft Office 97 incluía un pequeño simulador de vuelo en Excel, y un pinball en Word, y hasta antes de Windows XP, el salvapantallas comenzaba a mostrar nombres de volcanes al escribir volcano.

Apple es bien conocida por muchos guiños sutiles en el diseño de sus productos, aunque no pueden considerarse huevos de Pascua en su definición más pura. Dos de mis favoritos so el logo de la aplicación TextEdit con el mensaje del anuncio Here’s to the Crazy Ones, y el icono que usa para mostrar ordenadores Windows en red:

textedit

pc_icon

El primer huevo de Pascua de Apple fue la inclusión de las firmas de todos los integrantes del equipo del Macintosh en su carcasa. Otro ejemplo más reciente es el de Mac OS X Mountain Lion (2012), en el que las aplicaciones descargadas tenían temporalmente la fecha 24 de enero de 1984 (lanzamiento del primer Macintosh).

os_x_mountain_lion

Google por su parte es muy dado a los huevos de Pascua, siendo mi favorito el coche de Mario Kart que lanzaron por el Día Internacional de Mario en el 2018 (10 de marzo, Mar10).

mario_karts

Para cerrar, me gustaría añadir uno que introduje en las aplicaciones que desarrollo en STT (2DMA, 3DMA y iSen), y que ya algún usuario ha descubierto por su cuenta 😄. En la ficha de cliente de la BBDD se cambia el icono del cliente por una tarta si se abre la ficha del mismo el día de su cumpleaños.

2dma

En https://eeggs.com es posible encontrar una gran listado de huevos de Pascua, ¿cuáles conocíais ya?

» Leer más, comentarios, etc...

Blog Bitix

Programas basados en consola con Java usando Lanterna

abril 03, 2021 10:00

Java

Todavía hoy en día la terminal no ha desaparecido, y no lo hará, aún habiendo pasado ya algunas décadas de la aparición de las interfaces gráficas. Algunas ventajas de la terminal es que conociendo los comandos es más fácil realizar una tarea que con un programa basado en una ventana con botones que hay que pulsar usando el ratón, además las tareas usando comandos se pueden automatizar con scripts y combinar varios donde la entrada de uno sea la salida de otros dando lugar a funcionalidades mucho más complejas que las que realizan los comandos individualmente. También los comandos son más eficientes al no requerir tantos recursos del sistema. Por todo ello los comandos y programas basados en la consola o terminal no van a desaparecer.

En GNU/Linux la terminal es una parte importante del sistema con la que es posible realizar muchas de las tareas, es más fácil y habitual para tareas repetitivas. ncurses es una librería para desarrollar programas basados en texto pero simulando una interfaz gráfica. Se pueden crear ventanas, botones, mensajes de texto, paneles, gestores de disposición o layouts, etiquetas, cajas de texto, selectores, botones check y radio, diálogos, etc…

En Java está la librería Lanterna que proporciona similar funcionalidad que ncurses, y quizá más, sirve para el mismo propósito pero con una implementación completamente basada en Java y sin necesidad de recurrir a código nativo. En la documentación de Lanterna hay varios ejemplos y guías de las clases principales que forman la API.

Un ejemplo de uso posible para Lanterna es realizar un instalador basado en texto para el script de instalación de Arch Linux que implementé y mantengo desde hace un tiempo. Con Lanterna es posible crear el instalador o configurador para la instalación desatendida y automatizada que junto con jlink para crear un runtime distribuible de Java es posible ejecutar sin necesidad de instalar Java previamente en el sistema y utilizando la imagen que proporciona Arch Linux sin necesidad de modificarla.

El siguiente código muestra lo que podría ser la pantalla inicial de este instalador usando Lanterna.

 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
package io.github.picodotdev.blogbitix.lanterna;

import java.util.Arrays;

import com.googlecode.lanterna.SGR;
import com.googlecode.lanterna.TerminalSize;
import com.googlecode.lanterna.TextColor;
import com.googlecode.lanterna.graphics.SimpleTheme;
import com.googlecode.lanterna.gui2.BasicWindow;
import com.googlecode.lanterna.gui2.BorderLayout;
import com.googlecode.lanterna.gui2.Button;
import com.googlecode.lanterna.gui2.DefaultWindowManager;
import com.googlecode.lanterna.gui2.EmptySpace;
import com.googlecode.lanterna.gui2.GridLayout;
import com.googlecode.lanterna.gui2.Label;
import com.googlecode.lanterna.gui2.MultiWindowTextGUI;
import com.googlecode.lanterna.gui2.Panel;
import com.googlecode.lanterna.gui2.Window;
import com.googlecode.lanterna.screen.Screen;
import com.googlecode.lanterna.screen.TerminalScreen;
import com.googlecode.lanterna.terminal.DefaultTerminalFactory;
import com.googlecode.lanterna.terminal.Terminal;

public class Main {

    public static void main(String[] args) throws Exception {
        Terminal terminal = new DefaultTerminalFactory().createTerminal();
        Screen screen = new TerminalScreen(terminal);
        screen.startScreen();

        Panel titlePanel = new Panel();
        titlePanel.addComponent(new Label(" "));
        titlePanel.addComponent(new Label(" Arch Linux Installation").addStyle(SGR.BOLD));

        Panel buttonsPanel = new Panel(new GridLayout(2).setHorizontalSpacing(1));
        buttonsPanel.addComponent(new Button("Continue", () -> System.exit(0)));
        buttonsPanel.addComponent(new Button("Exit", () -> System.exit(0)));
        buttonsPanel.setLayoutData(GridLayout.createLayoutData(GridLayout.Alignment.END, GridLayout.Alignment.CENTER, false, false));

        Panel contentPanel = new Panel(new GridLayout(1).setLeftMarginSize(1).setRightMarginSize(1));
        contentPanel.addComponent(new EmptySpace(new TerminalSize(0, 1)));
        contentPanel.addComponent(new Label("Welcome to Arch Linux Install Script.\n\nThis automated, unnatended and configurable script\nwill install Arch Linux on your system."));
        contentPanel.addComponent(new EmptySpace(new TerminalSize(0, 1)));
        contentPanel.addComponent(new Label("Warning!\n\nThis script deletes all partitions of the persistent\nstorage and continuing all your data in it will be lost.").setForegroundColor(TextColor.ANSI.RED));
        contentPanel.addComponent(new EmptySpace(new TerminalSize(0, 1)));
        buttonsPanel.setLayoutData(GridLayout.createLayoutData(GridLayout.Alignment.END, GridLayout.Alignment.CENTER,false,false)).addTo(contentPanel);

        Panel mainPanel = new Panel(new BorderLayout());
        mainPanel.addComponent(titlePanel, BorderLayout.Location.TOP);

        BasicWindow mainWindow = new BasicWindow();
        mainWindow.setHints(Arrays.asList(Window.Hint.FULL_SCREEN, Window.Hint.NO_DECORATIONS));
        mainWindow.setTheme(new SimpleTheme(TextColor.ANSI.WHITE, TextColor.ANSI.BLUE));
        mainWindow.setComponent(mainPanel);

        BasicWindow window = new BasicWindow("Arch Linux Installation");
        window.setHints(Arrays.asList(Window.Hint.CENTERED));
        window.setComponent(contentPanel);

        MultiWindowTextGUI gui = new MultiWindowTextGUI(screen, new DefaultWindowManager(), new EmptySpace(TextColor.ANSI.BLUE));
        gui.addWindow(mainWindow);
        gui.addWindow(window);
        gui.waitForWindowToClose(mainWindow);
        gui.setActiveWindow(window);
    }
}
Main.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
plugins {
    id 'application'
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'com.googlecode.lanterna:lanterna:3.1.1'
}

application {
    mainClass = 'io.github.picodotdev.blogbitix.lanterna.Main'
    sourceCompatibility = '11'
}

build.gradle

Hola Mundo con Lanterna

Hola Mundo con Lanterna
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 distZip && unzip -o -d app/build/distributions/ app/build/distributions/app.zip && ./app/build/distributions/app/bin/app

» Leer más, comentarios, etc...

Picando Código

Anunciado Asterix & Obelix : Slap them all! – nuevo juego beat ’em up

abril 01, 2021 12:00

El estudio francés de videojuegos Microids anunció una nueva aventura de Astérix y Obélix disponible en el otoño del hemisferio norte, primavera del hemisferio sur. Lo vamos a poder jugar en Nintendo Switch, PC, Playstation y Xbox. Asterix & Obelix: Slap them All! es un juego beat ’em up 2D en el universo creado por René Goscinny y Albert Uderzo.

Asterix & Obelix: Slap them All!

La historia nos lleva al año 50 A.C, donde toda la Galia está ocupada por los Romanos… ¿Toda? ¡No! Una aldea poblada por irreductibles galos resiste, ahora y siempre, al invasor. Vamos a poder jugar como Astérix y Obélix y visitar de los lugares más icónicos de la serie de cómics, enfrentándonos a legionarios romanos, piratas, bandidos y hasta los Normandos.

El juego es publicado por Microids, y desarrollado por Mr Nutz Studio. No encontré demasiada información del estudio en internet, pero con un poco de investigación aprendí algo más. Dicen que el equipo ha estado creando juegos desde 1988. Trabajaron en Mr Nutz, un juego de plataformas típico de la época de los 16-bits y Toki en Nintendo Switch. Mr Nutz fue diseñado y desarrollado para Ocean Software en el Reino Unido tras el cierre de Ocean Francia. El artista Philippe Dessoly y el programador Pierre Adane, ex empleados de Ocean Francia, crearon Mr Nutz. Philippe Dessoly también fue el artista en Toki y es el artista en este juego también. No encontré confirmación, pero Pierre Adane está listado en el About de Microids, así que asumo que Mr Nutz Studio es el nombre bajo el cual desarrolla juegos este dúo en conjunto con Microids.

El estudio quiere hacer que la aventura sea lo más respetuosa posible del material original. Eligieron usar una dirección artística muy cercana a la de los cómics, con peronajes y escenarios dibujados a mano. “Un verdadero tributo a los clásicos 2D animados y un estilo que seguramente apelará a fans y gamers retro por igual”. Comentan que a diferencia de la poción mágica, no hay secretos en la receta del gameplay. Pretende seguir las mecánicas clásicas que definieron al género beat ’em up, agregándole juego cooperativo local.

Estoy muy contento con este resurgimiento de juegos beat ’em up. Esta saga se presta muy bien para el género, y por lo poco que se ve hasta ahora, se ve muy respetuosa con el material original.

Del mismo estudio me compré hace un tiempo Asterix & Obelix XXL2 para Nintendo Switch. Me entretuvo un poco por todas las referencias a otros videojuegos y porque conozco la serie. Pero es un remaster en alta definición de un juego de 2006. Si bien es algo entretenido, se le notan los años. Pero la edición de colección está buena, incluyó un par de figuras de plástico de mis galos preferidos. ¡Le tengo más fe a este nuevo videojuego de los irreductibles galos!

Como podemos apreciar en el trailer, la animación se ve muy bien, pero incluso así, los gráficos no son finales todavía:

YouTube Video

El juego va a incluir audio en Inglés, Francés y Alemán, y textos en estos idiomas, Italiano y Español. Va a ser un buen año para juegos del género y seguidores de Astérix 😁

El post Anunciado Asterix & Obelix : Slap them all! – nuevo juego beat ’em up fue publicado originalmente en Picando Código.

» Leer más, comentarios, etc...

Blog Bitix

Los conceptos de encapsulación, herencia, polimorfismo y composición de la programación orientada a objetos

marzo 31, 2021 05:00

La programación orientada a objetos es un paradigma adoptado por todos lenguajes modernos y publicados en las últimas décadas. La programación orientada a objetos proporciona una sintaxis en el lenguaje para definir abstracciones que hacen sencillo utilizar conceptos cuya implementación es compleja. La encapsulación, la abstracción, la herencia, el polimorfismo, la composición y la inyección de dependencias son conceptos fundamentales a conocer en la programación orientada a objetos.

Java

Para el desarrollo de software a lo largo del tiempo se han definido varios paradigmas de programación implementados en los lenguajes de programación.

Los primeros lenguajes de programación utilizaban un paradigma imperativo con un conjunto de instrucciones ejecutadas de forma secuencial y organizado en funciones que manipulan datos. Posteriormente, surge el paradigma de programación orientado a objetos en el que el código se organiza en objetos que encapsulan los datos y las funciones que los manipulan. Otro paradigma es la programación funcional donde el código se organiza en funciones puras que dados unos datos de entrada genera un resultado y en vez de cambiar de estado a los datos existentes genera nuevos datos haciendo a los datos inmutables.

Muchos de los lenguajes de programación hacen uso u ofrecen formas de aplicar al mismo tiempo varios de estos paradigmas de programación. Por ejemplo, el lenguaje de programación C aún siendo un lenguaje de programación que hace uso del paradigma imperativo también es posible utilizar conceptos de la programación orientada a objetos o funcionales, aunque el lenguaje en sí no ofrezca abstracciones propias de orientación a objetos o funcionales. El lenguaje de programación Java es orientado a objetos aunque también en el código de los métodos utiliza programación imperativa y con las novedades incluidas en Java 8 con las lambdas, streams, o los records en Java 16 y el soporte en las estructuras de datos de las colecciones permite utilizar conceptos de la programación funcional.

En la programación orientada a objetos hay varios conceptos que definen este paradigma de programación, la encapsulación de datos, abstracciones de los modelos en los programas, los objetos, clases e instancias, herencia, polimorfismo y composición.

Contenido del artículo

Conceptos de la programación orientada a objetos

Los lenguajes de programación orientados a objetos se diferencian de los imperativos en que el propio lenguaje incluye abstracciones y sintaxis específica para el soporte de la programación orientada a objetos.

El lenguaje de programación Java considerado como un lenguaje de programación a objetos incluye palabras reservadas para la definición de clases e interfaces e implementa los conceptos de herencia y polimorfismo.

Encapsulación

La encapsulación no es un concepto propio de la programación orientada a objetos pero es fundamental, los objetos son la abstracción que proporciona la encapsulación.

La encapsulación consiste en hacer que los datos sean modificados únicamente por las funciones destinadas a tal efecto. La encapsulación permite que los datos conserven un estado válido y consistente, trata de evitar que cualquier código pueda modificar una estructura de datos con el consiguiente problema de generación de inconsistencias.

Se denomina encapsulación porque los datos y sus estructuras de datos no están accesibles de forma directa, sino que para acceder a los datos o manipularlos se ha de realizar a través de las funciones asociadas, los datos están encapsulados.

Abstracción

La abstracción es el concepto por el que un modelo es creado con las propiedades relevantes a observar. Un programa trata únicamente con las propiedades de un objeto que al programa le interesa. Las clases son la abstracción de los conceptos que maneja la aplicación, pueden ser conceptos que existan en el mundo real pero simplificados al tener únicamente las propiedades relevantes para la aplicación. Las clases también pueden ser conceptos que no tengan una existencia física en el mundo real como una lista de elementos, una dirección IP o un archivo de ordenador.

Un avión es un objeto físico del mundo real con multitud de propiedades, desde su fabricante y modelo, color, tamaño, numero de asientos, ubicación, capacidad de carga, peso, año de diseño y fabricación, materiales de fabricación, altitud, posición GPS, dirección, velocidad y distancia máxima y muchas otras. De todas estas propiedades en una aplicación de gestión de embarque le interesará únicamente las propiedades de los asientos, quizá en otra aplicación para la programación de vuelo le interesa otras propiedades como altitud, posición GPS, dirección, velocidad aeropuerto origen y destino o distancia.

Abstracción en dos modelos diferentes de un objeto

Abstracción en dos modelos diferentes de un objeto
Fuente: matiasbeltramone.github.io

Objeto, clase e instancia

Los objetos, clases e instancias son conceptos característicos de la programación a objetos. Son la denominación que le dan los lenguajes de programación orientada a objetos para la encapsulación y las abstracciones.

Los objetos y clases encapsulan los datos y definen la colección de funciones que los manipulan. Las clases son la definición de los objetos en tiempo de compilación y las instancias son la creación en tiempo de ejecución de una clase, en tiempo de ejecución un programa puede crear tantas instancias de una clase como desee, al crear la instancia se reserva la memoria para el conjunto de datos de la clase.

A las funciones de las clases en el lenguaje de dominio de la orientación a objetos se les denomina métodos y a los datos propiedades. Esta es la definición de una clase en Java con varias propiedades y varios métodos que manipulan esas propiedades, si otra clase quiere manipular los datos lo ha de hacer a través de los métodos de la clase tal como permitan los modificadores de acceso de los miembros de la clase.

 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
public enum Color {
    BLACK, WHITE, LIGHT_GREY, RED, BLUE
}

public enum Brand {
    RENAULT, PEUGEOT, FORD, TOYOTA, MERCEDES, TESLA
}

public enum Status {
    STOPED, ON
}

public enum Gasoline {
    OCTANE_95, OCTANE_98, GASOLEO_A
}

public class Car {

    private Brand brand
    private Color color;
    private int maxSpeed;
    private int speed;

    private Status status;

    public Car(Brand brand, Color color, int maxSpeed) {
        this.brand = brand;
        this.color = color;
        this.maxSpeed = maxSpeed;

        this.speed = 0;
        this.status = STOPED;
    }

    public void on() {
        this.status = ON;
    }

    public void stop() {
        this.speed = 0;
        this.status = STOPED;
    }

    public void setSpeed(int speed) {
        this.speed = speed;
    }

    public void fillCombustible(Gasoline gasoline, int liters) {
        ...
    }

    ...
}
Car-class.java

En Java la creación de una instancia de una clase se realiza con la palabra reservada new y utilizando un método especializado únicamente en construir instancias de la clase, un método constructor.

1
2
Car car = new Car(Branc.RENAULT, Color.LIGHT_GREY, 160);

Car-new.java

La invocación de new y un constructor devuelve una referencia a la instancia del objeto a través de la cual se realizan la invocación de sus métodos o también denominado el paso de mensajes.

El formato de la invocación de un método en una instancia de un objeto es el siguiente. La referencia del objeto se separa con un punto del método a invocar, entre los paréntesis se proporciona una lista de argumentos separados por comas. Los argumentos pueden ser referencias a otras instancias de objetos o en Java datos primitivos numéricos.

1
2
3
4
5
objeto.metodo(argumentos);

car.on();
car.setSpeed(50);
car.fillCombustible(Gasoline.GASOLEO_A, 50);
Car-method.java

Herencia e interfaces

Otro de los conceptos propios de la programación orientada a objetos es la herencia. Al implementar una clase y para reutilizar el código una clase puede extender de otra, heredando el comportamiento de la clase extendida. La relación de herencia entre las clases es una relación de «es-un».

En Java la herencia se realiza con la palabra reservada extends.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
public class Vehicle {

    private BigDecimal price;
    private int speed;

    public Vehicle(BigDecimal price) {
        ...
    }
}

public class Car extends Vehicle {
    ...
}

public class Truck extends Vehicle {
    ...
}

public class Bicycle extends Vehicle {
    ...
}
Car-inheritance.java

Como un coche es un vehículo la referencia de coche se puede asignar a la referencia de vehículo, por el contrario no todos los vehículos son coches y por tanto una referencia de vehículo no se puede asignar directamente a una referencia de coche.

Si se está seguro de que una referencia de vehículo es una referencia de coche es posible hacer la asignación haciendo un cast de la referencia de forma explícita para que el compilador no genere un error de compilación. Para comprobar si una referencia es de una determinada clase se utiliza el operador instanceof. Si se realiza un cast y en tiempo de ejecución no se puede realizar porque la referencia no sea asignable a la clase que se hace cast se produce una excepción del tipo ClassCastException.

1
2
3
4
5
6
7
8
Car car = new Car(Branc.RENAULT, Color.LIGHT_GREY, 160);
Vehicle vehicle = car;

...

if (vehicle instanceof Car) {
    Car car = (Car) vehicle;  
}
Car-cast.java

En Java solo se permite heredar de una única clase, no hay herencia múltiple. Sin embargo, si se permite implementar múltiples interfaces. En Java una interfaz es una colección de métodos que una clase que la implementa debe proporciona una implementación de los métodos de la interfaz.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public interface Cleanable {
    void clean();
}

public class Car extends Vehicle implements Cleanable {

    @Override
    public clean() {
        ...
    }
}
Car-interface.java

En Java las clases abstractas no pueden instanciarse pero si ser extendidas por otras clases que no sean abstractas. Una clase al implementar una interfaz ha de proporcionar una implementación para todos los métodos de la interfaz, en caso de no implementar algún método la clase ha de declararse como abstracta con la palabra reservado abstract.

Clases, herencia e interfaces

Clases, herencia e interfaces
Fuente: matiasbeltramone.github.io

Desde la versión de Java 8 las interfaces con los métodos default pueden proporcionar implementaciones para métodos.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public interface Math {

    BigDecimal mutiply(BigDecimal a, BigDecimal b);

    default BigDecimal square(BigDecimal a) {
        return mutiply(a, a);
    }

    default BigDecimal cube(BigDecimal a) {
        return mutiply(square(a), a);
    }
}
Math-interface-default-method.java

Ejemplos de clases, herencia e interfaces

 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
public interface Speak {
    void speak();
}

public abstract class Animal implements Speak {
    ...
}

public class Dog extends Animal {
    ...

    @Override
    public void speak() {
        System.out.println("Guau!");
    }
}

public class Cat extends Animal {
    ...

    @Override
    public void speak() {
        System.out.println("Miau!");
    }
}

public class Human extends Animal {
    ...

    @Override
    public void speak() {
        System.out.println("Hello!");
    }
}
Animal-classes.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public class Shape {
    ...
}

public class Circle extends Shape {
    ...
}

public class Rectangle extends Shape {
    ...
}
Shapes-classes.java

Polimorfismo

El polimorfismo es una propiedad por la cual el método invocado varía en función de la clase de la instancia de un objeto. El polimorfismo es una característica única en la programación orientada a objetos, mientras que la encapsulación y herencia es posible conseguirla en lenguajes no orientados a objetos de una manera razonablemente segura el polimorfismo al usar punteros a funciones es propensa a errores. Los los lenguajes orientados lo que proporcionan es un uso sencillo y seguro del polimorfismo ocultando los detalles internos de su implementación de sus punteros a funciones.

Polimorfismo

Polimorfismo
Fuente: matiasbeltramone.github.io

En una jerarquía de clases que representen diferentes figuras geométricas dos operaciones son el cálculo del área y de la longitud del perímetro. La fórmula matemática depende de la clase de figura. En el caso de un cuadrado y de un círculo las fórmulas para el cálculo del área y perímetro son distintas.

 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
public abstract class Shape {
    ...

    public abstract double calculatePerimeter();
    public abstract double calculateArea();
}

public class Circle extends Shape {

    private double radious;

    ...

    public double calculatePerimeter() {
        return 2 * Math.PI * radious;
    }

    public double calculateArea() {
        return Math.PI * radious * radious;
    }
}

public class Rectangle extends Shape {

    private double tall;
    private double with;

    ...

    public double calculatePerimeter() {
        return 2 * (tall + with);
    }

    public double calculateArea() {
        return tall * with;
    }
}
Shape-polymorfism-classes.java

La potencia del polimorfismo es que teniendo una referencia de Shape al invocar al método de la operación el método que se ejecuta es el propio de la clase de la instancia en tiempo de ejecución, si shape es un square se llama al método calculatePerimeter o calculateArea de square y si shape es un circle a sus respectivos métodos.

1
2
3
4
Shape shape = ...;

System.out.printf("Shape perimter %s%n", shape.calculatePerimeter());
System.out.printf("Shape area %s%n", shape.calculatearea());
Shape-polymorfism-example.java

Los problemas de la herencia

El principal problema de la herencia es que en ocasiones no es el mecanismo adecuado para reutilizar el comportamiento, ocasionado que al intentar usar herencia provoque un problema exponencial del número de clases posibles.

En un ejemplo de pizzas que tienen ingredientes una posible jerarquía de clases es la siguiente.

 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
public class Pizza {

    private String base;
    private List<String> ingredients;

    public Pizza(String base, List<String> ingredients) {
        ...
    }

}

public class CarbonaraPizza extends Pizza {

    public CarbonaraPizza() {
        super("Normal", List.of("Mozzarella Cheese", "Bacon", "Mushroom", "Onion"));
    }
}

public class BarbecuePizza extends Pizza  {

    public BarbecuePizza() {
        super("Normal", List.of("Mozzarella Cheese", "Beef", "Onion", "Bacon", "Corn"));
    }
}

public class HawaianPizza extends Pizza {

    public HawaianPizza() {
        super("Normal", List.of("Mozzarella Cheese Extra", "York Double", "Pineapple"));
    }
}
Pizza-classes-1.java

El problema surge cuando a las pizzas se les añade otro vector adicional de diseño, además de los ingredientes. Si a las pizzas se les añade el tipo de cocina y una clase concreta con las diferentes combinaciones el número de clases crece de forma exponencial con el nuevo vector de diseño, se produce una proliferación de clases que se convierte en un problema de mantenimiento.

 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
public class Pizza {

    private String base;
    private List<String> ingredients;

    public Pizza(String base, List<String> ingredients) {
        ...
    }

    ...
}

public class CarbonaraPizza extends Pizza {

    public CarbonaraPizza() {
        super("Normal", List.of("Mozzarella Cheese", "Bacon", "Mushroom", "Onion"));
    }

    ...
}

public class BarbecuePizza extends Pizza  {

    public BarbecuePizza() {
        super("Normal", List.of("Mozzarella Cheese", "Beef", "Onion", "Bacon", "Corn"));
    }

    ...
}

public class HawaianPizza extends Pizza {

    public HawaianPizza() {
        super("Normal", List.of("Mozzarella Cheese Extra", "York Double", "Pineapple"));
    }

    ...
}

public class NewYorkStyleCarbonaraPizza extends HawaianPizza {
    ...
}

public class ChicagoStyleCarbonaraPizza extends HawaianPizza {
    ...
}

public class NewYorkStyleBarbecuePizza extends HawaianPizza {
    ...
}

public class ChicagoStyleBarbecuePizza extends HawaianPizza {
    ...
}

public class NewYorkStyleHawawianPizza extends HawaianPizza {
    ...
}

public class ChicagoStyleHawawianPizza extends HawaianPizza {
    ...
}
Pizza-classes-2.java

Con el tipo de masa podría haber sido otro vector de diseño pero en este caso se ha implementado con una relación «tiene-un» en vez de «es-un», la solución para el tipo de cocina es aplicar una relación «tiene-un», esto es, en vez de usar herencia la solución es usar composición.

Composición

Si la herencia es una relación «es-un» entre dos clases, la composición es una relación «tiene-un» entre dos clases. La composición se produce cuando una clase contiene referencias a instancias de otras clases en sus propiedades. La clase coche contiene una marca, modelo, motor, ruedas, aceite, color, velocidad y velocidad máxima.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
public Car {

    ...

    private Brand brand;
    private Model model;
    private Engine engine;
    private Oil oil;
    private Color color;
    private Tire tireFrontLeft;
    private Tire tireFrontRight;
    private Tire tireBackLeft;
    private Tire tireBackRight;
    private int maxSpeed;
    private int speed;

    private Status status;

    ...
}
Car-composition.java

En el problema de las pizzas utilizando herencia la solución es usar composición para la forma de cocinar de las pizzas en vez de herencia.

 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
public class Pizza {

    private String base;
    private List<String> ingredients;
    private BakeStyle bakeStyle;

    public Pizza(String base, List<String> ingredients, BakeStyle bakeStyle) {
        ...
    }

    public void bake() {
        bakeStyle.bake(this);
    }
}

public class CarbonaraPizza extends Pizza {

    public CarbonaraPizza(BakeStyle bakeStyle) {
        super("Normal", List.of("Mozzarella Cheese", "Bacon", "Mushroom", "Onion"), bakeStyle);
    }
}

public class BarbecuePizza extends Pizza  {

    public BarbecuePizza(BakeStyle bakeStyle) {
        super("Normal", List.of("Mozzarella Cheese", "Beef", "Onion", "Bacon", "Corn"), bakeStyle);
    }
}

public class HawaianPizza extends Pizza {

    public HawaianPizza(BakeStyle bakeStyle) {
        super("Normal", List.of("Mozzarella Cheese Extra", "York Double", "Pineapple"), bakeStyle);
    }
}

public abstract BakeStyle {
    public abstract void bake(Pizza pizza);
}

public NewYorkBakeStyle {
    public void bake(Pizza pizza) {
        ...
    }
}

public ChicagoNewYorkBakeStyle {
    public void bake(Pizza pizza) {
        ...
    }
}
Pizza-composition.java

Beneficios de la composición

Aunque la herencia es útil y adecuado en algunos casos por regla general se recomienda usar composición sobre herencia por los siguientes beneficios:

  • Flexibilidad: con la herencia la reutilización de código está fijado por la herencia. Es posible la circunstancia en que la clase hija solo necesite una parte de los métodos de la clase padre pero con el mecanismo de la herencia la clase hija los hereda todos o que solo una parte de las clases hijas necesitan los métodos adicionales. La herencia es habitualmente no suficientemente flexible.
  • Herencia múltiple: la herencia en Java solo permite extender de una única clase padre. Las interfaces y los métodos por defecto suplen en cierta medida la herencia múltiple pero también tienen limitaciones como no poder tener propiedades.
  • Evitar duplicidad: aún usando interfaces si no es a través de los métodos por defecto obliga a duplicar código en diferentes clases. La duplicidad de código por norma general es algo a evitar.

Inyección de dependencias

Los lenguajes de programación ofrecen un mecanismo para construir instancias, en Java es a través de la palabra reservada new y los constructores, las relaciones con otras instancias se establecen pasando sus referencias como argumentos del constructor o con los métodos de la instancia.

El recolector de basura de Java es el mecanismo de la máquina virtual de Java de liberar la memoria de las instancias cuando ya no hay más referencias accesibles por otras instancias, la recolección de basura se realiza de forma automática liberando al programador de hacer esta tarea de forma explícita lo que hace los programas más sencillos, con menos errores y ofreciendo un rendimiento similar y suficiente para la mayoría de los programas.

Una herramienta muy utilizada son los contenedores, uno de ellos en Java conocidos Spring, estos permiten delegar en ellos la construcción de las instancias junto con las relaciones con otras instancias a través de la inyección de dependencias.

El contenedor de objetos para la creación de las instancias y el recolector de basura para la liberación de la memoria permiten liberar al programador de realizar estas tareas de forma explícita.

» Leer más, comentarios, etc...

Picando Código

Siete días en el Picandoverso – Marzo 2021 V – Dark Fate

marzo 31, 2021 03:00

Llegamos al último día de Marzo de 2021, y la décima entrega de enlaces sobre Ruby, videojuegos, cómics y demás que denominaremos ‘siete días en el Picandoverso’. Estos últimos días tuve libre en el trabajo, tomándome días que me quedaron pendiente por no tomarme vacaciones el año pasado. Así que intenté aprovechar para no estar demasiado tiempo en la computadora, y en algunos momentos lo logré. Por suerte en los próximos meses se empiezan a flexibilizar las medidas de aislamiento en Escocia así que en breve empezaré a volver a tener más cosas para hacer fuera de mi apartamento.

Siete días en el Picandoverso - Marzo 2021 5

💎 Ruby

  • En RSpec fundamentals: a basic glossary, podemos encontrar una guía práctica de referencia para métodos de RSpec. También puede servir como introducción rápida a Rspec.
  • What is a Rails Model describe los modelos de Rails y cómo pensar en ellos fuera de Rails y con el concepto de modelo en general.
  • Gem in a box nos permite alojar gemas en un servidor propio con el mismo comportamiento que RubyGems. Podemos subir nuestras gemas ahí, y provee soporte para el API de bundler por lo que podemos usar este servidor cuando declaramos nuestras dependencias. No provee soporte para autenticación, eso queda delegado al servidor web o Rack.
  • Una gema que me resultó interesante y útil: credit_card_validations, permite validar números de tarjetas de crédito. Podemos usarla con un monkey patching de String 😱 o usando una clase Detector de la gema. También nos permite generar números válidos (útil para testing) y tiene soporte para plugins.
  • Se publicó una nueva versión de JRuby 9.2.17.0. Esta agrega características de compatibilidad, rendimiento, mejoras a la biblioteca estándar y más.
  • Debugging Ruby Libraries nos muestra algunas técnicas para depurar bibliotecas Ruby, como abrir el código fuente de una gema y más.

Tecnología

📝 Está disponible Emacs 27.2, es una versión de mantenimiento con arreglos de errores y ninguna funcionalidad nueva.

Creo que ya lo comenté en un ‘7 días’ anterior, pero cambié el tema de Emacs a Curry-On y estoy muy contento con el cambio. Está bueno ir alternando el tema cada tanto…

Videojuegos

El juego Ex-Zodiac tiene nuevo tráiler y se sigue viendo cada vez mejor. Aquellos que apoyamos el Kickstarter a partir de cierto monto, tuvimos la oportunidad de probar una versión nueva con el nivel de desierto que se muestra en el tráiler. Viene muy bien este juego, con apenas 4 niveles para probar en el demo, es todo lo que se esperaría de un remake moderno del Star Fox de Super Nintendo y más:

YouTube Video

Cómics

⚔ El próximo libro de los irreductibles galos va a ser Astérix tras las huellas del grifo.

El 21 de octubre de 2021, Astérix, Obélix e Ideafix estarán de regreso para disfrutar de su aventura número 39 en forma de historieta. Acompañados de Panorámix, se disponen a emprender un largo y enigmático viaje en busca de una extraña y terrorífica criatura.

¡Me tengo que poner al día! El último libro que leí fue Astérix en Italia, pero me saltié El papiro del César, y me falta también leer Astérix y la hija de Vercingetorix.

💬En cómics Marvel, esta semana sale el primer número de una mini-serie de 5 números de Beta Ray Bill. El arte se ve muy bueno, ya veré qué tal cuando me lleguen los cómics de hoy. Me viene doliendo leer Avengers por Jason Aaron. Después del excelente trabajo que hizo con Thor, no entiendo cómo sus historias y diálogos en uno de los libros principales de la compañía parecen escritos por un niño de 8 años… Thor por Donny Cates viene estando bastante bien, pero no se compara con el nivel que tenía justamente la tanda de Aaron. Amazing Spider-Man por Nick Spencer por fín levantó un poco en los últimos dos números que leí (61 y 62). Vemos un poco más de cosas Spider-Manescas, pero siempre recordándonos que existe ese bodrio casi infinito que ha sido Kindred hasta ahora… Por otro lado leí el primer número de Non-Stop Spider-Man por Joe Kelly, y es excelente, con un arte muy particular de Chris Bacalo. La serie Guardians of the Galaxy de Al Ewing llegó a un cierre con el número 12, pero a partir del 13 sigue al mando con un nuevo equipo y nueva dirección.

Daredevil por Chip Zdarsky, The Immortal Hulk por Al Ewing y Maestro: War & Pax por Peter David siguen manteniendo su excelente nivel.

Una notica que llegué a agregar momentos antes de salir a imprenta, el artista John Romita Jr. vuelve a Marvel después de pasar un buen tiempo dibujando a Superman para la Distinguida Competencia. Para mi gusto, Romita Jr. hizo alguna cosa buena en Amazing Spider-Man allá por los 90’s, pero no me gustó para nada lo que hizo en títulos más modernos. Incluso mirando imágenes de su Superman, no me gusta demasiado. Tiene un estilo bastante particular, para mí a veces la pega y a veces no. Pero bueno, vuelve a Marvel en Julio y seguramente le den alguno de los títulos “grandes”.

Relacionado a esto, Humble Bundle tiene un paquete de los mejores títulos de Boom Studios en 2020. De los títulos del bundle sólo leí y puedo recomendar We only find them when they’re dead, de Al Ewing. Una serie en el espacio donde mercenarios explotan recursos de los cuerpos de dioses muertos.

Televisión/Películas

Se estrenó el trailer de la quinta temporada de Rick and Morty, que se empieza a transmitir el 20 de junio:

YouTube Video

📺 Van 2 capítulos de The Falcon and The Winter Soldier. Arrancó muy bien y con el segundo se puso hasta mejor. Tremenda esta serie. Aprovechando la suscripción a Disney+ me puse a mirar la serie de Spider-Man de los 90’s, y no recordaba que estuviera tan buena. La calidad de la animación es genial y las historias respetuosas de los cómics. También empecé a mirar en paralelo Gargoyles por influencia de mi primo.

🎥 Se estrenó también el trailer de Suicide Squad de James Gunn y tiene muy buena pinta. Parece que no va a ser un bodrio abismal como la película anterior.

Picando Código

No recuerdo nada interesante para contar sobre mi estado mental de los últimos días, digamos que sigue decayendo de manera estable, y la pérdida de memoria es apenas uno de los síntomas. Potencialmente me recupere una vez que salgamos del aislamiento y vuelva a tener tantas de esas interacciones normales que el ser humano necesita para desarrollar su cerebro. Ya vengo notando un poco de mejora al encontrarme con amigos en parques y calles. Pero estamos bien, Fernando, yo, Fernandito, Fergus, el otro Fernando y los demás. Mandan saludos.

Marzo de 2021 fue un nuevo récord en cuanto a entradas en el blog en los últimos 10 años. Después de alcanzar la increíble cantidad de 17 posts en febrero, con éste post alcancé a publicar 24 en marzo y 1602 posts en total en Picando Código desde 2007 🤯

Otros 7 días en el Picandoverso:

Se pueden seguir los posts de Picando Código por RSS, Twitter (cuenta únicamente con posts del blog) y canal de Telegram. También estoy en Twitter y Mastodon, donde además de compartir lo que se publica en el blog publico alguna cosa más.

Tapadh leibh, chì mi thu a-rithist!
El post Siete días en el Picandoverso – Marzo 2021 V – Dark Fate fue publicado originalmente en Picando Código.

» Leer más, comentarios, etc...

Picando Código

NEOGEO POCKET COLOR SELECTION Vol. 1 en Nintendo Switch

marzo 31, 2021 10:00

El pasado 17 de marzo, SNK anunció la recopilación de 10 títulos clásicos de su consola portátil: NEOGEO POCKET COLOR SELECTION Vol.1, disponible en el Nintendo eShop para Nintendo Switch.

Neo Geo Pocket Color Selection Vol. 1

Ya se habían publicado 6 de éstos juegos individualmente en el eShop. Con esta selección obtenemos 4 más a un precio muy conveniente. Además de los clásicos de pelea, obtenemos dos títulos de la serie Metal Slug, Dark Arms y un juego de Golf.

Tenemos una interfaz muy buena desde donde podemos seleccionar entre los 10 cartuchos disponibles. Al seleccionar cada cartucho se nos presentan varias opciones: Jugar, ver la caja, ver el manual, elegir lenguaje y dispositivo:

NEOGEO POCKET COLOR SELECTION Vol. 1

Los manuales están todos súper completos, son particularmente útiles en los juegos de pelea para ver las reglas generales y los movimientos especiales de cada luchador. El lenguaje nos permite seleccionar entre inglés y japonés, además de ver el arte del cartucho localizado para cada idioma. Las cajas están modeladas en 3D, y podemos rotarlas manualmente y apreciarlas de todos los ángulos, así como vivir virtualmente la experiencia de abrir la caja y sacar el cartucho. Lograron muy bien esa sensación de una colección virtual de los cartuchos. Por último, podemos elegir jugar los juegos en modo “Neo Geo Pocket” en blanco y negro y modo color también.

Todos los juegos incluyen las características que ya pudimos apreciar en los juegos disponibles hasta ahora: rebobinar el juego, seleccionar entre varios diseños distintos de Neo Geo Pocket como borde, y alejar/acercar la pantalla. Un paquete de lujo, donde lo que más importa es la posibilidad de jugar estos títulos, pero todos los detalles extra le agregan valor al producto final. ¡Vamos a los juegos!

Metal Slug

Metal Slug es otra de las series clásicas de SNK que nunca podía faltar en las maquinitas. Así que no podíá faltar en la consola portátil. Se incluyen Metal Slug 1st Mission y su secuela Metal Slug 2nd Mission. Son para un sólo jugador, pero recrean todo lo bueno de la serie. Creo que lo que más destaco de todos los juegos en esta colección es cómo SNK logró mantener el espíritu de los títulos originales en estos ports a un dispositivo de hardware obviamente mucho menos poderoso (¡la batería en el Neo Geo Pocket Color duraba 40 horas!).

Las animaciones de los personajes se ven y se sienten muy fieles a las versiones originales. Podemos elegir entre dos personajes protagonistas para ir disparando a cuanto soldado nos encontremos y rescatando prisioneros. No faltan las típicas misiones comandando un tanque, avión, submarino y más.

[See image gallery at picandocodigo.net]

Juegos de pelea

SNK ha formado parte importante de la historia de los juegos de pelea. Fueron responsables de desarrollar muchos títulos clásicos y han aportado innovaciones que ayudaron a definir el género a lo largo del tiempo. En esta selección podemos apreciar un poco la variedad de éstos estilos, a pesar de estar adaptados al Neo Geo Pocket. No se trataba sólo de cambiar los sprites de un motor de pelea para seguir publicando títulos, cada serie tiene su personalidad y características que la hacen especial.

Tienen en común el estilo de los personajes con sprites en 8-bits más caricaturizados y escenarios pixelados aprovechando al máximo las limitadas capacidades y colores del hardware. El resultado final es muy bueno. Y como ya dije en reseñas anteriores, no hay que subestimar la profundidad que ofrecen a pesar de la apariencia de los personajes y el hecho de contar con solamente dos botones.

Los luchadores mantienen sus poderes originales y combos de títulos para consolas hogareñas y arcades. También agregan la posibilidad de desbloquear personajes escondidos. Así que hay contenido para rato.

Creo que además de ser disfrutables de por sí, y ser títulos que hay que conocer, sirven de entrada a otros juegos de SNK. Por lo menos en mi caso, me dieron ganas de probar más juegos de las mismas series de SNK al descubrir las mecánicas de cada uno. Así que también sería interesante ver más compilados de otros juegos de SNK que están disponibles en Nintendo Switch en el eShop (¡ya existe una para Samurai Shodown!).

[See image gallery at picandocodigo.net] Snk Gals’ Fighters – Este fue el primer juego que probé,  y pueden seguir el enlace para leer la reseña que le dediqué en Picando Código. Casi una colección en sí misma, un juego de peleas que incluye luchadoras de varios títulos distintos de SNK.

Samurai Shodown! 2 – La versión portátil del juego de pelea donde reemplazamos las piñas y patadas por espadas. Cada golpe se hace mucho más peligroso y mortal. Podemos elegir inicialmente entre 15 personajes distintos, cada uno con dos estilos de pelea. Además de la historia, tenemos la opción versus para jugar contra alguien más, y un modo colección. Al ir ganando peleas y campeonatos, obtenemos cartas con un arte distintivo y bonus que podemos equipar en nuestros luchadores. En su momento se podía intercambiar cartas entre dos Neo Geo Pocket Color.

King Of Fighters R-2 – Una excelente entrada en esta serie clásica de SNK, donde elegimos 3 personajes para crear un equipo de luchadores. Nos permite elegir de entre 23 personajes en total, incluyendo algunos escondidos, además de la posibilidad de editar un luchador.

The Last Blade: Beyond The Destiny – The Last Blade es una serie similar a Samurai Shodown. En las peleas usamos armas,  y cuenta con muchos aspectos de la mitología japonesa. Este port mantiene elementos del primer título de la serie, pero a medida que desbloqueamos cosas acumulando puntos, vamos viendo más finales y mini juegos. Podemos elegir inicialmente 9 personajes, pero hay varios escondidos. Incluye un modo historia, supervivencia y entrenamiento, además de batallas VS para jugar contra otras personas. Si nos interesa conocer más sobre la serie, SNK compartió un webcómic de The Last Blade.

Fatal Fury First Contact – Muy buena versión portátil de la legendaria saga de Fatal Fury. Incluye los personajes clásicos como Terry Bogard, Geese Howard y Mai Shiranui, así como personajes nuevos, y algunos personajes escondidos que tenemos que desbloquear. No incluye el sistema de dos planos de algunos Fatal Fury, por lo que es más fácil para principiantes.

Snk Vs. Capcom: The Match Of The Millennium – Otro de los títulos que ya había tenido la oportunidad de jugar. En el enlace está la reseña que publiqué en Picando Código.

Y más

Big Tournament Golf – El golf para mí es como el tenis: la única forma que lo encuentro divertido es como videojuego. Y Big Tournament Golf no es la excepción. Es un juego de golf al estilo arcade. Tenemos seis golfistas para elegir y podemos competir en varios modos: Stroke Play – elegimos un curso y jugamos 18 hoyos para obtener el mejor puntaje posible. Handicap – 18 hoyos en un escenario al azar para calcular el handicap en base al puntaje final. Triple Crown – Competencia en tres torneos distintos.

Los escenarios son variados y cuentan con obstáculos comunes como cuerpos de agua y partes con arena o pasto alto, así como también abismos entre la parte donde empezamos a jugar y el hoyo. Se ven muy bien y al igual que otros juegos de la colección, aprovechan de manera muy eficiente las capacidades del sistema. Tenemos varios palos para elegir dependiendo de la distancia y las condiciones del escenario.

Es un juego divertido y tranquilo. Además nos enseña un montón de términos de golf de los que no tenía idea.

[See image gallery at picandocodigo.net] Dark Arms Beast Buster 1999 – Dejé este juego para lo último porque fue el único con el que realmente no me logré entretener tanto. Es un juego de acción RPG, donde vemos al personaje desde una vista aérea y tenemos que ir disparándole a enemigos. Fue el único que no me resultó tan divertido y bien logrado como el resto, pero de repente no es mi estilo simplemente.

Conclusión

NeoGeo Pocket Color Selection Vol. 1 es una colección excelente. Recomendada para todo tipo de videojugadores. Nos permite disfrutar de una parte importante de la historia de los videojuegos, y es muy entretenida. La música 16 bits es genial, los gráficos pixelados son hermosos y los juegos están muy buenos. Me parece genial que estos títulos para una consola que no recibió suficiente atención en su momento puedan revivir un poco de gloria hoy en el Nintendo Switch.

Esta reseña está basada en la versión digital, pero la versión física estará disponible “pronto”. Me quedo a la espera para agregarla a mi colección, y veremos si se publica algún tipo de edición especial coleccionable 🙂

Otro detalle a tener en cuenta es que esta selección es el “volumen 1”, así que no sorprendería ver más selecciones de la biblioteca de juegos del Neo Geo Pocket Color en el futuro.

NeoGeo Pocket Color Selection Vol. 1 está disponible en la eShop versión Digital a USD 39.99 / MX$ 887.78 /39,99 €

YouTube Video

El post NEOGEO POCKET COLOR SELECTION Vol. 1 en Nintendo Switch fue publicado originalmente en Picando Código.

» Leer más, comentarios, etc...

Variable not found

Enlaces interesantes 437

marzo 29, 2021 06:05

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

Data

Machine learning / IA / Bots

Web / HTML / CSS / Javascript

Visual Studio / Complementos / Herramientas

Xamarin / Mobile

Otros

Publicado en Variable not found.

» Leer más, comentarios, etc...

Blog Bitix

Convertir texto o imagen a arte de caracteres ASCII

marzo 26, 2021 11:00

El arte ASCII es utilizar caracteres para obtener una composición que simula una imagen o dibujo. Es posible convertir texto a arte de caracteres ASCII o una imagen en formato svg, jpeg o png a texto. En GNU/Linux hay herramientas de línea de comandos que permiten crear arte ASCII tanto para texto como para imágenes. En internet también hay disponibles páginas que ofrecen el servicio de generar arte ASCII sin necesidad de instalar ningún software en la propia computadora.

GNU

Linux

Con la combinación adecuada de caracteres y varias líneas de texto es posible crear composiciones artísticas de texto, formando un arte ASCII basado en múltiples caracteres. El arte ASCII permite crear dibujos o convertir una frase en un texto en forma de dibujo.

El arte ASCII es adecuado para ser mostrado en interfaces basadas en texto como la terminal del sistema operativo. En GNU/Linux hay utilidades de línea de comandos que permiten crear arte ASCII, también hay páginas web que proporcionan la funcionalidad sin necesidad de instalar ningún software en el sistema.

Contenido del artículo

Texto a arte de caracteres ASCII

La herramienta figlet de linea de comandos permite convertir una frase a arte ASCII, es posible configurarla con diferentes estilos de fuente que producen resultados diferentes en el arte ASCII. Utilizando caracteres de escape de la terminal es posible añadir colores, Jansi es una librería Java que permite añadir colores a texto emitido en la terminal.

Además de instalar el paquete de figlet en la distribución de GNU/Linux hay que descargar los archivos de las fuentes para generar el arte ASCII con el estilo deseado. La fuente se indica en el comando con el parámetro -f.

1
2
3
4
5
6
$ figlet -w 240 "Blog Bitix"
$ figlet -f ~/Descargas/alphabet.flf -w 240 "Blog Bitix"
$ figlet -f ~/Descargas/3-d.flf -w 240 "Blog Bitix"
$ figlet -f ~/Descargas/lean.flf -w 240 "Blog Bitix"
$ figlet -f ~/Descargas/slant.flf -w 240 "Blog Bitix"
$ figlet -f ~/Descargas/univers.flf -w 240 "Blog Bitix"
figlet.sh
 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
Font: standard
 ____  _             ____  _ _   _
| __ )| | ___   __ _| __ )(_| |_(___  __
|  _ \| |/ _ \ / _` |  _ \| | __| \ \/ /
| |_) | | (_) | (_| | |_) | | |_| |>  <
|____/|_|\___/ \__, |____/|_|\__|_/_/\_\
               |___/

Font: alphabet
BBBB  l          BBBB      t
B   B l          B   B ii  t  ii
BBBB  l ooo ggg  BBBB     ttt    x x
B   B l o o g g  B   B ii  t  ii  x
BBBB  l ooo ggg  BBBB  ii  tt ii x x
              g
            ggg

Font: 3-d
 ******    **                    ******   **   **   **
/*////**  /**           *****   /*////** //   /**  //
/*   /**  /**  ******  **///**  /*   /**  ** ****** ** **   **
/******   /** **////**/**  /**  /******  /**///**/ /**//** **
/*//// ** /**/**   /**//******  /*//// **/**  /**  /** //***
/*    /** /**/**   /** /////**  /*    /**/**  /**  /**  **/**
/*******  ***//******   *****   /******* /**  //** /** ** //**
///////  ///  //////   /////    ///////  //    //  // //   //

Font: lean
    _/_/_/    _/                          _/_/_/    _/    _/      _/
   _/    _/  _/    _/_/      _/_/_/      _/    _/      _/_/_/_/      _/    _/
  _/_/_/    _/  _/    _/  _/    _/      _/_/_/    _/    _/      _/    _/_/
 _/    _/  _/  _/    _/  _/    _/      _/    _/  _/    _/      _/  _/    _/
_/_/_/    _/    _/_/      _/_/_/      _/_/_/    _/      _/_/  _/  _/    _/
                             _/
                        _/_/

Font: slant
    ____  __               ____  _ __  _
   / __ )/ /___  ____ _   / __ )(_) /_(_)  __
  / __  / / __ \/ __ `/  / __  / / __/ / |/_/
 / /_/ / / /_/ / /_/ /  / /_/ / / /_/ />  <
/_____/_/\____/\__, /  /_____/_/\__/_/_/|_|
              /____/

Font: univers
88888888ba   88                               88888888ba   88           88
88      "8b  88                               88      "8b  ""    ,d     ""
88      ,8P  88                               88      ,8P        88
88aaaaaa8P'  88   ,adPPYba,    ,adPPYb,d8     88aaaaaa8P'  88  MM88MMM  88  8b,     ,d8
88""""""8b,  88  a8"     "8a  a8"    `Y88     88""""""8b,  88    88     88   `Y8, ,8P'
88      `8b  88  8b       d8  8b       88     88      `8b  88    88     88     )888(
88      a8P  88  "8a,   ,a8"  "8a,   ,d88     88      a8P  88    88,    88   ,d8" "8b,
88888888P"   88   `"YbbdP"'    `"YbbdP"Y8     88888888P"   88    "Y888  88  8P'     `Y8
                               aa,    ,88
                                "Y8bbdP"
figlet.txt

Texto convertido a arte de caracteres ASCII

Imagen a arte de caracteres ASCII

También es posible convertir una imagen a arte ASCII, en el caso de las imágenes el resultado ha de tener un número adecuado de líneas y columnas para producir resultados con la suficiente definición para obtener resultados fieles a la imagen original.

La herramienta jp2a permite convertir una imagen a arte ASCII. Basta con indicar la imagen fuente y personalizar las opciones del resultado como la anchura de caracteres con la opción –width. Utilizando las tuberías del intérprete de comandos es posible combinar el resultado de un comando que procese o transforme la imagen y se la proporcione como entrada a jp2a, en este caso para utilizar formatos no soportado por jp2a convirtiéndolo previamente a uno soportado permite obtener el arte ASCII.

La herramienta jp2a combinada con el extraer un fotograma de una película permite generar el arte ASCII de un momento de una película.

1
2
3
4
5
6
7
$ jp2a --width=80 --invert ~/Descargas/blogbitix-750.png
$ jp2a --width=80 --invert ~/Descargas/blogbitix-750.jpg

$ convert ~/Descargas/archlinux.svg jpg:- | jp2a --width=80 --invert -
$ convert ~/Descargas/linux.svg jpg:- | jp2a --width=80 --invert -
$ convert ~/Descargas/gnu.svg jpg:- | jp2a --width=80 --invert -
$ convert ~/Descargas/gnome.svg jpg:- | jp2a --width=80 --invert -
jp2a.sh
  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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
                                      .                                        
                                       l'                                       
                                      coo.                                      
                                     :oooo.                                     
                                    ;oooool.                                    
                                   ,oooooool.                                   
                                  .oooooooool                                   
                                 ...;ooooooool.                                 
                                'ool:;:looooool.                                
                               'oooooooooooooool.                               
                              ,oooooooooooooooool.                              
                             ;oooooooooooooooooool.                             
                            ;oooooooooooooooooooool.                            
                           :ooooooool'.  .:ooooooooo.                           
                          cooooooooc       'ooooooooo'                          
                        .cooooooooo         ,ooooooooo;                         
                       .looooooooo:         .ooooooc:;:;                        
                      .loooooooooo:         .ooooooool;.                        
                     'oooooooooc;,.          ';:loooooool,                      
                    ,ooool:,..                    .';looooc                     
                   ;ol:'.                              .;col.                   
                  ''.                                      .,.                  
                            .ld.         :. ..                                  
  ..''..    ..  ..    ..    'kk.         o.                                     
 ,kxdxkkx' ;kkokko,okkkkkko.'kdokkkkxc.  o. '. .,.,,,,;.  ,.      :  ,.   .'    
 ,ccllckkd ;kkl. 'kko'. .,. 'kkc   .xko  o. ;. ,c      c. :'     .o   ;, ':     
okkc,;okkd ;kk'  ckk.       'kk.    xko  o. ;. ,;      :. :'     .o    'o,      
xko   .kkd ;kk'  'kkl.   .. 'kk.    dko  o  ;. ,,      c. :'     .l   .:.;'     
.dkkdxkoxd ;kk'   .okkxdkkd.'kk.    dko  o  :. ;,      c. 'c.  .';l  ;'   .;    
  .:c;.',. .,.       ,cc:.  .:,     c:.  .  .  ..      '   .:ll; ., ..     ..   

                                   .,:cllc:,.                                   
                               .lONMMMMMMMMMWXk:.                               
                             .OMMMMMMMMMMMMWkkKWWx.                             
                            .XMMMMMMMMMMMMMN0KNWMMN;                            
                            dMMMMMMMMMMMMMMMMMMMMMMW;                           
                            XMMMWNWMMMMMMMMMNXWMMMMMX                           
                           .MMNkxx0XMMMM0oc:lx0NMMMMMc                          
                           .MX.',..kMMMc  ,,. ,NMMMMMx                          
                           .WO,WOk.:WNX  OMKO. dMMMMMd                          
                            XN'0WK;:lco,.OMMN' xMMMMMd                          
                            0MO'c'''..''..;:'.:WMMMMMX                          
                            xXl'............,,'KMMMMMMc                         
                            lXl,.........,,,'':NMMKKNMN.                        
                            :Mdll;,,,,,,,',,'''kMMXxd0MO                        
                            OMc.;lc:;;;;;,.    .0MMMNWMMO.                      
                          .OMX.  .;::;,.         kMMMMMMMX'                     
                         cNMk.     ...            KMMMMMMMWl                    
                       .0MMx                      .NMMMMMMMMK.                  
                      oWMMK'                       ;WMMMMMMMMWc                 
                     kMMMNo;.      .        ..',;;,.lMMWWMMMMMM0.               
                    kMWMWl.                      .';.oMMNXNMMMMMK.              
                   xMNNMl                           ..oMMWNWWMMMMX.             
                  :MNNWc                               kWXNWKWMMMMX.            
                 .NNNW:                                ,MMMMWKMMMMMO            
                .XMWMO                                  XMMMMNMMMMMMc           
               .XMXWM;           '                      kMMMMWMMMMMMX           
              .NMMKNN            '                      xMMMXXMMMMMMM'          
              xMMMNKX           .'                      kMMWKWMMMMMMM'          
              'xc:o0K.          .'                      KWNNWWNNXKWMO           
             .......c0d.         .                  ....lMMMMMMMMX0d.           
            '........'kW0;                          '..'dMMMMMMMWx...           
      ....,,...........cNMNd.                     .':..'cd0XXXKk:....           
    .'..................;KMMM0;                   .;c'..',::::;'......          
    .'...................'xWMMMc                  .:l,..................        
    .,.....................lX0x'                  oKo;.....................     
    .,......................'.                 .cXMKl,......................    
    .........................,:'          .':dKMMMMkc'....................      
    .........................':kN0kxxkO0KNMMMMMMMMNo:'..............'...        
    ..,;;;;,,,'''...........',coNMMMMMMMMMMMMMMMMMKo:,'........',;,'...         
      ...',;::cccc;,,'''''',:cox0kddooolllccclodxOOol:;,,,,,;:c:;.....          
        ........',;::ccccccll:,..................'';oolllclll:'.....            
            ...........',,,'...              ........',,,,'.....                

           .,ccccllllllll,                                .;::::::;.            
        ,;;,'  .:;';loc::l:;,                          ',;;,,,. .'.''','        
     ,:;. .cKXNXollc;;o;.,' .''lo                  c,''..;;ldcddxkKkko .;:'     
   ;l' .0WMMd.;:,,,,'',,,,,''','                   .'.....''...''':;:XNKo 'c,   
  :;  xWMK;.'c,                                                   .;;':0MK: ,c  
 :,  cMMX; c,               .''''''''''      .'........              :,;NMX. 'c 
,c  :MMW..o.             .:;. .':clc;'.,:' .dl .,cc:'  ',.            ;':MMX  :,
o   oMMK.o.            .:, 'l0WMMMMMMMNo.,ldxOlkXXMMMNOc.';.           ;,NMX,  l
l  .0MMo.o            :; ;0MMMMMMMMMMMMMWd   ,c ,k0MMMMMNo.,:          ; kMW:  o
l  .OMMk.d          ;c.'0MMMMMMMMMMMMMMWNO    :  ,0MMMMMMMX:.;.        :.KMN:  o
o   cWMK'l;       ;c..xWMMMWN0xolloddl,. ':.   '''';lNOkKNMM0'',.     .,cWMK,  d
l' .:0MM; ;l'  .:c',kWNx;..      'l.    . .',';o.    o.   'dWWd.','..;,.xMMd. .d
.d  .xWMWN, ','::oKNd,       .d;0Mk     .co.  ,l; ;Kd.',    .OMW0o:.,,;NMMNc  o'
 ,c  c0MMMWNNodNMM0.        ,d. dc ....,.  '.     K0.. ;      dMMMM0NMMMMWd. :, 
  'c  'oNWMMMMMMM0.        ..      ..'';k   l.    O,,;::       kMMMMMWW0d.. c'  
   .l; ..,KxMNWW0.           .    dkkMMK,.   .    oONMNx.      .0MXKdd'.  ;c.   
     .:;.   ',oK.            ,    .,'dOo.          :K0x;         lX,  .',;.     
        ,;;;;;O;            c:        .. ..          o:;,         .k:,'         
             .O            lK;                        ::d;:,.      :l,.         
             co          ,d; ,             ',,,,.      :0. .,,,,,''':d,         
            :l         :o;    .          :xo:. .,:;.    ,c::::.                 
          .:d.   .,:cccK.                xXl.;;,.  ',..      .d                 
         cx;,,codW:.   x;         ..      .  xk,cc    .       k                 
         ;l;';' .W.    o:            .'  .       ..         .o;                 
                .W.    .xc             :;                .:cc.                  
                .N.     ,O             .d.             .''ll.                   
                 0;      clk.            l:                .O.                  
                 cd        ,lk.           .lcc;;;:::cldxk0xl.                   
                  x.        :x                ....       o;                     
                  .x.       .lcol,               ..',,,,,d.                     
                   .o;         ;lKc  .       'dXKkkNK:'..                       
                     ,c.        lX':OX'.           ol                           
                       ,,       lXl0MMWo         .  x'                          
                         ..      .:ONk0K'       l:;cl                           
                                   .kK.xWXl  cONWNl                             
                                  :d;. ;WMX.OMMMMMO'                            
                                   .   x:NMNXMMMMMMMWKc.                        
                                       . .dNNKWXd0WMKl                          
                                           .o;'cc..,,.                          

                                                      .',,'.                    
                                  ..             .ckXMMMMMMMNk.                 
                               ,OWMMWO.        .kMMMMMMMMMMMMMO                 
                              lMMMMMMMK       oWMMMMMMMMMMMMMMd                 
                    ,c:.     .WMMMMMMMN      kMMMMMMMMMMMMMMMK.                 
                  dWMMMW;    ,MMMMMMMMO     lMMMMMMMMMMMMMMMK.                  
                 lMMMMMMN.   .NMMMMMMW,     XMMMMMMMMMMMMMWo                    
                 oMMMMMMM;    lMMMMMMc     .MMMMMMMMMMMMMO.                     
          .,.    .XMMMMMM,     lWMMK,       KMMMMMMMMMWO,                       
        ,XMMM0.   .KMMMMK        '.         .XMMMMMW0l.                         
        NMMMMMK     cKW0.                     ,clc,                             
        OMMMMMMc                      ....                                      
        .0MMMMMx            .,cdk0XNWMMMMMMWNKko;.                              
          :0MMMc       .:d0NMMMMMMMMMMMMMMMMMMMMMM0:                            
            .'.     'oXMMMMMMMMMMMMMMMMMMMMMMMMMMMMMk                           
                  cKMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM.                          
                lNMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMN                           
              'XMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMN,                           
             'WMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWk.                            
             0MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWk.                              
            'MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMKl.                                
            ;MMMMMMMMMMMMMMMMMMMMMMMMMMMMWOl.                                   
            'MMMMMMMMMMMMMMMMMMMMMMMMMWk;                                       
             KMMMMMMMMMMMMMMMMMMMMMNx;                                          
             ;MMMMMMMMMMMMMMMMMMMO,                                             
              dMMMMMMMMMMMMMMMMK.          'lx0XNWNXOc                          
               oMMMMMMMMMMMMMMM.         ,NMMMMMMMMMMMl                         
                ;NMMMMMMMMMMMMM,         oMMMMMMMMMMMW.                         
                 .xMMMMMMMMMMMMWo.      .KMMMMMMMMMMW:                          
                   .OMMMMMMMMMMMMM0o:,;dNMMMMMMMMMMN,                           
                     'OMMMMMMMMMMMMMMMMMMMMMMMMMMMk.                            
                       .l0MMMMMMMMMMMMMMMMMMMMMWk.                              
                          .:xXMMMMMMMMMMMMMMWOc.                                
                              .,coxkO00Oxo:'                                    
                                                                                
                                                                                
                                                                                
       ;oxkxdc.  co'     oo'   .cdkkdc.    ;ooc    .ooo   ;ooooooo'  .:.,'.:    
     oWMXxoox0.  0MMd   .MMc  dWM0od0MMd   KMMM;   KMMM,  dMMKkkkk,   : :',;    
    lMMk         0MMMX' .MMc oMMl    oMMl .WMWMX  oMMMMl  dMM:                  
    OMM'  'dddd  0M0xMWc.MMc 0MM.    .MMO ,MMdKMl.WMdMMk  dMMNXXX,              
    xMM:  .odWM. 0Mk ,XMXMMc OMM'    ,MMx lMM,,MNKMO KMX  dMMd,,,.              
    .WMNc.  'WM. 0Mk  .OMMMc 'WMK'  ,KMN. OMW. xMMN. xMM. dMMo.....             
     .dXMMWMMWO  0Mk    :NMc  .xNMMMMNk.  NMK  .NMc  cMM: dMMMMMMMd             
         ....                    ....            .                              
jp2a.txt

Logotipo de Arch Linux convertido a arte de caracteres ASCII con jp2a Logotipo de Linux convertido a arte de caracteres ASCII con jp2a Logotipo de GNOME convertido a arte de caracteres ASCII con jp2a

Logotipo de GNU convertido a arte de caracteres ASCII con jp2a

Varios logotipos convertidos a arte de caracteres ASCII con jp2a

Páginas web de conversión a arte de caracteres ASCII

No es necesario instalar aplicaciones para generar tanto un texto en arte ASCII como convertir una imagen a arte ASCII, hay algunas páginas que ofrecen estas funcionalidades simplemente introduciendo el texto a convertir a arte ASCII como proporcionando la imagen a convertir a arte ASCII.

El resultado es un conjunto de caracteres que forman el arte ASCII. El propio buscador DuckDuckGo es capaz de generar el arte ASCII de figlet con la fuente standard, la página Online Ascii Tools permite convertir un texto a arte ASCII seleccionando la fuente o incluyendo una colección de arte ASCII y la página ASCII Generator permite convertir una imagen a arte ASCII.

Referencia:

» Leer más, comentarios, etc...

Blog Bitix

Autenticación con segundo factor de autenticación en SSH

marzo 26, 2021 04:00

El servicio SSH permite el acceso a equipos remotos a un usuario desde cualquier ubicación en la que se encuentre el usuario siempre que tenga conectividad desde el punto de acceso a internet y el equipo remoto. La autenticación se realiza mediante un usuario y contraseña o mediante clave privada y pública, adicionalmente SSH también se puede configurar para requerir un segundo factor de autenticación o 2FA que consituye una segunda clave.

GNU

Linux

Una forma de acceso a sistemas remotos para realizar tareas de administración es mediante SSH. La red permite acceder a sistemas remotos con SSH siempre que haya conectividad entre el la red del usuario y la red del servidor, con el auge de los servidores ofrecidos por los proveedores de hospedaje o los servicios de computación en la nube en la que lo servidores ya no son físicos sino lógicos SSH es la forma de acceder a los sistemas desde cualquier lugar.

SSH es un protocolo seguro y cifrado que utiliza como método de autenticación un usuario y contraseña o para mayor seguridad una clave SSH, también se puede configurar para añadir adicionalmente un segundo factor de autenticación o 2FA para mayor seguridad.

En el artículo específico comento como configurar SSH con autenticación mediante clave pública y privada, en otro artículo comento como tener acceso simple y seguro a sistemas remotos con Boundary.

Es recomendable usar segundo factor de autenticación en servicios como Google, Amazon y Paypal y otros relevantes que lo ofrezcan. También es recomendable utilizar un gestor de contraseñas como KeePassXC para guardar las contraseñas únicas y como aplicación para generar los tokens de 2FA.

Contenido del artículo

Instalar el módulo SSH de Google 2FA

Usar 2FA con SSH requiere instalar un módulo de autenticación que valide el proceso de autenticación. El módulo permite usar los tokens de un solo uso en el proceso de autenticación adicionalmente a la contraseña o clave SSH.

En los sistemas basados en Debian como Ubuntu hay que instalar el siguiente paquete que añade un nuevo módulo de PAM para 2FA.

1
2
$ sudo apt install libpam-google-authenticator

apt-install-libpam-google-authenticator.sh

Posteriormente hay que configurar SSH para que haga uso del módulo PAM de Google Authenticator añadiendo la siguiente línea en el archivo /etc/pam.d/sshd.

1
2
$ sudo vim /etc/pam.d/sshd

sshd.sh
1
2
auth required pam_google_authenticator.so

sshd-1

También hay que modificar el archivo de configuración de SSH /etc/ssh/sshd_config.

1
2
$ sudo vim /etc/ssh/sshd_config

sshd_config.sh
1
2
UsePAM yes
ChallengeResponseAuthentication yes
sshd_config-1

Configurar el módulo SSH de Google 2FA

La autenticación con 2FA es una segunda contraseña o código a introducir al iniciar sesión en el sistema remoto. Para utilizar 2FA hay que configurar previamente una aplicación que proporcione los códigos temporales.

El siguiente comando ejecutado con el usuario permite generar un código QR y la información para generar los tokens o configurar una aplicación como KeePassXC para generarlos. El comando realiza varias preguntas a las que se puede contestar con los siguientes valores.

  • Make tokens “time-base”: yes
  • Update the .google_authenticator file: yes
  • Disallow multiple uses: yes
  • Increase the original generation time limit: no
  • Enable rate-limiting: yes
 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
pi@raspberrypi:~ $ google-authenticator

Do you want authentication tokens to be time-based (y/n) y
Warning: pasting the following URL into your browser exposes the OTP secret to Google:
  https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/pi@raspberrypi%3Fsecret%3DZDLUAXH4UI3AJIX6EPHVQSVD5E%26issuer%3Draspberrypi
                                                                                  
                                                                                  
                                                                                  
                                                                                  
                                                                                  
Your new secret key is: ZDLUAXH4UI3AJIX6EPHVQSVD5E
Your verification code is 998007
Your emergency scratch codes are:
  46891237
  64319086
  49832138
  91155656
  34340292

Do you want me to update your "/home/pi/.google_authenticator" file? (y/n) y

Do you want to disallow multiple uses of the same authentication
token? This restricts you to one login about every 30s, but it increases
your chances to notice or even prevent man-in-the-middle attacks (y/n) y

By default, a new token is generated every 30 seconds by the mobile app.
In order to compensate for possible time-skew between the client and the server,
we allow an extra token before and after the current time. This allows for a
time skew of up to 30 seconds between authentication server and client. If you
experience problems with poor time synchronization, you can increase the window
from its default size of 3 permitted codes (one previous code, the current
code, the next code) to 17 permitted codes (the 8 previous codes, the current
code, and the 8 next codes). This will permit for a time skew of up to 4 minutes
between client and server.
Do you want to do so? (y/n) n

If the computer that you are logging into isn't hardened against brute-force
login attempts, you can enable rate-limiting for the authentication module.
By default, this limits attackers to no more than 3 login attempts every 30s.
Do you want to enable rate-limiting? (y/n) y
pi@raspberrypi:~ $ 
google-authenticator.sh

El resultado del comando es un código QR que se puede escanear con la aplicación de Google Authenticator para teléfono inteligente o con la clave secreta utilizar KeePassXC para generar los tokens.

Configuración de Google Authenticator Configuración OTP en KeePassXC Obtención de OTP en KeePassXC

Configuracón para Google Authenticator, KeePassXC y obtención OTP desde KeePassXC

Una vez modificada la configuración hay que reiniciar el servicio de SSH.

1
2
$ sudo systemctl restart sshd.service

sshd-restart.sh

Usar autenticación 2FA con claves SSH

Al utilizar la autenticación mediante claves públicas y privadas con la configuración por defecto es suficiente para otorgar acceso al sistema remoto, con lo que no se solicitará el segundo factor de autenticación.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
[picodotdev@archlinux ~]$ ssh-copy-id -i "/home/picodotdev/pico.dev@gmail.com" pi@192.168.1.101
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/picodotdev/pico.dev@gmail.com.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
(pi@192.168.1.101) Password: 
(pi@192.168.1.101) Verification code: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'pi@192.168.1.101'"
and check to make sure that only the key(s) you wanted were added.

[picodotdev@archlinux ~]$ 
ssh-copy-id.sh

Para que se pida el segundo factor de autenticación aún utilizando la autenticación mediante clave pública y privada hay que modificar la configuración de SSH de nuevo con los siguientes cambios de adicionales.

La siguiente línea del archivo /etc/pam.d/sshd ha de estar comentada de esta forma y añadir al final de archivo los métodos de autenticación.

1
2
#@include common-auth

sshd-2

Nuevamente hay que modificar el archivo /etc/ssh/sshd_config y añadir esta línea al final.

1
2
AuthenticationMethods publickey,keyboard-interactive

sshd_config-2

Y después reiniciar el servicio de SSH.

1
2
$ sudo systemctl restart sshd.service

sshd-restart.sh

Probar la autenticación SSH

Una vez realizada la configuración es recomendable probar que la autenticación se realiza de forma correcta tanto con usuario y contraseña como en el caso de claves. Una vez proporcionado el usuario y la contraseña se solicita el token del segundo factor de autenticación que es generado por la aplicación Google Authenticator, KeePassXC u otra aplicación configurada para generarlos.

En este caso realizando la autenticación con usuario y contraseña se solicita el token 2FA.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
[picodotdev@archlinux ~]$ ssh pi@192.168.1.101
(pi@192.168.1.101) Password: 
(pi@192.168.1.101) Verification code: 
Linux raspberrypi 5.10.17+ #1403 Mon Feb 22 11:26:13 GMT 2021 armv6l

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Fri Mar 26 16:49:20 2021 from 192.168.1.4

SSH is enabled and the default password for the 'pi' user has not been changed.
This is a security risk - please login as the 'pi' user and type 'passwd' to set a new password.

pi@raspberrypi:~ $ 
ssh-pi-password.sh

En este otro caso con clave privada y pública también se solicita el token 2FA.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
[picodotdev@archlinux ~]$ ssh pi@192.168.1.101
(pi@192.168.1.101) Verification code: 
Linux raspberrypi 5.10.17+ #1403 Mon Feb 22 11:26:13 GMT 2021 armv6l

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Fri Mar 26 16:47:26 2021 from 192.168.1.4

SSH is enabled and the default password for the 'pi' user has not been changed.
This is a security risk - please login as the 'pi' user and type 'passwd' to set a new password.

pi@raspberrypi:~ $ 
ssh-pi-pubkey.sh

» Leer más, comentarios, etc...

Variable not found

Analiza tu código a fondo y desde distintas perspectivas con NDepend

marzo 23, 2021 07:05

Como probablemente ya sabréis, NDepend es una de esas herramientas que están ahí de siempre, ayudando a desarrolladores y arquitectos a mejorar la calidad de nuestro software gracias a sus potentes y flexibles herramientas de análisis de proyectos.

Hace tiempo ya echamos por aquí un vistazo, pero creo que es interesante darle otra vuelta y refrescar conocimientos.

Qué es NDepend y en qué puede ayudarnos

NDepend de un analizador estático capaz de inspeccionar al detalle nuestros proyectos y ofrecernos métricas de calidad e información desde distintas perspectivas,tanto en tiempo de diseño como desde el interior de pipelines o procesos de build automatizados. Podemos usarlo desde línea de comandos, mediante un ejecutable standalone, o bien integrado en herramientas, como Visual Studio, Azure DevOps, TFS, TeamCity, AppVeyoor o SonarQube y otras.

Como otras soluciones, NDepend es capaz de analizar nuestro código y proponernos modificaciones sintácticas o consejos para alinearnos con buenas prácticas y convenciones habituales. Sin embargo, a diferencia de la competencia, NDepend permite obtener información bastante clarificadora sobre cómo evoluciona nuestra base de código y utilidades para mantener su calidad a raya durante el proceso de desarrollo, pues ofrece:

  • Información sobre la calidad del código que estamos introduciendo, relativo al nivel de calidad deseado o a un punto de partida establecido.

  • Estimación de deuda técnica o, en otras palabras, qué tiempo debemos dedicar al proyecto más adelante para solucionar problemas que estamos introduciendo en la actualidad. Aunque obviamente es una estimación, nos da una idea de la carga que suponen las prisas y el "dejar cosas para más adelante", y, sobre todo, nos permite ver su evolución en el tiempo e incidencia acumulada.

  • Configuración de criterios de calidad que deben cumplirse necesariamente durante la fase de desarrollo. Mediante expresiones LINQ, podemos realizar consultas a nuestro código y extraer conclusiones de forma realmente sencilla.

Pero donde NDepend destaca especialmente es en su conjunto de herramientas de visualización, que ofrecen perspectivas sobre nuestros proyectos que difícilmente podríamos lograr usando otras soluciones.

Al abrir un proyecto, ya sea seleccionando un archivo de solución (*.sln), proyecto (*.csproj), o incluso ensamblados independientes, tendremos acceso a un completo informe con las conclusiones más importantes obtenidas de su análisis. Para que os hagáis una idea de la información que podremos ver, en la web del producto tienen varios ejemplos de análisis de proyectos reales a los que vale la pena echar un vistazo, como:

Fijaos que en ambos casos se trata de comparaciones: NDepend no sólo realiza el análisis estático de la base de código actual, sino que puede compararla con versiones anteriores, o puntos de partida, para poder estudiar la evolución de distintos aspectos: tamaño, complejidad, problemas en el código, deuda técnica, porcentaje de cobertura de pruebas, etc.

La evolución, tanto de métricas predefinidas como de métricas personalizadas, puede analizarse de forma visual mediante las gráficas de tendencias. En ellas es posible observar cómo evolucionan los valores deseados a lo largo del tiempo y las distintas versiones del proyecto:

Gráfico de tendencias en NDepend

Por otra parte, el diagrama de dependencias es una de las grandes novedades de la última versión del producto, pues ha sido reimplementado desde cero para ofrecer mucha más potencia que en versiones anteriores. Este diagrama muestra la estructura de de un proyecto y las dependencias entre los principales bloques:

Diagrama de dependencias en NDepend

Este diagrama es interactivo, de forma que podemos ir profundizando sucesivamente hasta el máximo nivel de detalle y obteniendo interesantes métricas de cada bloque de código.

Otra forma de analizar las relaciones entre los bloques estructurales de un proyecto es a través de su matriz de dependencias. En esta matriz, las filas y columnas identifican los distintos componentes, mientras que en cada posición de la matriz veremos el grado de acoplamiento entre ambos. Este enfoque de análisis de dependencias puede ayudar a identificar valores anómalos en acoplamiento, cohesión, componentes con demasiadas responsabilidades, dependencias cíclicas, etc.

Matriz de dependencias en NDepend

Asimismo, es posible analizar el valor de distintas métricas sobre la superficie y estructura de la aplicación gracias al visualizador de métricas de código. Esta herramienta muestra un "mapa" de nuestro proyecto, sobre el que veremos los valores que nos interesen utilizando un código de colores para distinguir visualmente sus rangos de valores.

Análisis visual de la complejidad ciclomática

El nivel de granularidad es totalmente configurable (método, clase, namespace...), así como las métrica que decidirán la dimensión de los bloques y su color. Por ejemplo, en la gráfica anterior, cada cuadro representa un método, su tamaño viene definido por el número de líneas de IL que contiene, y el color por su complejidad ciclomática. De esta forma, podremos tener una idea muy rápida de dónde se encuentran los "puntos calientes", o las partes de nuestra aplicación más complicadas.

También es impresionante la capacidad de combinar los informes, gráficas, definición de reglas y otras funcionalidades con la posibilidad de utilizar queries sobre nuestra base de código usando LINQ. Por ejemplo, una consulta como la siguiente podría ser útil para filtrar los métodos con complejidad elevada en un informe:

from m in JustMyCode.Methods
where m.CyclomaticComplexity > 20
select new { m, m.CyclomaticComplexity, m.NbLinesOfCode }

O bien, para definir reglas de calidad de código personalizadas. En el siguiente código se configura una regla que lanzará un warning cuando tenemos más de un método con una complejidad elevada:

warnif count > 0 
from m in JustMyCode.Methods
where m.CyclomaticComplexity > 20
select new { m, m.CyclomaticComplexity, m.NbLinesOfCode }

En conjunto, todas estas herramientas pueden ser de gran utilidad en distintos escenarios, como en:

  • Mejorar la arquitectura de un proyecto
  • Mejorar la calidad de código
  • Comprender una base de código heredado
  • Auditar código externo
  • Analizar el impacto de refactorizaciones antes de acometerlas
  • Detectar dónde se concentra la complejidad de una base de código
  • Detectar breaking changes que afectarán a APIs
  • Detectar y eliminar código muerto
  • ... y muchos otros

NDepend es software comercial y tiene coste por licencia, pero podéis descargar una versión de prueba de 14 días para comprobar si os puede resultar útil. Os recomiendo que le deis una oportunidad y lo probéis con algunos de vuestros proyectos, porque seguro que váis a aprender bastante sobre ellos ;)

Publicado en Variable not found.

» Leer más, comentarios, etc...

Variable not found

Enlaces interesantes 436

marzo 22, 2021 07:05

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

Data

Machine learning / IA / Bots

Web / HTML / CSS / Javascript

Visual Studio / Complementos / Herramientas

Xamarin

Otros

Publicado en Variable not found.

» Leer más, comentarios, etc...

Una sinfonía en C#

Observables en Javascript RXjs ¿Qué es un Subject?

marzo 22, 2021 12:00

En este cuarto y último post sobre Observables en Javascript vamos a ver el último tema que, según mi opinión, forma parte de los conceptos más básicos para comprender los observables. Vamos a hablar de Subjects. Si no has leídos los posts anteriores dejo la lista:

¿Qué es un Subject?

En pocas palabras, es un objeto que permite crear un observable para controlarlo manualmente, por ejemplo.

// Creamos un subject que emitirá _strings_
let subject = new Subject<string>();
// nos suscribimos
subject.subscribe({
    next: (value) => {
        console.log(value);
    }
});
// invocamos manualmente el método next y emitimos un valor
subject.next('Hola');

En el ejemplo de arriba vemos el funcionamiento más básico de Subject, crear un observable que podemos controlar, luego nos suscribimos y el resultado es el esperado, emite un valor cuando invocamos manualmente el método next.

Hola

Crear nuestros propios observables y controlarlos

Entonces, podríamos tranquilamente hacer algo así:

let subject = new Subject<number>();

subject.subscribe({
    next: (value) => console.log(value),
    complete: () => console.log('complete'),
    error: (value) => console.log('Error ' + value)
});

let i = 0;
let counter = 0;
let interval = setInterval(()=>{
    i++;
    if(i === 10){
        counter++;
        i = 0;
        subject.next(counter);
    }
}, 200);

document.querySelector("#stopButton")?.addEventListener("click", ()=>{
    subject.complete();
    clearInterval(interval);
});

document.querySelector("#errorButton")?.addEventListener("click", ()=>{
    subject.error("Mi Error custom");
});

Y vemos que el resultado es el esperado, hasta que presionamos Stop y se ejecuta el complete

1 
2 
3 
4 
complete

Si en lugar de Stop forzamos un error el Subject deja de emitir también.

1 
2 
3 
4 
5 
6 
7 
Error Mi Error custom

Controlar otros observables

El último ejemplo que es el más interesante es que, ya que los operadores son observables (o funciones que retornan observables) podemos utilizar un Subject para controlar otros Observables, por ejemplo.

let onStop = new Subject<void>();

// creamos un observable del evento click de un botón
// agregamos un operador TakeUntil para que deje de recibir eventos cuando onStop finalice.
const observer = {
    next: (item : any) => console.log(` X:${item.clientX} Y:${item.clientY}`),
    complete: () => console.log("complete"),
    error: () => console.log("error")
};

let onStop = new Subject<boolean>();

fromEvent(document, "click").pipe(takeUntil(onStop)).subscribe(observer);

document.querySelector("#stopButton")?.addEventListener("click", ()=>{
    onStop.next(true);
});

En el ejemplo de arriba simplemente controlamos el takeUntil gracias a nuestro Subject, cuando se next es true. La idea de hacerlo así es que un evento proveniente de otro lugar puede detener a un evento diferente. O que si lo hacemos manualmente (por ejemplo el usuario hace click) podemos detener un flujo de ejemplos o varios, recordemos que un Subject al igual que cualquier Observable controla múltiples suscripciones.

Nada más por hoy, nos leemos.

» Leer más, comentarios, etc...

Una sinfonía en C#

marzo 20, 2021 11:09

En este cuarto y último post sobre Observables en Javascript vamos a ver el último tema que, según mi opinión, forma parte de los conceptos más básicos para comprender los observables. Vamos a hablar de Subjects. Si no has leídos los posts anteriores dejo la lista:

¿Qué es un Subject?

En pocas palabras, es un objeto que permite crear un observable para controlarlo manualmente, por ejemplo.

// Creamos un subject que emitirá _strings_
let subject = new Subject<string>();
// nos suscribimos
subject.subscribe({
    next: (value) => {
        console.log(value);
    }
});
// invocamos manualmente el método next y emitimos un valor
subject.next('Hola');

En el ejemplo de arriba vemos el funcionamiento más básico de Subject, crear un observable que podemos controlar, luego nos suscribimos y el resultado es el esperado, emite un valor.

Hola

Crear nuestros propios observables y controlarlos

Entonces, podríamos tranquilamente hacer algo así:

let subject = new Subject<number>();

subject.subscribe({
    next: (value) => console.log(value),
    complete: () => console.log('complete'),
    error: (value) => console.log('Error ' + value)
});

let i = 0;
let counter = 0;
let interval = setInterval(()=>{
    i++;
    if(i === 10){
        counter++;
        i = 0;
        subject.next(counter);
    }
}, 200);

document.querySelector("#stopButton")?.addEventListener("click", ()=>{
    subject.complete();
    clearInterval(interval);
});

document.querySelector("#errorButton")?.addEventListener("click", ()=>{
    subject.error("Mi Error custom");
});

Y vemos que el resultado es el esperado, hasta que presionamos Stop y se ejecuta el complete

1 
2 
3 
4 
complete

Si en lugar de Stop forzamos un error el Subject deja de emitir también.

1 
2 
3 
4 
5 
6 
7 
Error Mi Error custom

Controlar otros observables

El último ejemplo que es el más interesante es que, ya que los operadores son observables (o funciones que retornan observables) podemos utilizar un Subject para controlar otros Observables, por ejemplo.

let onStop = new Subject<void>();

// creamos un observable del evento click de un botón
// agregamos un operador TakeUntil para que deje de recibir eventos cuando onStop finalice.
const observer = {
    next: (item : any) => console.log(` X:${item.clientX} Y:${item.clientY}`),
    complete: () => console.log("complete"),
    error: () => console.log("error")
};

let onStop = new Subject<boolean>();

fromEvent(document, "click").pipe(takeUntil(onStop)).subscribe(observer);

document.querySelector("#stopButton")?.addEventListener("click", ()=>{
    onStop.next(true);
});

En el ejemplo de arriba simplemente controlamos el takeUntil gracias a nuestro Subject, cuando se next es true. La idea de hacerlo así es que un evento proveniente de otro lugar puede detener a un evento diferente. O que si lo hacemos manualmente (por ejemplo el usuario hace click) podemos detener un flujo de ejemplos o varios, recordemos que un Subject al igual que cualquier Observable controla múltiples suscripciones.

Nada más por hoy, nos leemos.

» Leer más, comentarios, etc...

Blog Bitix

Análisis de la serie de juegos de plataformas Trine

marzo 20, 2021 08:00

La serie de juegos Trine destacan por su nivel artístico gráfico y como juego de plataformas con puzles, incluso el primer Trine destaca en esto. Los juegos están basados en las aventuras de tres personajes un caballero, un mago y una ladrona cuya historia es narrada antes de cada nivel y está completamente doblada al español. El objetivo es llegar al final de cada nivel empleando una combinación de habilidades de cada personaje pero para darle más diversión al juego es posible completarlo con varios niveles de dificultad o como objetivos adicionales encontrar todo los orbes de experiencia, algunos de los cuales están un poco escondidos.

Trine: Enchanted Edition es un juego de plataformas desarrollado por Frozenbyte en el año 2009 y remasterizado en el 2014, con posterioridad se ha publicado varios más que continúan la historia del primero, Trine 2: Complete Story (2013), Trine 3: The Artifacts of Power (2015) y Trine 4: The Nightmare Prince (2019). Estos juegos están disponibles tanto para consola como para PC.

Cada juego de la colección de Trine tiene algunas pequeñas diferencias aún siendo los conceptos básicos del original los mismos en todos, el más diferente es Trine 3 que adopta un modo de juego más en tres dimensiones y con más libertad de movimientos. Son juegos principalmente de plataformas, de aventuras, resolver puzles y con un pequeño componente de rol de elegir habilidades en cada personaje u objetos. Los juegos de Trine destacan por su apartado gráfico y banda sonora que incluso el primero de la colección tiene un nivel de detalles gráficos notable.

Debido a que son juegos ya con varios años en las diferentes tiendas digitales en cada plataforma se encuentra a un precio de unos pocos euros, los tres primeros se distribuyen como una colección siendo aún así bastante baratos.

Pantalla inicial y menú Pantalla inicial y menú Pantalla inicial y menú

Pantalla inicial y menú Pantalla inicial y menú Pantalla inicial y menú

Pantalla inicial y menú Pantalla inicial y menú Pantalla inicial y menú

Pantalla inicial y menú

Anticipación del juego

Este artículo contiene información de estrategias para completar más fácilmente el juego, parte de la diversión de un juego es descubrir y superar los retos que se plantean por uno mismo. Sin embargo, algunos juegos son difíciles sin una pequeña ayuda que obliga a tener que dedicarles mucho más tiempo o a recomenzarlos.

En algunos juegos el argumento es una de las partes más importantes. El texto del artículo no contiene información acerca del argumento del juego, de la mitad o del final, ni hace ningún spoiler por lo que lo puedes leer sin riesgo de conocer alguna parte del argumento de forma anticipada. Sin embargo, algunos enlaces del artículo a otras páginas y vídeos sí pueden contener información del argumento de modo que recomiendo consultar solo las partes del juego una vez superadas.

Contenido del artículo

El juego

Los juegos en toda la saga narran la historia de tres personajes Pontius un caballero, Amadeus un mago y Zoya una ladrona. Al inicio de cada nivel hay una narración que sirve como hilo conductor del juego e incluso dentro de los niveles los personajes conversan haciendo algún comentario con un toque de humor, los juegos Trine poseen un buen doblaje al español.

Inicio de nivel en Trine 1 Inicio de nivel en Trine 2

Inicios de nivel en Trine 1 y 2

El juego consiste en llegar al final de cada uno de los niveles, recoger los orbes de experiencia y abrir los cofres del tesoro. La dificultad radica en que algunos orbes y cofres están un poco escondidos con lo que es necesario fijarse bien en cada sección del nivel para descubrirlos, también en que algunas secciones requieren de la combinación de los personajes y emplear sus habilidades para continuar a la siguiente sección.

Recoger los orbes de experiencia otorgan puntos de habilidad para emplearlos en ganar habilidades en los personajes. En cada uno de los juegos las habilidades varían, por ejemplo, en Trine los personajes tienen tres habilidades cada uno con varios niveles y un inventario de objetos. En Trine 2 los personajes no tienen inventario y las habilidades están organizadas en un árbol.

Habilidades de personajes en Trine 1 Habilidades de personajes en Trine 1 Habilidades de personajes en Trine 2

Habilidades de personajes en Trine 1 y 2

En algunos niveles se encuentran varios enemigos, en Trine son esqueletos y en Trine 2 son duendes. En algunos niveles hay jefes enemigos que para eliminarlos hay que emplear una táctica según su comportamiento, variedad de ataques o descubrir sus puntos vulnerables para hacerles daño.

Jefe enemigo de Trine 1 Jefe enemigo de Trine 2

Jefes enemigos de Trine 1 y 2

Posee varios niveles de dificultad que hacen que los enemigos tengan más vida, los personajes reciban más daño al sufrir heridas o al llegar a ciertos puntos de control los personajes no se curen completamente y sus resurrecciones estén limitadas. En caso de que los tres personajes mueran se ha de reiniciar el nivel desde el principio en el modo hardcore, si un personaje muere al llegar a ciertos puntos de control los personajes muertos reviven y se puede continuar. Aunque los personajes puedan resucitar obliga a llegar hasta el siguiente punto de control sin los personajes restantes lo que dificulta continuar avanzando al no poder emplear las habilidades de los personajes muertos.

El juego soporta un modo cooperativo entre varios jugadores que pueden jugar simultáneamente en la misma partida con varios mandos. Se hace uso de físicas para interactuar con los objetos objetos, utiliza la tecnología Nvidia PhysX que da más realismo en el comportamiento físico de los objetos. Los tiempos de carga son más bajos que en otros juegos debido a que el juego no requiere grandes recursos.

Diferencias entre los juegos de la serie Trine

Los juegos de Trine en realidad no son juegos completamente distintos sino que más bien cada uno de ellos es una nueva colección de niveles con algunos aspectos cambiados de los personajes.

Mientras que en Trine 1 y Trine 2 el aspecto del juegos es más bien en dos dimensiones o 2D o 2.5D en Trine 3 es el primer juego de la serie con una jugabilidad en 3D. Trine 4 recupera el estilo de juego de los dos primeros 2D.

En Trine hay 16 niveles con unos 25 orbes de experiencia por nivel, en Trine 2 hay 20 niveles y un número mayor de orbes de experiencia que puede llegar a los 75. En Trine hay una barra de magia que desaparece en Trine 2.

Niveles de Trine 1 Niveles de Trine 2 Niveles de Trine 3

Niveles de Trine 1, 2 y 3

Objetivos del juego

El juego básicamente es un juego de plataformas en el que en alguno puntos hay que resolver sencillos puzles con las habilidades combinadas de los personajes. Si la solución para resolver un puzle es demasiado complicada es que esa forma de resolverlo no es la que pensaron los desarrolladores, dados los diferentes personajes y sus habilidades hay múltiples formas válidas de resolver cada puzle. Otro objetivo del juego es recoger todos los orbes de experiencia y encontrar los cofres de tesoro, algunos están un poco escondidos con lo que es necesario fijarse bien en cada una de las secciones de los niveles, después de los primeros niveles se va conociendo que sitios son susceptibles de tener alguna zona oculta a explorar.

El juego posee varios niveles de dificultad y un modo hardcore, para conseguir todos los objetivos del juego hay que completar cada nivel en el mayor nivel de dificultad y en el modo hardcore.

Arte gráfico y banda sonora

Los juegos de Trine destacan por su nivel artístico lleno de detalles, colores vivos, brumas y efectos de luz que los hacen interesantes para disfrutar de su aspecto gráfico. El hecho de que para encontrar los orbes y tesoros haya que fijarse en cada una de las secciones refuerzan el disfrutar del aspecto artístico y ser consciente del mismo.

Incluso el primer Trine tiene unos detalles gráficos muy notables, mejorados en Trine 2 y que en la versión de Trine 4 alcanzan su mayor esplendor. Además del aspecto gráfico el juego se complementa con una banda sonora destacable y variada, combinado con su jugabilidad hacen del juego una muy buena experiencia.

Arte gráfico de Trine 1 Arte gráfico de Trine 1

Arte gráfico de Trine 2 Arte gráfico de Trine 2

Arte gráfico de Trine 3

Arte gráfico de Trine 1, 2 y 3

A lo largo de las diferentes versiones y con el paso de los años el arte gráfico ha mejorado en algunos aspectos pero incluso en la versión de Trine 1: Enchanted Edition el aspecto gráfico en la PlayStation 4 es admirable.

Historia

El juego se desarrolla con una pequeña historia lineal como hilo conductor al inicio de cada nivel que dan sentida a las aventuras de los personajes y niveles. No es una historia muy elaborada ni diferentes lineas argumentales pero completa con su papel en el juego con suficiencia. En estos vídeos están los inicios de las historias.

Banda sonora original

La banda sonora enriquece el juego estando a la altura del arte gráfico, completa el juego en el aspecto del audio.

Ubicación de los orbes de experiencia y cofres

Algunos de los orbes de experiencia y los cofres del tesoro están escondidos, con la experiencia de juego uno se fija donde pueden estar y encontrarlos requiere explorar de forma completa los rincones escondidos de cada sección. Aún así quizá alguno se resista el encontrarlo, algunos niveles son un poco largos con lo que intentar encontrarlos requiere tiempo y aún así cuesta recogerlos todos, en caso de querer obtenerlos todos en YouTube hay vídeos donde se muestra la ubicación de cada uno de ellos.

En los siguientes enlaces se pueden ver todos los orbes, objetos coleccionables y cofres en los diferentes niveles.

» Leer más, comentarios, etc...

Bitácora de Javier Gutiérrez Chamorro (Guti)

El curioso bug de QB64 (on error)

marzo 19, 2021 10:35



Hace unas semanas me comentaban un curioso bug en QB64. Una herramienta de desarrollo de la que a modo de curiosidad fui de los primeros en evaluar en 2010, pero que nunca llegué a recomendar como herramienta de tipo profesional. Tanto por sus características, por como ha quedado comprobado por su soporte. Debido a la …

El curioso bug de QB64 (on error) Leer más »



Artículo publicado originalmente en Bitácora de Javier Gutiérrez Chamorro (Guti)

» Leer más, comentarios, etc...

Una sinfonía en C#

Observable en Javascript y RxJs, MergeMap y SwitchMap

marzo 15, 2021 12:00

En los dos posts anteriores comenzamos a aprender sobre observables y ver algunos operadores, los más “normales” que funcionan más como filtros, ahora vamos a ir un paso más allá revisando MergeMap y SwitchMap que permiten hacer cosas más interesantes.

MergeMap y SwitchMap

Estos operadores son algo complejos de comprender al principio y de entender sus diferencias, pero intentaremos resumirlo.

Ambos permiten controlar un observable a partir de los elementos de otro, de este modo podemos generar un tercer observable como resultado (o devolver el segundo observable modificado).

Por ejemplo

import { from, fromEvent, interval, Observable, of, Subject, throwError, timer } from 'rxjs';
import { map, mergeMap, switchMap, take, tap } from 'rxjs/operators';

// se genera un objeto que sea el observer de cada evento del observable
const observer = {
    next: (item : any) => {console.log("next " +  item)},
    complete: () => {console.log("complete")},
    error: () => {console.log("error")}
}

// se crea un observable a partir de la acción click de un botón
var obsevableButton = fromEvent(document.querySelector("#startButton"), "click");
// se crea un segundo observable que es un interval cada 1 segundo que se ejecuta 10 veces
var observableInterval = interval(1000).pipe(take(10));

// utilizamos MergeMap sobre el click del botón
// dentro del MergeMap colocamos el segundo observable como valor de retorno del MergeMap
// y colocamos tap para escribir por consola los valores del primero y segundo observable
obsevableButton.pipe(mergeMap((first)=> {
    return observableInterval.pipe(tap((i)=>{
        console.log("primero " + JSON.stringify(first));
        console.log("segundo " + i);
    }))
}
)).subscribe(observer);

Vamos a analizar el código lentamente. Si lo ejecutamos (haciendo click en el botón) comienza a funcionar el segundo observable, primera cosa interesante

MergeMap inicia el segundo observable al ejecutarse el primero

Entonces, como mínimos podemos usar MergeMap para iniciar otro observable.

Y esto, además, nos permite dentro del MergeMap, por ejemplo, hacer un map (o aplicar cualquier operador) de los dos observables y devolver el resultado

var obsevableButton = from([2]);
var observableInterval = interval(1000).pipe(take(5));

obsevableButton.pipe(mergeMap((first)=> {
    return observableInterval.pipe(map((second)=> first * second));
}
)).subscribe(observer);

En este caso el resultado es la multiplicación del valor multiplicado por 0, 1, 2, 3, 4.

next 0
next 2
next 4
next 6
next 8
complete

Perfecto, es decir, a partir de recibir un valor con MergeMap podemos retornar un nuevo observable, y esto nos permite controlar la ejecución del segundo a partir de lo que hace el primero. Agregando algún operador como map (o el que sea) dentro podemos hacer que ese observable sea el resultado de “mezclar” ambos. Excelente.

Perooo, qué pasa si en el primer ejemplo presionamos el botón más de una vez, o lo que es igual, el primer observable retorna más de un valor.


obsevableButton.pipe(mergeMap((first)=> {
    return observableInterval
    .pipe(tap((element) => console.log("segundo observable: " + element + " primer observable: " + first)))
    .pipe(map((second)=> first * second));
}
)).subscribe(observer);

Lo que pasa es que tenemos ambos resultados, segunda conclusión:

Con MergeMap cada elemento en el primer observable dispara el segundo de nuevo, genera una nueva suscripción

segundo observable: 0 primer observable: 2 
next 0
segundo observable: 0 primer observable: 8 
next 0
segundo observable: 1 primer observable: 2 
next 2
segundo observable: 1 primer observable: 8 
next 8
segundo observable: 2 primer observable: 2 
next 4
segundo observable: 2 primer observable: 8 
next 16
segundo observable: 3 primer observable: 2 
next 6
segundo observable: 3 primer observable: 8 
next 24
segundo observable: 4 primer observable: 2 
next 8
segundo observable: 4 primer observable: 8 
next 32
complete

Y cuál es la diferencia entre MergeMap y SwitchMap

Bien, es poca pero muy importante

A diferencia de MergeMap, si el primer observable retorna un nuevo valor SwitchMap cancela la suscripción actual, no existe la posiblidad de que haya ejecuciones en paralelo como con MergeMap.

El mismo ejemplo de recién en SwitchMap

obsevableButton.pipe(switchMap((first)=> {
    return observableInterval
    .pipe(tap((element) => console.log("segundo observable: " + element + " primer observable: " + first)))
    .pipe(map((second)=> first * second));
}
)).subscribe(observer);

El resultado sería:

segundo observable: 0 primer observable: 8
next 0
segundo observable: 1 primer observable: 8
next 8
segundo observable: 2 primer observable: 8
next 16
segundo observable: 3 primer observable: 8
next 24
segundo observable: 4 primer observable: 8
next 32
complete

El primer valor del primer observable (el 2) no se llega a ver porque ocurre inmendiatamente y es cancelado por el segundo valor antes que transcurra el tiempo (1 segundo) que tiene el segundo observable para generar cada valor y hacer el map, vamos a cambiar un poco las cosas para verlo

// generamos un observable de dos valores cada uno cada 1,5 segundos.
var obsevableButton = interval(1500).pipe(take(2));
// se crea un segundo observable que es un interval cada 1 segundo que se ejecuta 5 veces
var observableInterval = interval(1000).pipe(take(5));

obsevableButton.pipe(switchMap((first)=> {
    return observableInterval
    .pipe(tap((element) => console.log("segundo observable: " + element + " primer observable: " + first)))
    .pipe(map((second)=> first * second));
}
)).subscribe(observer);

Y en este caso se aprecia que al pasar 1,5 segundos el primer valor (el 0) del primer observable ya no genera resultados y vemos un único resultado a partir del 0 y el resto a partir del 1. Es decir que el observable generado por SwitchMap gracias al primer valor del primer observable se ha cancelado.

segundo observable: 0 primer observable: 0
next 0
segundo observable: 0 primer observable: 1
next 0
segundo observable: 1 primer observable: 1
next 1
segundo observable: 2 primer observable: 1
next 2
segundo observable: 3 primer observable: 1
next 3
segundo observable: 4 primer observable: 1
next 4
complete

Por qué usar uno o el otro?

Bien, en mi experiencia he usado más SwitchMap porque es muy común al hacer llamadas HTTP, por ejemplo, si un usuario presiona un botón y eso general un request y eso general un llamada HTTP es muy probable que querramos cancelar esa llamada (ese observable) si el usuario hacer click otra vez antes que finalice. Un buen ejemplo es una caja de búsqueda con autocomplete, cada vez que el valor cambie queremos cancelar la llama anterior.

Espero que haber sido claro, nos leemos.

» Leer más, comentarios, etc...

Mascando Bits

Inclusión de aportes mediante las diferentes estrategias de Merge en Git

marzo 11, 2021 08:10

Cada vez suele ser más normal ver la figura del ingeniero de software que se dedica a la gestión de proyectos, gestionando las ramas de desarrollo (develop & features) y la rama estable master (recientemente normalizada como main).

Imagen obtenida de la presentación Desarrollo Colaborativo de Software

Muchas veces sin querer se usan las herramientas de «merge» de código de manera incorrecta sin pararse a pensar en los beneficios y «contraprestaciones» que puede tener hacerlo de una forma u otra. Es por ello que este artículo, pretende arrojar algo de luz en qué nos puede convenir hacer en cada momento.

Antes de nada vamos a aclarar la notación para que resulte todo más sencillo. Nos referiremos a la rama Base, como la rama a la que se desea fusionar los cambios en el proceso de merge. Por otro lado nos referiremos a la rama Head como la rama que contiene los cambios que queremos incluir en la rama Base. Estos cambios en términos de plataformas para el desarrollo colaborativo de software como GitHub, GitLab, Bitbucket o Gogs, se suele aplicar con frecuencia en los conocidos como Pull Request (PR). Una solicitud formal a la inclusión de código de un desarrollador o grupo de desarrolladores externo al equipo de desarrolladores de un repositorio, la cual puede ser revisada y probada antes de realizar el merge.

La rama Base más habitual es la master o main que es asumida además como rama estable del desarrollo en un repositorio de manera generalizada. Los puntos más estables y que deberías usar son los denominados Tags de versión que son puntos específicos donde se ha trabajado una estabilidad específica que suele cerrar una iteración de desarrollo que incluye mejoras y soluciones a fallos conocidos desde la anterior versión.

Porque sale fuera de alcance de este artículo, no mencionaremos toda la problemática y gestión inherente que puede aparecer en forma de conflicto cuando realizamos un merge de código. Conflictos que deberán ser resueltos para asegurar la coherencia y estabilidad de la rama Base. Y que dicho sea de paso, suelen ser producidos muchas veces por falta de comunicación o por no ser «aséptico» en la forma de programar, refactorizando el código más de la cuenta o cuando no toca, por tener un mal diseño de clases o funciones… o incluso por aplicar la regla del scout que se resume en «Dejar las cosas mejor de como te las encontraste». Esto último puede convertir en un infierno la tarea de la persona que se dedica a integrar cambios y aportes externos si no se gestiona correctamente o falla el proceso de comunicación. Los potenciales conflictos por cambios en el código, es la causa número uno por la que una propuesta de cambio (PR) acaba por no integrarse al código finalmente y por consecuencia genera frustración y pérdida de tiempo.

Merge

La opción de hacer un merge de varios commits de una rama (Head) o hacer un merge de un PR es la acción habitual y predeterminada. Al realizar el merge todos los commits de la rama Head se fusionarán con los de la rama Base.

Estado inicial

Tras aplicar el merge

En esta ilustración, la rama Head se bifurca desde el segundo commit en la rama Base. Se sugieren algunos cambios como nuevas confirmaciones en la rama Head y ahora deben actualizarse en la rama Base. Mediante el merge, las confirmaciones se agregan a la rama Base como se muestra en la imagen superior.

No obstante el ejemplo presentado resulta una visión simplificada, existiendo dos posibles formas de hacer el merge dependiendo de la casuística en la inclusión o no del merge commit.

Fast-Forward o No Fast-Forward 🤔

En el primer caso, el merge fusiona lo cambios y añade los commits de la rama Head en la rama Base. Esto es posible siempre y cuando los commits se produzcan en la rama Head. Básicamente lo que se produce es un desplazamiento del puntero (fast-forward) de la rama Base al último commit de la rama Head.

master = Base | feature = Base

En el segundo caso, con el merge se añade un commit adicional en la rama Base que deja constancia de la unión de la rama Head con la rama Base. Este commit adicional aparece, bien porque lo forzamos para que no se produzca un fast forward (–no-ff); o bien porque la rama Base también contenía cambios, existiendo cambios en ambas ramas en el momento de la fusión.

Squash + Merge

Squash y merge combina todos los commits de la rama Head en un único commit y luego fusiona la rama Head con la rama Base. De esta manera, el historial de commits de la rama Head queda simplificado en un único commit en la rama Base.

Estado inicial

Tras aplicar squash + merge

Se puede observar que la rama Head se bifurca desde el segundo commit de la rama Base y se agregan dos nuevos commits que se añaden a la cabecera de la rama Base. Mediante squash y merge, ambos commits (6 y 7) se combinan en una único commit y luego se fusionan en la rama Base como se muestra en la imagen superior.

Rebase + Merge

Rebase y merge agrega todas los commits en la rama Head de manera individual a la rama Base sin un merge commit. Para todas los hotfix y commits puntuales que no se puedan fusionar con otros commits, esta es la opción de referencia. Esto es debido a que a no existe relación de parentesco con los commits preexistentes del propio árbol.

Cuando se hace una reorganización con rebase en el flujo de los commits de una rama, el SHA único de cada commit cambia debido a que además del contenido del commit para la formación del hash SHA, también se tiene en cuenta el parentesco con el commit inmediatamente anterior y por consiguiente del árbol completo. Este hecho provoca que el uso de rebase provoque más conflictos y su gestión sea más complicada. Esta gestión es complicada, es debido a que Git principalmente usa los commits comunes como base de parentesco, el contenido del propio commit y su contexto (líneas de código anteriores y posteriores a cada cambio de un commit); y en el caso del rebase por causa de la reorganización, no se cuenta con la base de parentesco.

Estado inicial

Tras aplicar rebase + merge de la rama Base a la rama Head

Tras aplicar rebase + merge de la rama head a la rama Base

Atendiendo a la ilustración, la rama Base se bifurca en el segundo commit para formar la rama Head. Posteriormente, se agrega un nuevo commit a la rama Base. Mientras tanto, los commits se realizan en la rama Head.

Por causa del rebase y merge de la rama de la Base a la rama Head, la base de la rama Head se vuelve a colocar. Es decir, ahora la rama Head se bifurca desde el nuevo tercer commit para que el nuevo commit de la rama Base se incluya en la rama Head. Y luego, se aplican los commits en la rama Head.

Ahora, para actualizar la rama Base con los últimos commits de la rama Head, el rebase se realiza de la rama Head a la rama Base como se muestra en la imagen superior.

GitHub

En GitHub podemos ver estas 3 opciones, siendo el ejemplo más habitual e ilustrativo cuando estamos revisando un PR y finalmente decidimos incorporar los cambios:

Haciendo click en la flecha que apunta hacia abajo al lado del «Merge pull request», podremos ver las tres formas de hacer merge que hemos mencionado. De manera análoga GitLab, Bitbucket o Gogs presentan las mismas opciones, o muy similares.

Conclusiones

Tras ver todas las opciones de merge, es recomendable tener en Git cuanta más traza mejor, eso incluye la creación del merge commit evitando el fast-forward si con ello podemos mejorar la traza de la rama donde existían los cambios que se fusionan a la rama Base.

Pero si trabajas en proyectos grandes o eres el gestor de la ramas de desarrollo de un repositorio con suficientes desarrolladores implicados, es más que seguro usarás squash y merge para compartimentar mejor los commits de cada desarrollador. Eso sí asegúrate de tener un buen sistema de CI como Travis CI o AppVeyor, así como suficientes pruebas unitarias, porque el problema de juntar varios commits en uno, es la imposibilidad de revertir los commits parciales una vez que se han juntado.

Por último el uso de rebase y merge es recomendable hacerlo como última opción y en caso de que squash y merge no sean suficiente o se quiera tener la trazabilidad manteniendo los commits parciales de las ramas que se fusionan (hotfix, commits puntales, excesiva densidad de ramas del árbol de versionado Git…), pudiendo realizar así una regresión limpia y más fácil de seguir. La principal desventaja de este método es que se pierde trazabilidad cronológica por la reorganización y potencialmente aumentan los conflictos, pero a la vez se gana simplicidad y claridad en el árbol debido a que no genera una densidad de ramas que complique su gestión. Además, también es posible revertir cualquier commit parcial, pero esto pierde relevancia, cuando se asume que existen servicios de CI que deberías estar ya usando que pueden hacer correr tus pruebas unitarias y ahorrarte sufrimiento y sobresfuerzo innecesario.

» Leer más, comentarios, etc...

proyectos Ágiles

Master en Agile – MMA 2021

marzo 09, 2021 04:32

En octubre de 2021 se iniciará el Barcelona la 11ª edición del Postgrado en Métodos Ágiles (PMA) y otra del Máster en Transformación Agile (MMA) en La Salle (Universitat Ramon Llull), el primero a nivel mundial sobre Agile.

MMA-banner

El Máster incluye el Certified Scrum Master (CSM) de la Scrum Alliance y la certificación Kanban Systems Design de la Lean Kanban University.

SAI_BadgeSizes_DigitalBadging_CSM

Certified Kanban Training

Esta es una oportunidad única para aprender de profesionales de primer nivel, con varios años de experiencia específica en Agile, aplicando principios y métodos ágiles en contextos diversos, especializándose en aspectos concretos,  investigando sobre nuevas técnicas y ponentes en conferencias nacionales e incluso internacionales.

PMA – Postgrado en métodos Ágiles

El PMA incluye el Certified Scrum Master (CSM) de la Scrum Alliance.

Asignaturas Temas Profesores
Fundamentos & Inception

Principios y métodos más conocidos (Scrum, Lean, Kanban y XP). Facilitadores e impedimentos. Inception y conceptualización ágil de proyecto, priorización ágil, historias de usuario,  elaboración de Product Backlog, técnicas de priorización.

Silvia Sistaré
Agustín Yagüe
Scrum y Kanban Estimación y planificación ágil, framework de Scrum, retrospectivas, Kanban, métricas ágiles, herramientas ágiles físicas, radiadores de información. Tiago Garcez
Teodora Bozheva
Personas y equipos Gestión de personas, gestión de conflictos, motivación e incentivos, facilitación compartida, contratación ágil, visual thinking. Steven Wallace

 

Manuel Lopez

Silvia Sistaré

Virginia Armas

Gestión de producto ágil

Design Thinking.

Lean Startup & Agile Product Management

Juncal Guinea

Gabriel Prat

Ingeniería ágil 

User eXperience y prototipado en Agile.

ALM ágil, eXtreme Programing, Software Craftsmanship, testing ágil.

BDD y TDD. Desarrollo guiado por pruebas (de aceptación y unitarias).

Cómo trabajar con código heredado y reducir la deuda técnica.

Juncal Guinea

Álvaro García

Pablo Gómez

Rubén Bernárdez

Trabajo Final de Postgrado Durante el Postgrado se elaborará un caso práctico de introducción de los contenidos en un equipo ágil. Para ellos los alumnos se organizarán en equipos multidisciplinares utilizando Scrum.  

MMA – Master en Métodos Ágiles

Incluye todas las asignaturas del Postgrado (PMA), el CSM, la certificación Kanban Systems Design de la Lean Kanban University y, adicionalmente, las siguientes asignaturas especializadas en Business Agility, agilidad organizacional y transformación:

Asignaturas Temas Profesores
Enterprise Learning & personal efficiency

Agile Kaizen, Comunidades de Práctica, Open Spaces, Talent development, gamification.

Productividad y aprendizaje personal en Agile (eficiencia).

Steven Wallace
Manuel Lopez
Jordi Molla
Lean Thinking & Agile Management

Lean

Escalado con Kanban.

Visual Management Framework (VMF- Agile para cualquier área – Fuera de tecnología).

Agile-Lean Management

Teodora Bozheva

Xavier Quesada

Xavier Albaladejo

Coaching y Cultura

Coaching de equipos, creación de equipos de alto rendimiento, liderazgo.

Tipos de cultura empresarial, gestión del cambio organizativo.

Joserra Díaz

Jasmina Nikolic
Jaume Gurt

Transformación Continua

Enterprise continuous improvement.

Despliegue de Agile en organizaciones. Contratos ágiles.

Enterprise software development & DevOps.

Ángel Medinilla
Xavier Albaladejo

Álvaro García

Scaling Agile 

Escalado (LESS, Spotify, Nexus, SAFe), desescalado y auto-organización empresarial (reinventing organizations, sociocracy 3.0, liberating structures, …), equipos distribuidos.

Impact Mapping, Product Portfolio Management, Roadmapping, Budgeting for Agile

Adrian Perreau
Fernando Palomo

Mattijas Larsson

Trabajo Final de Máster Durante el Máster se elaborará un caso práctico de introducción y aplicación de Agile en una empresa, incluyendo la parte de transformación organizativa, de métodos y de cultura. Para ellos los alumnos se organizarán en equipos multidisciplinares utilizando Scrum.  

Algunos comentarios de los alumnos en ediciones anteriores: “Cuando se acaba la clase, estamos ya esperando a que llegue la semana que viene para ver un nuevo tema con el siguiente profesor”. “Muy práctico”. “La calidad y diversidad de puntos de vista entre los profesores le aporta mucho valor”.  Más detalles en: Mejora de la situación laboral los alumnos del PMA trans un año.

 
Además de los conocimientos concretos que se reciben, uno de los principales cambios que han experimentado los alumnos es mayor perspectiva en los problemas, cómo abordar la complejidad en las empresas, en su trabajo y en las relaciones entre personas y en equipos. Han ganado discurso y aplomo para defender de manera más objetiva propuestas de cambio y mejora.
 

El Máster tendrá una duración de un año académico y se realizará viernes tarde y sábado por la mañana.

 
Para más detalles, consultar la página oficial del Máster.
 

–> Ver también cuál ha sido la Mejora de la situación laboral de los alumnos tras un año y los Principales aspectos valorados por los alumnos.

» Leer más, comentarios, etc...

Meta-Info

¿Que es?

Planeta Código es un agregador de weblogs sobre programación y desarrollo en castellano. Si eres lector te permite seguirlos de modo cómodo en esta misma página o mediante el fichero de subscripción.

rss subscripción

Puedes utilizar las siguientes imagenes para enlazar PlanetaCodigo:
planetacodigo

planetacodigo

Si tienes un weblog de programación y quieres ser añadido aquí, envíame un email solicitándolo.

Idea: Juanjo Navarro

Diseño: Albin