Weblogs Código

Variable not found

¡16 años de Variable Not Found!

mayo 17, 2022 06:05

16 años de Variable Not Found

Hace unos días, Variable Not Found cumplió dieciséis añitos de vida, una eternidad para este mundo en el que vivimos, donde todo ocurre tan rápido y las cosas cambian a una velocidad de vértigo 😊.

Dieciséis años viviendo algo único. Cada uno de los 1.350 artículos publicados ha sido para mí una increíble oportunidad de mejora y aprendizaje y, con suerte, espero (y confío) haber podido ayudar a alguno de los muchísimos visitantes que durante este periodo han pasado por aquí y me han animado a seguir en la brecha.

Dieciséis años creciendo juntos. Comencé esta aventura con más pelo, mejor vista y bastante menos canas, pero la ilusión de poder escribir sobre lo que me gusta, con el plus de que esto pudiera ser útil para alguien, sigue intacta.

Pero bah, dejémonos de historias sentimentales... como es tradición, veamos cómo ha funcionado el blog durante este año.

Variable Not Found en cifras: 2021-2022

Durante este año pasado, las visitas han bajado respecto al anterior, que, por alguna extraña razón, registró unas cifras excepcionales. Aún así, 107.000 usuarios únicos, visitando un total de 180.000 páginas, es una barbaridad para un blog de barrio como este, donde sigo sin invertir ningún tiempo ni recursos en mejorar el SEO ni usar técnicas siniestras como click bait para atraer visitantes. El que llega aquí es porque tenía que llegar 😉

En Twitter, sumamos 2.800 seguidores entre @jmaguilar y @variablnotfound, y 972 seguidores en Facebook, lo que son también unas cifras bastante importantes si tenemos en cuenta que no puedo dedicarles apenas tiempo y que funcionan principalmente con el piloto automático. También siguen creciendo los followers desde Feedly, que superan ya los 2.340.

Como en años anteriores, continúa el imparable crecimiento de visitantes de sexo femenino, que alcanza el 31%. Podéis entender mejor a qué me refiero con "imparable" si tenéis en cuenta que en 2016, hace solo seis años, las mujeres representaban únicamente el 17% de las visitas.

Por edades, la mayoría de visitantes se encuentran en la franja de 18-34 años, aunque sigue viéndose que cada vez tenemos más seniors en esta profesión, creciendo cada año en un porcentaje interesante. Está claro que nos vamos haciendo mayores, y eso se refleja en las estadísticas.

El 90% de los visitantes proceden de buscadores (básicamente Google), mientras que un 7% vienen de forma directa. Los países desde los que más visitantes acuden al blog son:

Distribución geográfica de visitantes
País%
México22,6%
España18,28%
Colombia11,97%
Argentina9,11%
Perú7,68%
Ecuador4,24%

En cuanto a los navegadores utilizados, Chrome continúa siendo el líder en el 78% de los visitantes, y Edge (9,31%) ha superado a Firefox (7,23%) por primera vez. Curiosamente, aún el 1% de los visitantes usan alguna versión de Internet Explorer 😱

Otra cosa positiva de este año es que que algunas publicaciones fueron esponsorizadas por Syncfusion (¡muchas gracias!), lo que me ha permitido obtener algún dinerillo extra para, al menos, tener algún detallito para la familia, a la que mis extrañas aficiones roban tanto tiempo.

En definitiva, ahí seguimos desde este pequeño rincón de la red, intentando aportar nuestro granito de arena al inmenso desierto del conocimiento. Muchas gracias a todos los que seguís el blog por continuar haciéndolo posible después de tanto tiempo, y espero que estéis por aquí un año más, ayudándome a buscar la variable ;)

Publicado en Variable not found.

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

Variable not found

Enlaces interesantes 487

mayo 16, 2022 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 / .NET MAUI / Crossplatform

Otros

Publicado en Variable not found.

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

Variable not found

Constructores estáticos, inicializadores de módulos y startup hooks: tres formas de ejecutar código antes que Program.Main()

mayo 10, 2022 06:05

.NET

Solemos pensar que el punto de entrada de una aplicación .NET, ya sea el método estático Main() del clásico Program.cs o el nuevo Program.cs de .NET 6 que utiliza top level statements, es lo primero que se ejecuta en nuestras aplicaciones, en realidad no es así. Hay vida antes de que nuestra aplicación empiece a correr ;)

Aunque obviamente su utilidad es limitada y no es algo que necesitaremos hacer a menudo (o probablemente nunca), es conveniente saber que existen varias formas de insertar código que se ejecute antes que lo que siempre hemos considerado el entry point de nuestra aplicación, y es lo que veremos en este post.

1. Constructores estáticos

La primera fórmula consiste en usar el constructor estático de la clase Program, que es donde se encuentra en entry point. En aplicaciones de consola, escritorio, web, etc., esta clase es la que contiene el método estático Main() que tradicionalmente ha actuado como punto de entrada del programa.

Dado que el constructor estático de una clase se ejecuta antes que cualquier otra cosa en ella, bastaría con insertar aquí nuestro código personalizado:

internal class Program
{
static Program() => Console.WriteLine("Hello from Program static constructor");
static void Main(string[] args) => Console.WriteLine("Hello from Main()");
}

El resultado de la ejecución de este código será:

Hello from Program static constructor
Hello from Main()

Si usamos .NET 6 o superior, la cosa cambiará un poco, pues la clase Program.cs está algo escondida tras la magia de los top level statements de C#9. Pero de forma similar a la anterior, podríamos introducir el constructor estático de la siguiente manera:

// File: Program.cs
Console.WriteLine("Hello from Main()")

public partial class Program
{
static Program() => Console.WriteLine("Hello from Program static constructor");
}

El resultado obtenido por consola será el mismo que antes:

Hello from Program static constructor
Hello from Main()

2. Inicializadores de módulos

Otra posibilidad es el uso de inicializadores de módulos, una característica introducida también en C# 9 que permite ejecutar código justo cuando el ensamblado en el que se encuentre sea cargado en memoria. Este código debe encontrarse en métodos estáticos void sin parámetros, decorados con el atributo [ModuleInitializer].

Los module initializers se ejecutan una única vez, cuando el ensamblado se carga para que cualquiera de los componentes definidos en el mismo sean utilizados. Por ejemplo, imaginad que tenemos una biblioteca .NET llamada MyClassLibrary con las dos clases siguientes:

public class Initializer
{
[ModuleInitializer]
public static void Initialize()
{
Console.WriteLine("Hello from MyClassLibrary module initializer!");
}
}

public class MyClass
{
public MyClass() => Console.WriteLine("Hello from MyClass constructor");
}

Si referenciamos esta biblioteca desde nuestro proyecto principal y hacemos una referencia a MyClass en su método principal, veremos que el inicializador de módulo de cla clase Initializer se está ejecutando:

internal class Program
{
static Program() => Console.WriteLine("Hello from Program static constructor");
static void Main(string[] args)
{
Console.WriteLine("Hello from Main()");
var foo = new MyClass(); // Clase definida en MyClassLibrary
}
}

La salida será la siguiente. Fijaos que el inicializador de MyClassLibrary se ha ejecutado al principio, para dejar el módulo inicializado antes de ser utilizado; tras ello, se ejecutó el constructor estático de Program seguido del método Main() y finalmente el constructor de MyClass:

Hello from MyClassLibrary module initializer!
Hello from Program static constructor
Hello from Main()
Hello from MyClass constructor

Si además introdujésemos un constructor estático en la clase MyClass, veríamos que éste se ejecuta en el orden esperado, justo antes del constructor de instancia:

Hello from MyClassLibrary module initializer!
Hello from Program static constructor
Hello from Main()
Hello from MyClass static constructor
Hello from MyClass constructor

El código de los inicializadores de módulos se ejecutará también si el ensamblado ha sido cargado de forma dinámica. Así, en el siguiente código, el método marcado con [ModuleInitializer] será ejecutado al intentar usarlo:

// path contiene la ruta al archivo .dll del ensamblado
var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(path);
var c = assembly.CreateInstance("MyClassLibrary.MyClass");
// Aquí ya se habrá ejecutado el module initializer
// y luego el constructor de MyClass
...

3. Startup hooks

Una opción más para ejecutar código antes del entry point es utilizar los startup hooks. A diferencia del caso anterior, donde los inicializadores estaban incluidos en ensamblados referenciados directamente desde el proyecto principal, en esta ocasión se trata de algo que podemos modificar dinámicamente en cada entorno de ejecución.

La idea consiste en establecer en la variable de entorno DOTNET_STARTUP_HOOKS la ruta (o rutas, separadas por punto y coma) de una serie de ensamblados en cuyo interior se encuentra el código de inicialización a ejecutar, que debe encontrarse obligatoriamente definido en el método estático Initialize() de una  clase interna llamada StartupHook.

Un ejemplo sería el siguiente código en una biblioteca de clases, llamada por ejemplo 'MyHook':

// Esta clase debe definirse en la "raíz" del proyecto,
// por lo que no la definimos dentro de un namespace concreto.
internal class StartupHook
{
public static void Initialize()
{
Console.WriteLine("Hello from the startup hook!");
}
}

Este código se ejecutará al arrancar cualquier aplicación .NET (Core), en su mismo proceso, antes que los constructores estáticos e incluso que los inicializadores de módulos, siempre que la ruta hacia su ensamblado se encuentre en la variable de entorno DOTNET_STARTUP_HOOKS, como podemos ver a continuación con un proyecto simple que únicamente saluda al usuario por consola:

C:\HelloWorld\bin\debug\net6.0\>HelloWorld.exe
Hello world!

C:\HelloWorld\bin\debug\net6.0\>SET DOTNET_STARTUP_HOOKS=C:\Hooks\MyHook.dll

C:\HelloWorld\bin\debug\net6.0\>HelloWorld.exe
Hello from the startup hook!
Hello world!

Esta capacidad de ejecución previa de un ensamblado externo puede resultar interesante, sobre todo para hacer cosas raras. Por ejemplo, imaginad una aplicación de consola como la siguiente:

internal class Program
{
public static string Text { get; set; } = "Hello world!";
static void Main(string[] args)
{
Console.WriteLine(Text);
}
}

Aunque previsiblemente su ejecución finalizará mostrando por pantalla el texto "Hello world!", sería posible adjuntarle un startup hook que modifique este comportamiento utilizando reflection para alterar el valor justo antes de que se ejecute:

internal class StartupHook
{
public static void Initialize()
{
var program = Assembly.GetEntryAssembly()?.DefinedTypes
.FirstOrDefault(t => t.Name == "Program");
var textProperty = program?.DeclaredProperties
.FirstOrDefault(p => p.Name == "Text");
textProperty?.SetValue(null, "Text changed by the hook!");
}
}

De esta forma, una vez incluida la ruta hacia el ensamblado que contiene esta clase en la variable de entorno DOTNET_STARTUP_HOOKS, lo que veríamos por consola sería lo siguiente:

C:\HelloWorld\bin\debug\net6.0\>HelloWorld.exe
Hello world!

C:\HelloWorld\bin\debug\net6.0\>SET DOTNET_STARTUP_HOOKS=C:\Hooks\MyHook.dll

C:\HelloWorld\bin\debug\net6.0\>HelloWorld.exe
Text changed by the hook!

Podéis ver otros usos divertidos de los startup hooks en este post de Kevin Gosse, donde pone del revés la salida por consola, o sobrescribe Array.Empty(), entre otras diabluras ;)

Y si queréis leer algo más sobre los temas que hemos visto en el post, ahí van algunas referencias:

Publicado en Variable not found.

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

Variable not found

Enlaces interesantes 486

mayo 09, 2022 06:33

Intel 486

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 / .NET MAUI

Otros

Publicado en Variable not found.

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

Blog Bitix

Desempaquetado y análisis de teclado mecánico compacto e inalámbrico KEMOVE DK61

mayo 05, 2022 05:00

El KEMOVE DK61 es un teclado mecánico que mejora en varios aspectos y aúna varias de las mejores cosas que tienen los DIERYA DK61E y DK63 sin incrementar demasiado su precio con lo que si no se quiere ajustar el presupuesto al máximo compensa por las características mejoradas. El KEMOVE DK61 es muy compacto, de formato 60% con con la ventaja de tener un tamaño reducido y el inconveniente de no tener algunas teclas. Similar al DIERYA DK61E pero que incorpora la conexión inalámbrica del DK63 e incrementa su autonomía con una batería de mayor capacidad y conservando la iluminación RGB. En otras características como switches y keycaps está a la altura de un buen teclado de gama alta pero que en este caso el KEMOVE a un precio por debajo de los 100€.

KEMOVE

Hay una buena cantidad de teclados mecánicos entre los que elegir en base a las necesidades propias y las características de los teclados entre las que está el formato o número de teclas que tienen y por supuesto su precio entre otras. Aunque hay muchos teclados mecánicos muchos no están destinados de forma específica a los usuarios que los utilizan con disposición de teclas en español, otros cuantos ni siquiera se venden en tiendas españolas y no es tan fácil encontrar keycaps con la disposición española que tenga por ejemplo la letra ñ y la tecla de tilde. Sin embargo, hay algunos disponibles y dada la versatilidad y personalización de los teclados mecánicos se pueden adaptar a las necesidades propias con algunos pasos adicionales.

La marca KEMOVE me envía un nuevo teclado mecánico el KEMOVE DK61 para realizar su desempaquetado y análisis en este artículo que compararé con los anteriores DIERYA me envió con anterioridad y publique en sus respectivos artículos. KEMOVE es una marca de mayor calidad que se nota en varios aspectos de los teclados pero sin tener un precio significativamente mayor.

Contenido del artículo

Características técnicas del teclado KEMOVE DK61

El KEMOVE DK61 es un teclado mecánico compacto que tiene una combinación de características de los DIERYA DK61E y el DIERYA DK63. La marca KEMOVE se diferencia de la marca DIERYA en la calidad de los teclados y materiales, también sus teclados tiene un precio ligeramente mayor pero sin ser excesivamente mucho más y que salvo que se quiera ajustar el presupuesto la diferencia de precio compensa en las las mejoras proporcionadas. Loas DIERYA aún siendo unos buenos teclados con un precio muy ajustado para lo que ofrecen tenían algunos puntos a mejorar, algunos de ellos han sido resueltos en el KEMOVE DK61.

En cuanto a formato el KEMOVE DK61 es igual que el DIERYA DK61E, un teclado en formato 60% compacto de 61 teclas que prescinde de las teclas del teclado numérico, las teclas de función, las teclas de flechas y las del bloque superior como insertar, suprimir, inicio, fin, retroceder página, avanzar página, las teclas de función y algunas más.

Tener menos teclas tiene algunas ventajas, principalmente que el teclado ocupa menos espacio en la mesa y el ratón no queda tan lejos que usando un teclado completo con teclado numérico, otra ventaja es que es más fácilmente transportable. La desventaja es que al tener menos teclas algunas han de usarse como una combinación de teclas que si su uso es muy habitual resulta incómodo hasta acostumbrarse.

El KEMOVE DK61 se ofrece en varios tipos de switches, en Amazon están las versiones con los switches Gateron en diferentes colores y tanto lineales, táctiles y sonoros o clicky pero en la página de KEMOVE también se encuentra switches de las marcas Cherry MX y Kailh. En cualquier caso dado que el teclado es hot swappable estos se pueden intercambiar por otros que sean compatibles, el requerimiento es que sean de tres pines, compatibles con RGB si no se desea perder esta funcionalidad y de tipo cherry mx para reutilizar los mismos keycaps.

El ejemplar que tengo tiene switches Gateron Brown del tipo táctil, la diferencia entre este tipo de táctil y los lineales es muy poca y apenas es perceptible en el uso normal. Los switches lineales suelen ser preferidos por los que usan el teclado como jugadores y los táctiles suelen ser preferidos por aquellos que le dan un uso más a escribir texto, aunque cualquiera de los dos tipos sirven para ambas tareas siendo un preferencia personal que tipo usar. Como los switches son intercambiables si en algún momento se prefieren otros tanto de otro tipo como de otra marca compatible se pueden cambiar. Otra ventaja de que los switches sean intercambiables es que si alguno es defectuoso o se estropea con el uso se puede reemplazar por otro lo que prolonga la vida del teclado y no hay que desecharlo simplemente porque una tecla deja de funcionar correctamente.

Tipos de switches Gateron

Tipos de switches Gateron

El teclado tiene iluminación RGB en diferentes colores, efectos e intensidad que más allá del aspecto estético de tener colores resulta útil en caso de bajas condiciones de luz para ver las teclas. Además la iluminación RGB se utiliza para proporcionar algunas indicaciones al pulsar teclas como por ejemplo conocer de forma aproximada la carga de la batería.

El teclado tiene la posibilidad de funcionar tanto con cable como de forma inalámbrica mediante Bluetooth pudiendo configurar hasta tres dispositivos de forma simultánea. La conexión Bluetooth es fácil de configurar poniendo el teclado en modo configuración momento en el que es detectado por el dispositivo en el que se quiere usar y se completa la configuración. Utiliza una batería de 3000 mAh que le da para varias semanas de uso hasta la siguiente carga incluso con un uso diario de varias horas. La conexión es fiable y al tener batería no hace falta usar pilas ni reemplazarlas cada cierto tiempo.

El cable permite al teclado funcionar mediante cable que al ser Bluetooth en algunos casos es necesario como por ejemplo al acceder a la BIOS, el cable también sirve para cargar la batería del teclado. Es USB de tipo C para la conexión al teclado y de tipo A para la conexión al ordenador, destacando que es un cable de calidad como era en los DIERYA siendo mallado y reversible en ambos extremos lo que facilita su conexión en cualquier orientación del cable.

Las características completas del teclado son:

  • Cuerpo del teclado de plástico robusto y buena construcción, regulable en altura en una posición con patas extensibles.
  • Teclado 60%, 61 teclas.
  • Sin teclas de desplazamiento.
  • Disposición ANSI con teclas en inglés.
  • Switches Gateron, Cherry MX o Kailh, intercambiables o hot swapabble.
  • Keycaps PBT de doble disparo para la leyenda principal, pad printing para la serigrafía de función que está serigrafiada en el lateral de las teclas.
  • Switches y keycaps incluídos y premontados.
  • Iluminación RGB con varios efectos de luz e intensidad.
  • Cable mallado desmontable USB Tipo C y Tipo A ambos reversibles.
  • Conexión dual, con cable y/o Bluetooth 5.1 hasta 3 dispositivos, con batería recargable de 3000 mAh.
  • Indicativo del nivel de carga de batería con una combinación de teclas.
  • Incluye cubre teclado de plástico para evitar polvo.

Para conocer más detalles sobre los teclados mecánicos y en qué se diferencia de los teclados de membrana con una guía de introducción escribí el siguiente artículo comentando sus principales características, así como varios desempaquetados y análisis de teclados mecánicos con la que comparar con otros modelos más en detalle. Escribí una introducción a los conceptos básicos de los teclados mecánicos puedes visitar la guía de ese artículo y si quieres compararlo con un tecla de otra marca y tipo para saber cual te conviene según tus necesidades o preferencias escribí un Desempaquetado de teclado mecánico Glorious GMMK TKL junto con otros buenos modelos de teclados a considerar.

Diferencias con los teclados DIERYA DK63 y DK61E

Los modelos DIERYA DK63, DK61E y el KEMOVE DK61 son modelos muy parecidos entre ellos, pero examinando los detalles del KEMOVE DK61 se nota que es un teclado con algunas características que aúnan lo mejor de todos. Empezando porque el KEMOVE DK61 es inalámbrico al igual que el DK63 al contrario que el DK61E que solo era cableado, pero tiene una gran batería de 3000 mAh mayor que la del DK63 que era de 1900 mAh.

Tiene patas para regular la altura que ninguno de los DIERYA ofrecía. El switch para activar la conexión inalámbrica está en el lateral del teclado más accesible que en la parte inferior del DK63 y con un switch con un acabado de mejor calidad. La serigrafía de las funciones en vez de en la parte superior de la tecla está en un lateral, esto tiene la ventaja de que al ser de tipo pad printing evita que se desgaste y por otro lado hace la tecla más legible al tener menos símbolos en la parte superior para funciones que se usan menos habitualmente. Aún estando en un lateral la serigrafía es perfectamente legible desde la posición de uso. El backplate es de color blanco que resalta la iluminación RGB y finalmente se incluye un muy útil cubre teclado de plástico para evitar polvo cuando no se usa.

Consideraciones a tener en cuenta

Al ser un teclado compacto hay que considerar que algunas teclas han de usarse como una combinación, hasta acostumbrarse puede resultar incómodo. También hay que tener en cuenta que es un teclado con disposición ANSI que es diferente de la habitual en España que es ISO, tiene algunas diferencias en los tamaños de algunas teclas como la tecla Return. En caso de querer keycaps con serigrafía de teclado en Español hay que comprarlas aparte, en AliExpress hay unos keycaps con disposición en Español que usa mucha gente.

La conexión inalámbrica es Bluetooth con lo que requiere de que el dispositivo donde se tenga Bluetooth y esté la conexión disponible, por esto al acceder a la BIOS del equipo es probable que requiera utilizar la conexión por cable que tampoco es demasiado inconveniente.

Dónde comprar

El teclado mecánico KEMOVE DK61 se puede comprar directamente en la página oficial al mejor precio con la ventaja de poder hacer el pago mediante PayPal así como otros accesorios como una funda de transporte para el teclado, keycaps y switches. Si el modelo elegido está disponible en la página de Amazon del propio país lo envían directamente de Amazon en vez de China a un precio de unos 90 € y algo más barato en los momentos en tiene aplicado un descuento en el precio.

Aparte de este modelo la marca tiene disponibles otros modelos de teclado compactos como el DIERYA DK61E, el DIERYA DK63 y el DIERYA DK61 Pro, ambos DK61 son iguales pero el Pro tiene con conexión inalámbrica también por Bluetooth.

Si después de leer el artículo decides comprar uno de estos teclados y en el momento que vas a hacerlo no tiene algún descuento envíame un correo electrónico que puedes encontrar en la página Acerca de y le pido a la marca un cupón descuento para que puedas aplicarlo en el momento de realizar la compra.

Desempaquetado del teclado mecánico KEMOVE DK61

La caja

La caja del KEMOVE muestra el logotipo de la marca en la parte delantera y y se compone de una ventana que con el protector de plástico del teclado deja ver una parte del él, tiene una serigrafía con relieve únicamente por motivos estéticos pero que indica que hasta la caja está cuidada.

En la parte trasera se muestran dos ilustraciones y las características básicas del teclado. En uno de los laterales otra forma de logotipo de la marca y las características del ejemplar del teclado incluyendo el modelo, color y switches. La caja está precintada por un plástico que impide que entre suciedad o líquidos durante el transporte y esté en perfectas condiciones hasta el momento de abrirla.

Caja del teclado KEMOVE DK61 Caja del teclado KEMOVE DK61 Caja del teclado KEMOVE DK61

Caja del teclado KEMOVE DK61 Caja del teclado KEMOVE DK61

Caja del teclado KEMOVE DK61 Caja del teclado KEMOVE DK61

Caja del teclado KEMOVE DK61

El contenido de la caja

El contenido de la caja aparte del propio teclado se compone de su manual de usuario en el que se muestran los diferentes grupos de teclas que se usan en combinación con la tecla de función junto con la descripción de que hacen que es útil como referencia en caso de cambiar los keycaps, el cable para la conexión al ordenador y carga de la batería, una tarjeta de garantía, un extractor de keycaps y un extractor de switches y tres switches adicionales para probar otros tipos de switches o reemplazar alguno, también sirven como reemplazo en caso de que alguno se estropee.

Contenido de la caja:

  • El teclado.
  • Cable USB.
  • Un pequeño manual con las combinaciones de teclas.
  • Cubre teclado de plástico para evitar polvo.
  • Un extractor de keycaps.
  • Un extractor de switches.
  • Una tarjeta con la garantía ofrecida.
  • 3 switches adicionales de otros colores.

Un detalle que en mi caso echaba en falta en los DIERYA era que no incluían una tapa protectora para cuando el teclado no se está usando y evitar que se le acumule polvo. El KEMOVE incluye esa tapa de plástico que a mi me resulta muy útil, un detalle a la altura de de los mejores teclados y que no se suele encontrar en teclados en el rango de precios del KEMOVE. Además, este plástico que también forma parte del empaquetado permite en vez de desechar todo el embalaje después de abierto darle un uso durante toda la vida del teclado que será de más de un lustro e incluso una década.

Contenido de la caja del teclado KEMOVE DK61 Contenido de la caja del teclado KEMOVE DK61

Contenido de la caja del teclado KEMOVE DK61

El teclado

El cuerpo del teclado es completamente de plástico que da sensación de resistente con un pequeño biselado en la parte delantera. En gran medida tiene el mismo aspecto de los DIERYA y es que el teclado tampoco necesitaba ninguna mejora adicional. Las diferencias están en la parte trasera que incluye el nombre de la marca y las patas que permite regular la altura al menos en una posición cosa de las que carecían los DIERYA. Por otro lado en este KEMOVE tiene dos interruptores que están en el lateral para activar el modo inalámbrico y cambiar el modo de compatibilidad entre Windows y macOS.

El teclado se ofrece en dos colores el negro donominado shadow y blanco denominado snowfox tanto para el cuerpo del teclado como para los keycaps. La estabilidad en las teclas grandes como la barra espaciadora y las teclas de shift es buena. Que el teclado sea RGB siendo inalámbrico, que el cable sea desmontable y que los switches sean intercambiables es algo que no se suele encontrar en teclados en el rango de precios alrededor de 90 € en los que se ofrece el KEMOVE, estas características se suelen ofrecer en teclados en un rango de precios superior.

En el modo de funcionamiento inalámbrico permite configurar hasta tres dispositivos para cambiar de uno a otro según se desee con la combinación de teclas FN+Z, FN+X y FN+C. Es compatible tanto con Windows, macOS, como con GNU/Linux y Android reconociéndose todas las teclas incluidas las de función multimedia para controlar la reproducción y el volumen de sonido.

Conserva las mismas dimensiones que los DIERYA DK61E y DK 63, siendo para el KEMOVE DK61 de 29 cm de ancho, 10 cm de largo, por unos 3 cm en la parte baja y unos 4,5 en la parte alta de altura incluyendo los keycaps. Con las patas extraídas para regular la altura su altura llega a los 4,5 cm.

Teclado KEMOVE DK61 Teclado KEMOVE DK61 Teclado KEMOVE DK61

Teclado KEMOVE DK61 Teclado KEMOVE DK61 Teclado KEMOVE DK61

Teclado KEMOVE DK61 Teclado KEMOVE DK61 Teclado KEMOVE DK61

Teclado KEMOVE DK61 Teclado KEMOVE DK61

Teclado KEMOVE DK61

Los switches

El teclado se ofrece premontado con switches Gateron, Cherry MX y Kailh, los primeros están en Amazon y se envían desde el país de la página si están disponibles, los Kailh se ofrecen en la página de KEMOVE. Por supuesto, se ofrece una amplia gama de colores dentro de los Gateron, que incluyen los tres tipos básicos de lineales, táctiles y sonoros, dentro de estos tipos básicos algunos con mayor resistencia para aquellos que prefieran unas teclas que sean algo más duras.

En cualquier caso dado que el teclado es hot swappable permite cambiar los switches por cualesquiera otros de otra marca que sean compatibles. Los switches han de ser de tres pines y eléctricos, si se desea conservar la iluminación RGB ha de ser compatible también con el RGB.

En la página de Gateron hay una leyenda con la descripción de cada switch según su color tanto de qué tipo son, su fuerza de actuación y recorrido. En general unos rojos para los lineales y los marrones para los táctiles son los más comunes.

Swicthes eléctricos Gateron y estabilizador del KEMOVE DK61

Swicthes eléctricos Gateron y estabilizador del KEMOVE DK61

Los keycaps

Los keycaps son de plástico PBT considerado generalmente mejor por ofrecer mayor durabilidad que el plástico ABS más barato, el plástico PBT no es de lo más gruesos que hay pero es más que suficiente y no presenta ningún problema en su uso y durabilidad. La serigrafía para las leyendas principales de la tecla es de doble disparo o double shot que evita que con el uso se deteriore como ocurre en otras formas de impresión más baratas pero también de peor calidad. La leyenda de las teclas de función es de pad printing que no ofrece las mismas garantías de durabilidad pero al está en una lateral del keycap que no se suele tocar con los dedos su durabilidad no es afectada, por otro lado, al esta la leyenda de las teclas de función en un lateral hace que las teclas tengan un aspecto limpio y la leyenda principal se vea sin ninguna distracción.

Al ofrecerse un cubre teclado permite minimizar la cantidad de polvo que se acumula entre teclas cuando no se usa, en cualquier caso en caso de que pasado un tiempo las teclas acumulen algo de polvo entre la teclas o en el backplate los keycaps se pueden desmontar de los switches y realizar una limpieza a fondo de tal forma que quede tan limpio como el primer día de uso.

Keycaps del KEMOVE DK61

Keycaps del KEMOVE DK61

Análisis y primeras impresiones del teclado mecánico KEMOVE DK61

Al usarlo no he tenido ningún inconveniente para que el teclado sea reconocido por cualquiera de los sistemas operativos donde lo he probado tanto de forma cableada como de forma inalámbrica, las pulsaciones se registran de forma inmediata, en el modo inalámbrico la latencia es imperceptible y la conexión inalámbrica se muestra estable.

Realizar la conexión inalámbrica se hace en unos pocos segundos activando el teclado en modo configuración y emparejándolo en el dispositivo donde se desea usar. El teclado se pone en modo configuración manteniendo durante unos segundos la combinación de teclas FN+Z, FN+X y FN+C. La conexión inalámbrica es útil para usarla tanto en un ordenador, como en un smartphone, consola o televisión inteligente incluido poder usar la conexión inalámbrica en dispositivos en ubicaciones diferentes como en la oficina y en casa. Tanto en los smartphones, como en las consolas y televisiones inteligentes es muy útil que el teclado sea inalámbrico sin cables, en el caso de la televisión desde el sofá, en un ordenador si se tiene en la habitación desde la cama y en un smartphone sin tener que utilizar la pantalla táctil y con con la misma experiencia de uso que un ordenador por ejemplo al escribir un documento o redactar un correo electrónico.

Al ser de 60% sigue siendo un modelo muy compacto, ligero y fácilmente transportable. Pero los teclados 60% no son para todos los usuarios y algunos prefieren los TKL para no perder algunas teclas. Desconozco si la limitación de de hasta tres dispositivos es una limitación técnica o de costes pero quizá incluso para algunos usuarios poder configurarlos con más dispositivos sería útil dados los varios dispositivos como los mencionados anteriormente donde se puede usar un teclado inalámbrico, se tarda poco en realizar la configuración pero sería innecesario si pudiese utilizarse en hasta 5 o 7 dispositivos. Aún así la mayoría de teclados inalámbricos solo permiten hasta tres dispositivos por lo que no es un defecto respecto a modelos de otras marcas.

Que los switches para cambiar entre el modo inalámbrico y modo de compatibilidad entre Windows y macOS estén en un lateral es más cómodo y de acceso más fácil que si estuviese en la parte inferior como ocurre en el DK63. Que el backplate sea blanco hace destacar la iluminación RGB y que ofrezca una tapa de plástico para cubrir el teclado es un detalle que seguro los usuarios que lo usen lo agradecen para evitar el polvo.

Algunos de estos detalles es algo que echaba en falta en los DIERYA y que en los KEMOVE están resueltos, aunque si no estoy equivocado en la serigrafía de la tecla dónde está el F11 tiene el mismo error de serigrafía que el DK61E estando los caracteres en la posición contraria. Dónde está el - debería estar el _, no es algo muy grave pero al ser algo de diseño es algo que seguro se podría corregir si añadir costes de fabricación.

Compatibilidad con sistemas operativos

Lo he probado tanto en GNU/Linux, macOS y Android, en todos estos sistemas operativos el teclado es detectado correctamente en el momento que se pone en modo de configuración. Permite cambiar de uno a otro sistema con la combinación de teclas. Si es compatible con esos sistemas operativos es seguro que lo será también con Windows tal y como se indica en su caja de empaquetado. Para Windows se ofrece una aplicación de escritorio para configurar la iluminación y macros de teclado, los controladores y manual de usuario. Al tener un botón de compatibilidad para macOS las teclas se adaptarán es modo de funcionamiento específico de macOS.

Configuración del teclado con conexión inalámbrica en macOS Configuración del teclado con conexión inalámbrica en GNU/Linux Configuración del teclado con conexión inalámbrica en Android

Configuración del teclado con conexión inalámbrica

Análisis en vídeo

Aquí muestro un vídeo con la parte frontal del teclado visto desde la posición de uso y cerca tanto sin iluminación RBG como con iluminación RGB y en YouTube hay una buena cantidad de vídeos que analizan y hacen el desempaquetado de este modelo de teclado KEMOVE DK61. En los vídeos se explican detalles desde otro punto de vista, información adicional o complementaria a la ofrecida en este artículo.

Conclusión

El teclado KEMOVE mejora en varios aspectos a los teclados DIERYA sin incrementar demasiado su precio. Un precio que sigue siendo muy ajustado y con características que otras marcas ofrecen en un rango de precios más elevado. Encontrar un teclado con teclas PBT de doble disparo, que sea hot swappable, inalámbrico por Bluetooth y cableado, con iluminación RGB en este rango de precios no es tán fácil de encontrar.

Para algunos el mayor inconveniente sea tener unos keycaps en disposición de español si se quieren cambiar que en AliExpress hay varios vendedores que los ofrecen teniendo en cuenta que esto incrementa algo el precio del teclado y teniendo en cuenta que la serigrafía de las teclas de función se pierde. Otro aspecto a tener en cuenta es que carece de teclas de flechas dedicadas y teclas de bloque superior motivo por el cual algunos optan por modelos TKL con las mismas teclas y solo prescindiendo del teclado numérico.

El KEMOVE DK61 en los aspectos más importantes no tiene nada que envidiar a teclados considerados de gama alta y es que el KEMOVE puede considerarse también de gama alta, pero a diferencia de muchos otros tiene un precio asequible que se mantiene ajustado para muchos usuarios. Si se desea un teclado 60% con disposición ANSI e inglés sabiendo que se pueden cambiar los keycaps es una muy buena opción de compra pudiendo hacerlo además en Amazon o en su propia página a través del medio de pago PayPal.

Complementos para el teclado

Al comprar un teclado mecánico puede interesar comprar a la vez otros complementos para el teclado, como un concentrador USB para tener los puertos de conexión cerca especialmente si se suele estar conectando y desconectando dispositivos o el ordenador tiene difícil acceso a los puertos USB estando en la parte trasera del ordenador de torre.

En páginas como AliExpreses hay multitud de vendedores que venden conjuntos de keycaps y la marca KEMOVE también varios conjuntos de keycaps y switches. Una de las ventajas de los teclados mecánicos es poder personalizarlos y los keycaps es una forma, pudiendo elegir diferentes layouts o colores para algunas teclas como forma de distinción y hacer del teclado una pieza única.

Otro producto interesante es una alfombrilla de gran tamaño que permite colocar tanto el teclado como el ratón, permite evitar el desgaste de la mesa o ensuciarla. Algunas alfombrillas incluso con iluminación RGB que aparte de su efecto estético puede resultar también útil en condiciones de baja iluminación.

Finalmente, en caso de querer transportar el teclado es aconsejable comprar una funda para protegerlo en el transporte que KEMOVE vende en su página web o en algún momento también está disponible en Amazon y evitar que sufra algún deterioro en el transporte principalmente para proteger los keycaps.

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

Variable not found

Enlaces interesantes 485

mayo 03, 2022 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

    Web / HTML / CSS / Javascript

    Visual Studio / Complementos / Herramientas

    Xamarin / .NET MAUI

    Otros

    Publicado en Variable not found.

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

    Blog Bitix

    Cómo usar el comando git bisect para descubrir el primer commit con un error

    abril 28, 2022 05:00

    El comando git bisect es muy útil cuando se desea encontrar en que commit se ha introducido un error en un rango de commits ya que permite automatizar la búsqueda sin tener que hacerlo manualmente el desarrollador que simplemente se limita a indicar a Git si el commit a analizar en cada prueba es correcto o incorrecto. Una vez descubierto en que commit se ha introducido el error es cuestión de revisar los cambios de ese commit, analizar sus cambios e identificadas las líneas de código erróneas aplicar la solución.

    Git

    Una herramienta de control de versiones para el código fuente de las aplicaciones es esencial, para guardar todos los cambios realizados en el código y permitir compartir código entre los desarrolladores aparte de otras funcionalidades proporcionadas. Una de las herramientas de control de versiones más populares es Git, desarrollado por Linus Torvalds también autor original de núcleo Linux entre otros colaboradores.

    Una situación habitual al realizar cambios en el código fuente de un programa es pasado un tiempo descubrir un error y no conocer en que cambio lo ha producido y en que commit. Si no se tiene una pista de cual es el cambio que ha introducido error una solución es probar cada commit y para ver si esa versión de la aplicación tiene el error o no. Una vez probados varios commit al final se descubre que commit es el que ha introducido el error. Conociendo el commit que introduce el error hay que revisar los cambios de ese commit para conocer y cambiar las líneas de código erróneas.

    El comando git bisect

    Una de las funcionalidades que proporciona la herramienta de control de versiones Git es el subcomando bisect. El comando git bisect automatiza encontrar que commit ha introducido un error dado un rango de commits en el que se sospecha está el commit con el error.

    El comando git bisect aplica un algoritmo de búsqueda al rango de commits, en función de la indicación que se le proporcione de si el commit tiene o no el error al final del número de comprobaciones que sean necesarias proporciona el primer commit con el error en el rango analizado.

    El comando git bisect no se utiliza tan habitualmente como git stash o git commit pero cuando cuando es necesario es muy útil conocer como se usa y usarlo.

    El primer paso del comando git bisect es iniciar la bisección y proporcionar el rango de commits a analizar. Una vez proporcionado el rango de commits git cambia el commit del espacio de trabajo según su algoritmo de búsqueda. El siguiente paso suele consistir en arrancar la aplicación y comprobar si el commit tiene o no el error. Una vez conocido si el commit es correcto o tiene el error se le indica a Git con el comando git bisect good o git bisect bad respectivamente. Git a continuación selecciona otro commit teniendo que comprobar de nuevo si el nuevo commit seleccionado es correcto o incorrecto. Después de varias repeticiones de estos pasos se descubre el commit en el que se introdujo el error.

    Una vez terminada la bisección o en cualquier momento se puede dar por terminada con el comando git bisect reset y volver a un espacio de trabajo fuera del bisect. El comando git bisect view permite ver el estado de la bisección y los commits analizados.

    Estos con los comandos básicos y un ejemplo de uso.

    1
    2
    3
    4
    5
    
    $ git bisect start
    $ git bisect good
    $ git bisect bad
    $ git bisect reset
    $ git bisect (visualize|view)
    git-bisect-1.sh
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    
    $ git log --pretty=oneline 63575c4f1824c360dbf60aafaaec17401ea604bd..master
    022c1b295804bf810743f175358607a0a3bb7307 (HEAD -> master, origin/master) Remove Universal Analytics
    a07d1af345907016e19778feb064e08d17f36ed9 Add print_step for display_manager step
    39320076b996e4d582bf535f74d1f0b238b3768a Reorder packages
    d5233aa726c2626d52de8981bee65dcfbf69ae61 Merge pull request #209 from shuriken1812/master
    f7a4790992f859aac6fde86b3b18a72e259545bd Added pipewire-alsa and wireplumber
    0b0a1ddca33814e254b3bc395af476156559aac4 Allow to choose display manager
    0aeacbab0fe55b71b272d670c76ab52fa2b206c4 Support LightDM autologin
    ff01de4f91ff10c6b99b5b6275623ea93ec412ba Update Hugo  ndadd Google Analytics 4
    f3038ae0195dddcd98660ebd81721aa5645a8597 Merge pull request #194 from MauroSoli/patch-1
    20c5f7a12bbbc372e77187cae7ccd4a1c64c8a1b Change provision configuration description
    219f4ab9232b5537364d8b9a0e969520917f3230 add !tpm module
    git-log.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
    
    [picodotdev@archlinux alis (master $=)]$ git bisect start master 63575c4f1824c360dbf60aafaaec17401ea604bd
    Biseccionando: faltan 5 revisiones por probar después de esta (aproximadamente 3 pasos)
    [0aeacbab0fe55b71b272d670c76ab52fa2b206c4] Support LightDM autologin
    [picodotdev@archlinux alis ((0aeacba...) $|BISECTING)]$ git bisect good
    Biseccionando: faltan 2 revisiones por probar después de esta (aproximadamente 2 pasos)
    [d5233aa726c2626d52de8981bee65dcfbf69ae61] Merge pull request #209 from shuriken1812/master
    [picodotdev@archlinux alis ((d5233aa...) $|BISECTING)]$ git bisect bad
    Biseccionando: faltan 0 revisiones por probar después de esta (aproximadamente 1 paso)
    [f7a4790992f859aac6fde86b3b18a72e259545bd] Added pipewire-alsa and wireplumber
    [picodotdev@archlinux alis ((f7a4790...) $|BISECTING)]$ git bisect bad
    Biseccionando: faltan 0 revisiones por probar después de esta (aproximadamente 0 pasos)
    [0b0a1ddca33814e254b3bc395af476156559aac4] Allow to choose display manager
    [picodotdev@archlinux alis ((0b0a1dd...) $|BISECTING)]$ git bisect bad
    0b0a1ddca33814e254b3bc395af476156559aac4 is the first bad commit
    commit 0b0a1ddca33814e254b3bc395af476156559aac4
    Author: pico.dev <pico.dev@gmail.com>
    Date:   Sat Apr 23 14:48:22 2022 +0200
    
        Allow to choose display manager
    
     alis.conf |   4 +-
     alis.sh   | 148 +++++++++++++++++++++++++++++++++++++++++++++-----------------
     2 files changed, 112 insertions(+), 40 deletions(-)
     [picodotdev@archlinux alis ((0b0a1dd...) $|BISECTING)]$ git bisect reset
     [picodotdev@archlinux alis (master $=)]$ 
    git-bisect-example.sh

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

    Metodologías ágiles. De lo racional a la inspiración.

    Open Space, para un roto o para un descosido

    abril 28, 2022 07:03

    NOTA: Estoy escribiendo la guia de facilitación de Open Space. Hemos hablado varias veces aquí ya de los Open Space como un formato increible para la organización y facilitación de conferencias. En Agile-Spain hemos organizado ya tres a nivel nacional, y han surgido multitud de pequeños "opens" para tratar muchos temas alrededor del agilismo. Si no sabes qué es un Open Space, echa un ojo a esta

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

    Header Files

    Extendiendo el autocompletado en Bash

    abril 26, 2022 06:45

    Introducción

    Personalmente creo que hay cuatro acciones de teclado que consumen el 70% de mi tiempo en una terminal: Enter, Control-C, Arriba y Tab. Las dos primeras para iniciar y parar comandos, y las dos últimas para agilizar la escritura, bien sea buscando en el historial o bien completando el nombre del comando actual.

    Respecto al autocompletado, algunas shell, como Bash, permiten además hacer un autocompletado contextual, es decir, que una vez introducido el nombre del comando que se quiere ejecutar el motor de autocompletado ofrecerá las opciones pertinentes en base a dicho comando y a las opciones previamente seleccionadas. Esto no sólo ahorra tiempo de escritura, sino que además sirve de complemento a la ayuda del propio comando.

    En esta entrada expondremos cómo crear un script de autocompletado propia, de forma que podamos incluirlo en nuestros proyectos. Aunque me centraré en la shell Bash, esta funcionalidad también es posible para otras: en cmd (Windows) mediante clink (usando Lua), PowerShell mediante funciones TabExpansion, zsh mediante zsh-autocomplete (aunque en este caso habría que extender el proyecto base).

    Pre-requisitos

    Además de tener Bash como shell activa, necesitaremos el paquete bash-completion y activarlo en nuestra sesión. Podemos seguir las instrucciones listadas acá.

    Diseñando el script

    Comenzaremos detallando el comando al que queremos dar soporte, para luego mostrar y explicar el script en cuestión.

    Sintaxis del comando

    Vamos a suponer que nuestro comando se llama headerfiles y tiene la siguiente sintaxis:

    headerfiles [-h --help -j -f <nombre_de_fichero> -e [-x|-p] -o [slow|fast]]
    

    Particularidades:

    • -x y -p sólo están disponible si -e ha sido definido previamente.
    • -x y -p son mutuamente excluyentes.
    • -f <nombre_de_fichero> puede ser especificado varias veces.
    • -j -e no presentan problems si se indican varias veces, pero es equivalente a que sólo se indicasen una vez.
    • -o sólo puede ser especificado una vez.
    • -h --help tienen prioridad sobre cualquier otra opción.

    El script

    El primer paso será crear un fichero para guardar las funciones del script. Personalmente los suelo guardar en una ruta del tipo <proyecto>/scripts/autocomplete/headerfiles.bash, pero queda a vuestra discreción.

    Hay, como es imaginable, varias formas de programar este autocompletado personalizado, pero mostraré la que a mí particurmente me resulta más sencilla mentalmente, aunque no necesariamente sea la más eficiente: definir una función que fije la variable de entorno COMPREPLY. y pasar dicha función como argumento de complete, junto con el nombre de nuestro comando (Bash usará este nombre para determinar si debe llamar a nuestro autocompletado particular o a algún otro). La variable COMPREPLY es usada por complete como la lista de opciones que se mostrarán. Como ayuda, usaremos el comando compgen para generar, de forma amigable, dicha lista de opciones.

    Presento el script correspondiente a la sintaxis antes mencionada y luego procedo a su explicación:

    #/usr/bin/env bash
    
    # Prints 1 if the given option has already been specified, 0 otherwise
    has_option() {
        for i in "${COMP_WORDS[@]}"; do
            if [[ "$i" == "$1" ]]; then
                echo "1"
                return
            fi
        done
    
        echo "0"
    }
    
    # Function to be called when auto-completing
    _headerfiles() {
        COMPREPLY=()
    
        # These options have the highest precedence, so ignore any other if they've been specified
        if [[ "$(has_option -h)" == "1" || "$(has_option --help)" == "1" ]]; then
            return 0
        fi
    
        local cur=${COMP_WORDS[COMP_CWORD]}
        local prev=${COMP_WORDS[COMP_CWORD - 1]}
    
        case $prev in
            # Options with additional arguments
            "-f") COMPREPLY=(`compgen -f -- $cur`) ;;
            "-o") COMPREPLY=(`compgen -W "slow fast" -- $cur`) ;;
            # Any other option
            *)
                # This variable will contain the list of available options
                local AVAILABLE_OPTIONS=()
    
                # List of supported options that can be used only once
                local ALL_ONCE_OPTIONS=("-e -o -h --help")
    
                # Add dependant options
                if [[ "$(has_option -e)" == "1" ]]; then
                    # Mutually exclusive options
                    # Do not remove current word in shell to allow finishing its autocompletion
                    if [[ "$(has_option -x)" == "1" ]]; then
                        ALL_ONCE_OPTIONS=("${ALL_ONCE_OPTIONS[0]} -x")
                    elif [[ "$(has_option -p)" == "1" ]]; then
                        ALL_ONCE_OPTIONS=("${ALL_ONCE_OPTIONS[0]} -p")
                    else
                        ALL_ONCE_OPTIONS=("${ALL_ONCE_OPTIONS[0]} -x -p")
                    fi
                fi
    
                # Most options are allowed only once, so remove the ones already in use,
                # but do not remove current word in shell to allow finishing its autocompletion
                local PREV_COMP_WORDS=("${COMP_WORDS[@]}")
                unset "PREV_COMP_WORDS[-1]"
                for i in ${ALL_ONCE_OPTIONS}; do
                    for j in "${PREV_COMP_WORDS[@]}"; do
                        if [[ "$i" == "$j" ]]; then
                            continue 2
                        fi
                    done
                    AVAILABLE_OPTIONS+=("$i")
                done
    
                # The -f option can be used several times
                AVAILABLE_OPTIONS=("${AVAILABLE_OPTIONS[*]} -f")
    
                COMPREPLY=(`compgen -W "${AVAILABLE_OPTIONS[*]}" -- $cur`)
                ;;
        esac
    }
    
    complete -F _headerfiles headerfiles
    

    Como notas particulares:

    • Las opciones de máxima prioridad, aquéllas que cuando se especifican dejan sin efecto a las demás, se procesan de primero y con un early return.
    • Las opciones con argumentos adicionales se procesan de forma independiente, pudiendo generar un autocompletado específico para dicha opción:
      • compgen -f: nombres de ficheros.
      • compgen -d: nombres de directorios.
      • compgen -W "...": una lista de palabras (nótese que éste es el mismo método empleado en otras partes del script).
      • La opción anterior puede usarse en conjunto con una función que extraiga los términos disponibles (de un fichero, de otro comando, etc). Por ejemplo, Git lo hace cuando detecta una línea tipo git checkout, entonces el siguiente autocompletado son nombres de las ramas disponibles, que son extraídas de una consulta a git branch -a.
    • Cuando hay que listar las opciones disponibles, primero se enumeran las que se pueden elegir una única vez y se filtran para quitar las ya introducidas. Posteriormente se añaden las que pueden repetirse

    Activando el script de autocompletado

    Para activarlo bash con que carguemos el script: source /path/to/script.bash. Además, podemos agregar esta línea en nuestro .bashrc para que esté disponible en cualquier nueva sesión Bash que ejecutemos.

    Si nuestro proyecto incluye un comando de instalación o un paquete, deberemos añadir el script en el mismo e instalarlo en /usr/share/bash-completion/completions/.

    Conclusión

    Hemos estudiado cómo extender el autocompletado de Bash con algunas de las opciones más frecuentes. Otras combinaciones más complicadas pueden resolverse con una extensión de éstas (por ejemplo, el caso de que la lista de subvalores de una opción deba ser extraída de un fichero o comando). Para más información podemos consultar la documentación oficial.

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

    Variable not found

    Requerir parámetros de la query string en ASP.NET Core 6

    abril 26, 2022 06:05

    ASP.NET Core

    Imaginad que tenemos un controlador MVC como el siguiente:

    public class TestController : Controller
    {
    public IActionResult Add(int a, int b)
    {
    return Content($"Result: {a + b}");
    }
    }

    Claramente, la acción Add() retornará la suma de los enteros a y b que le llegarán como parámetros de la query string:

    GET https://localhost:7182/test/add?a=1&b=2 HTTP/1.1

    HTTP/1.1 200 OK
    Content-Type: text/plain; charset=utf-8

    Result: 3

    Pero, como sabemos, podríamos llamar a la acción sin indicar alguno de esos parámetros, o incluso ninguno de ellos:

    PeticiónRespuesta
    GET /test/add?a=1&b=2Result: 3
    GET /test/add?a=0&b=0Result: 0
    GET /test/add?a=1Result: 1
    GET /test/addResult: 0

    Esto es así porque el binder será capaz de poblar correctamente los parámetros a y b cuando estén presentes en la cadena de la petición y sean correctos, o les asignará su valor por defecto (0) cuando no hayan sido suministrados.

    Pero dado que el cero es un valor de entrada válido, a priori desde nuestro código no tendríamos forma de distinguir cuándo el parámetro ha sido omitido y cuándo se ha establecido expresamente.

    ¿Cómo podríamos hacerlo?

    Exigir parámetros no nulos, o usar [Required]

    En parámetros de tipo valor como los usados en el ejemplo anterior, bastaría con hacerlos anulables y comprobar si sus valores son nulos, lo cual indicaría que en la petición no se incluyó un valor válido para ellos:

    public IActionResult Add(int? a, int? b)
    {
    if (a == null || b == null)
    return BadRequest();

    return Content($"Result: {a + b}");
    }

    Otra forma, muy sencilla, legible y totalmente alineada con las buenas prácticas MVC, consiste simplemente en utilizar el atributo de validación [Required] en ambos parámetros. Así, el binder establecerá el ModelState como inválido si no existen valores correctos para ellos, y podremos actuar en consecuencia, como en el siguiente código:

    public IActionResult Add([Required]int a, [Required]int b)
    {
    if (!ModelState.IsValid)
    return BadRequest();

    return Content($"Result: {a + b}");
    }

    De esta forma, en ambos casos se retornará un resultado Bad request (HTTP 400) para peticiones que no incluyan valores apropiados para los parámetros a y b.

    Obviamente, en este caso podríamos mejorarlo usando el filtro [ApiController], pues sus convenciones se encargarían de verificar la validez de los datos de entrada incluso antes de ejecutar la acción.

    ¿Y los parámetros de tipo referencia, como string?

    Lo visto anteriormente funcionará bien con parámetros enteros o cualquier otro tipo valor (long, byte, bool, decimal...), pero con los tipos referencia como string la cosa cambia un poco en función de la configuración del proyecto.

    Si tenemos habilitados los tipos referencia anulables en el proyecto ASP.NET Core 6 (por ejemplo, introduciendo la propiedad <Nullable>enable</Nullable> en el .csproj, que es la configuración por defecto), los parámetros string no permitirán la entrada de nulos durante el binding. Por tanto, el siguiente código funcionará de forma directa sin necesidad de utilizar atributos como [Required] explícitamente, porque el framework lo habrá inferido automáticamente:

    public class TestController: Controller
    {
    public IActionResult Concat(string a, string b)
    {
    if (!ModelState.IsValid)
    return BadRequest();
    return Content($"Result: '{a + b}'");
    }
    }

    Una petición como GET /test/concat retornará un error 400 (Bad request), mientras que algo como GET /test/concat?a=12&b=34 retornará "Result: '1234'".

    Esto tiene bastante sentido, pues, cuando los tipos referencia anulables están activados, la propia firma de la acción ya está indicando que esos parámetros nunca deberían recibir nulos. Por esta razón, el binder establecerá el ModelState como inválido. Si quisiésemos permitir la entrada de nulos, deberíamos haber utilizado string? en la definición de los parámetros.

    En cambio, si hubiéramos desactivado esa característica (<Nullable>disable</Nullable>), los parámetros string sí podrían contener nulos, por lo que deberíamos comprobarlos manualmente o bien utilizando [Required], igual que con los tipos valor:

    public IActionResult Concat([Required] string a, [Required] string b)
    {
    if (!ModelState.IsValid)
    return BadRequest();
    return Content($"Result: '{a + b}'");
    }

    Publicado en Variable not found.

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

    Blog Bitix

    Aplicación con interfaz gráfica para repositorios Git

    abril 18, 2022 10:00

    Una herramienta con interfaz gráfica hace más fácil algunas tareas que usar la línea de comandos directamente. Este también es el caso al trabajar con repositorios de código fuente con la herramienta de control de versiones Git. Usar la linea de comandos tiene sus propias ventajas como permitir automatizar tareas con scripts o realizar operaciones sin tener que usar la interfaz gráfica. La interfaz gráfica y la linea de comandos no son excluyentes, se pueden usar según convenga en cada ocasión. Al trabajar con múltiples repositorios de Git, para realizar operaciones comunes como commits, analizar el historial y ver las diferencias en un archivo entre dos versiones una herramienta gráfica también facilita la tarea.

    Linux

    El sistema de control de versiones Git posee una línea de comandos con la que se realizan todas las acciones para clonar repositorios, para hacer commits, para ver diferencias, para explorar el historial, para crear ramas y cualquier otra acción. La línea de comandos es muy potente y además es automatizable con un script pero como cualquier otra línea de comandos no es intuitiva y difícil de aprender y en algún caso lenta al teclear un comando, sus opciones y argumentos.

    Es aconsejable conocer los comandos básicos de línea de comandos pero en el uso diario o para algunas acciones las aplicaciones con interfaz gráfica son más rápidas, más fáciles de aprender y sin necesidad de recordar las opciones de cada comando. En GNU/Linux y GNOME una aplicación cliente de Git es gitg.

    La aplicación gitg

    Gitg es una aplicación de escritorio con interfaz gráfica que permite visualizar un repositorio de Git, su historial y el contenido de los diferentes archivos en sus versiones. No tiene todas las opciones disponibles de la línea de comandos pero si muchos incluyendo los más comunes. Usar una herramienta con interfaz gráfica puede mejorar la productividad al trabajar con varios repositorios de control de versiones en Git y permite a los usuarios que estén empezando a usar Git una forma de usarlo más intuitiva.

    Está adaptada a la guía de estilos de las aplicaciones de GNOME, es una aplicación de software libre, está disponible tanto para GNU/Linux, macOS como Windows y en GNU/Linux se puede instalar como paquete de la distribución o como una aplicación en formato Flatpak independiente de la distribución disponible en Flathub con su paquete de gitg.

    gitg

    Las operaciones que permite son:

    • Ver el historial.
    • Ver el contenido de archivos.
    • Gestionar el área de staging para componer el commit.
    • Añadir y clonar un repositorio.
    • Actualizar la información del usuario.
    • Cambiar varias opciones de preferencias.

    En esta capturas se muestran los commits, historial y merges en una linea de tiempo gráfica, además de poder ver las ramas locales, las ramas remotas, los orígenes de las ramas así como los archivos modificados en cada commit y las diferencias y cambios realizados en cada archivo.

    Aplicación gitg Aplicación gitg

    Aplicación gitg

    Aplicación gitg

    Otras aplicaciones cliente de Git que tiene características similares son Github Desktop y SmartGit esta última tiene una licencia propietaria y no es gratuita, ambas tienen su versión de Flatpak en el repositorio de Flathub.

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

    Blog Bitix

    Mecanismos eléctricos, interruptores, enchufes y desempaquetado Schneider New Unica

    abril 15, 2022 08:00

    Los mecanismos de la instalación eléctrica que tenía de mi vivienda ya tienen alguno más de 20 años, con el uso y paso del tiempo algunos interruptores estaban sucios y ni aún intentando limpiarlos quedaban completamente limpios, por otro lado un par de interruptores me estaban haciendo ruido y arco eléctrico con la consecuencia de que alguna bombilla se me estaban fundiendo no cada más de tres o más años que duran las bombillas LED sino en menos de un año. Por estos motivos y también por el motivo estético he reemplazado tanto los interruptores como los enchufes. Reemplazar los mecanismos eléctricos no es difícil con uno mínimos conocimientos pero por seguridad al manipular elementos eléctricos hay que conocerlos y no tener ninguna duda ni cometer ningún error para no tener un accidente.

    Desde hace ya unos días uno de los conmutadores de luz en la habitación me hace ruido eléctrico como si la electricidad dentro del mecanismo estuviese haciendo un arco eléctrico, otro conmutador en función de las posiciones de los interruptores también me hace el mismo ruido de arco. Esto es un problema ya que como mínimo hace que las bombillas se fundan más rápido con lo que hay que sustituirlas y en un caso grave puede ser la causa de problemas mayores como algún incendio o quemar algún elemento por el calor que se genera. A veces el arco eléctrico se puede solucionar desmontando los cables del interruptor y volviéndolos a colocar pero no siempre es suficiente.

    Por este motivo he decidido cambiar los elementos eléctricos y aunque solo sean dos los que no funcionan correctamente he sustituido todos o al menos todos los visibles porque otro motivo del cambio es el estético y que todos tenga el mismo estilo. Hay varias marcas de mecanismos eléctricos y cada marca tiene varias líneas de mecanismos con su propia estética y funcionalidad. Otro motivo por el que se puede desear hacer el cambio de mecanismos es el funcional para por ejemplo tener interruptores iluminados y mecanismos inteligentes para regular el nivel de luz o controlarlos mediante un teléfono inteligente.

    La sustitución de los mecanismos eléctricos es una tarea doméstica no complicada que no requiere un profesional, siempre y cuando se tomen ciertas precauciones y se tengan unas nociones básicas de electricidad para hacer la tarea con seguridad, sin peligro y correctamente.

    En este artículo contiene los conceptos básicos de electricidad para hacer la sustitución, los mecanismos que he elegido, cómo colocarlos y donde comprar entre otras cosas.

    ilumitec Schneider

    Advertencia

    Este artículo está escrito por alguien que apenas sabe nada sobre electricidad y simplemente se ha informado buscando en internet y haciendo algunas preguntas para las dudas que no he encontrado. Manipular electricidad y elementos eléctricos aunque sea a nivel doméstico tiene riesgos sin los conocimientos básicos sobre electricidad con lo que usa fuentes fiables generada por profesionales en la materia para informate bien.

    Contenido del artículo

    Mecanismos eléctricos

    Los mecanismos eléctricos básicos de los que trata este artículo son interruptores de luz y enchufes de electricidad para conectar aparatos y herramientas. En cuanto a interruptores hay varios tipos de interruptores dependiendo desde cuántos puntos se desean apagar y encender la luz. Los mecanismos eléctricos ha de cumplir una normativa y aunque cada marca tienen sus propias líneas de productos en cuanto a funcionalidad todos se ajustan a la normativa. Por ejemplo, un enchufe de electricidad de tipo schuko es igual en cualquier marca en cuanto a forma del producto y utiliza los mismos cables de electricidad para su conexión. También todas las marcas ofrecen en sus catálogos los mismos tipos de interruptores.

    Luego están los acabados de los mecanismos eléctricos tanto en su forma estética como en color, cada fabricante ofrece varios elementos para satisfacer los gustos y preferencias. Este artículo no habla de los elementos eléctricos del cuadro de electricidad, estos ya requieren tal vez de un profesional para su manipulación.

    Tipos de interruptores

    Una de las cosas básicas de electricidad básica es conocer que tipos de interruptores existen y cuál es la diferencia entre cada uno de ellos. Aparte de los propios mecanismos eléctricos estos requieren de un bastidor para colocarlo sobre la pared y según el modelo de interruptor algunos requieren elementos adicionales como un marco o elementos intermedios.

    En algunos casos es posible colocar dos interruptores en el mismo módulo del bastidor, las teclas que accionan el interruptor será ancha o estrecha.

    Interruptor

    Los interruptores o interruptores simples permiten controlar un elemento de luz desde un único punto. Es un mecanismo eléctrico que cierra el circuito eléctrico o lo abre con el resultado de encender o apagar el elemento luminoso. Son los interruptores más sencillos, fáciles de colocar y baratos. Únicamente requieren un par de cables, el cable de fase por donde entra la electricidad y el cable de retorno del circuito eléctrico. No estoy seguro de si en estos tipos de mecanismos la posición de los cables importa, en algún vídeo he visto que si importa pero también me han dicho que no importa con lo que aún no estoy seguro, quizá alguien que lea este artículo y sepa más que yo me pueda decir.

    Interruptor

    Interruptor

    Interruptor para un punto de luz

    Interruptor conmutador

    Los interruptores conmutadores o conmutadores permiten controlar un elemento de luz desde dos puntos. Este es el caso por ejemplo de un pasillo largo en el que se desea encender y apagar la luz desde dos puntos diferentes del pasillo. A diferencia de los interruptores simples utilizan tres cables para realizar la conexión, el cable de fase y dos cables para conectar los conmutadores entre sí que dependiendo de su estado de actuación cortan o cierran el circuito eléctrico de forma alternativa según se pulsa cada uno de ellos.

    En estos creo sí que importa que el cable de la línea esté colocado en la entrada de la línea, y también importa la posición donde se colocan los otros dos cables de modo que la posición de apagado de los pulsadores sea la correcta y la misma para ambos.

    Interruptor conmutador

    Interruptor conmutador para dos puntos de luz o en combinación con los de cruzamiento para más puntos de luz

    Interruptor de cruzamiento

    Los interruptores de cruzamiento o cruzamiento permiten controlar la luz desde tres o más puntos. Normalmente se utilizan en la habitación principal, en la que a la entrada de la habitación y a cada lado de la cama hay interruptores. Los de cruzamiento son los elementos más complicados de los tres tipos de interruptores y requieren cuatro cables para realizar la conexión eléctrica.

    Los interruptores de cruzamiento se utilizan en combinación con interruptores conmutadores. En un caso de tres puntos se utilizan dos conmutadores a los extremos del circuito y en la parte central del circuito un interruptor de cruzamiento, en los casos de más puntos de luz se van añadiendo interruptores de cruzamiento en la parte central del circuito.

    En estos creo que también importa la posición donde se colocan los cables tanto en los conmutadores como en los de cruzamiento intermedios para que la posición de apagado de los pulsadores sea la correcta y la misma para todos.

    Interruptor de cruzamiento

    Interruptor de cruzamiento para tres o más puntos de luz

    Enchufes electricidad

    Generalmente en España los enchufes de electricidad para conectar aparatos eléctricos utilizan la forma estándar de schuko. Los enchufes utilizan tres cables, el de fase por donde se proporciona la electricidad, el neutro y el de tierra por seguridad en caso de fallos eléctricos.

    Para diferenciar la función de los diferentes tipos de cables, estos por normativa tienen definido un color para cada uno de ellos. El cable de fase suele ser negro, marrón o gris, el cable de tierra es amarillo y verde y el cable neutro es azul. Es importante seguir esta normativa de colores para no tener que revisar el conexionado del circuito eléctrico y poder instalarlo con seguridad y correctamente.

    Enchufe schuko

    Enchufe schuko

    Marcos y bastidores

    Aparte del propio mecanismo eléctrico son necesarios otros elementos. El bastidor es el elemento que hace de unión entre la caja embutida de la pared, permite montar el elemento eléctrico sobre el bastidor y colocar el marco para tapar el bastidor. Los bastidores y cajas de electricidad siguen una normativa en cuanto a dimensiones que es común para todos, los bastidores suelen ser compatibles con este estándar para poder montarlos sobre las cajas. Sin embargo, cada bastidor permite colocar elementos eléctricos de esa marca e incluso únicamente de una línea específica de la marca. Por lo que al cambiar los elementos eléctricos suele ser necesario cambiar también los bastidores y los marcos.

    Los marcos son los elementos que dan el acabado al mecanismo eléctrico, permiten ocultar el bastidor al rodear el mecanismo eléctrico. Los bastidores pueden ser de plástico o de metal, para los interruptores de luz pueden utilizarse bastidores de plástico que no han de soportar mucho esfuerzo mecánico pero para los enchufes es mejor utilizar bastidores de metal ya que requieren más esfuerzo mecánico y los bastidores de metal soportan un mayor nivel de esfuerzo. Los bastidores de plástico son más baratos que los de metal pero al menos para los enchufes de electricidad es aconsejable utilizar bastidores de metal.

    Marco simple Marco doble Marco triple

    Marco simple Marco doble Marco triple

    Marcos simple, doble y triple

    Algunas marcas y series tiene bastidores también dobles y triples pero las que solo proporcionan bastidores simples permiten componer bastidores de más elementos juntando tantos simples como se necesiten. En el caso de Schneider en el serie New Unica los bastidores son simples pero permiten juntarse como piezas de un puzzle quedando consistes muy parecido a como si fuese de una sola pieza y conservando las distancias adecuadas para los marcos y las cajas de registro. La ventaja de los bastidores simples es que permiten desmontarse individualmente, su desventaja es que montarlos requiere algo más de trabajo.

    Bastidor

    Bastidor de metal

    Otros elementos eléctricos

    Los fabricantes proporcionan elementos adicionales y diferentes tipos de mecanismos para otro tipo de funcionalidades como salida de cables, reguladores, antena televisión, tapas ciegas, dispositivos inteligentes conectados, … Y algunas series utilizan elementos adicionales o intermedios para proporcionar a los elementos otro tipo de acabado estético más personalizable.

    Mecanismos originales

    Tapa ciega

    Preguntas frecuentes sobre interruptores

    Un interruptor conmutador e incluso un interruptor de cruzamiento pueden hacer la función de un interruptor simple, por ello algunas marcas para algunas líneas de interruptores solo fabrican interruptores conmutadores y no fabrican interruptores simples. Aún así aunque un interruptor conmutador y de cruzamiento puedan hacer la función de un interruptor simple generalmente si la línea de interruptores utilizada los ofrece se siguen utilizando interruptores simples ya que son más baratos. El precio entre un interruptor simple y un conmutador generalmente es de unos pocos céntimos pero la diferencia con un conmutador de cruzamiento es ya de varios euros, con lo que sí es posible es mejor utilizar interruptores simples o conmutadores, por costes no es recomendable utilizar un interruptor de cruzamiento como si fuese un interruptor simple.

    Finalmente, un interruptor conmutador no puede hacer las funciones de un interruptor de cruzamiento e igualmente un interruptor de cruzamiento no puede hacer las funciones de un interruptor conmutador.

    Desempaquetado Schneider New Unica

    Para realizar la sustitución de los elementos eléctricos he elegido los del fabricante Schneider y de la serie New Unica, en la página del fabricante se ofrece información técnica de la serie Schneider New Unica y un documento con su catálogo completo asi como sus elementos de dispositivos inteligentes conectados. Hay varios fabricantes o marcas otras reconocidas son Simon, Niessen, Legrand, bticino o Jung. Cada marca tiene varias líneas de interruptores y enchufes, con su estilo y tipos de elementos.

    No he revisado todas las marcas y series y he elegido la serie New Unica por tener un precio que suele ser lo normal entre las diferentes marcas, por su aspecto estético, ofrecer acabado en negro y la posibilidad de montarle en cada módulo de bastidor dos elementos eléctricos, dos elementos estrechos. Me gustaría haber podido comprar interruptores iluminados pero el distribuidor donde lo he comprado no tenía esas referencias de la serie entre su catálogo a la venta. Otra serie que he mirado ha sido la serie Simon 270 que también estaba en el catálogo del distribuidor donde iba a hacer la compra, pero tenía dudas si sus bastidores permitían colocar dos elementos estrechos e el mismo módulo del bastidor.

    Un aspecto a destacar de la serie New Unica de Schneider es que el conexionado es de conexionado fácil sin tornillos, la entrada de los cables están en la misma ubicación que permite que los cables queden mejor ordenados y tengan la misma longitud. El tiempo dirá si resulta y es un buen producto, en apariencia es una marca reconocida y de buena calidad. Los bticino que he reemplazado ya tenían más de 20 años , un conmutador ya me hacía ruido y arco eléctrico al encenderlo, esto además de un riesgo cuanto menos hace que las luces se fundan con mayor velocidad. Y desmontando y volviendo a colocar los cables ya lo he intentado sin solución. Además por el cambio estético y elegir el color negro según mi gusto.

    En las imágenes se muestran los diferentes mecanismos eléctricos. La galería fotográfica de los fabricantes suelen ser escasa, este artículo tiene mejores fotos para saber cómo son los elementos por ejemplo muestra como son por detrás.

    En el color antracita los Schneider New Unica tienen un diseño minimalista sin apenas detalles, menos que los bticino anteriores que tenia. La superficie de los pulsadores no es totalmente lisa sino que tiene una superficie arenosa. En color negro no se que tal soportarán la suciedad y cuando se ensucien la facilidad de limpieza. Los bastidores son de metal dando la sensación de ser capaces de soportar bastante carga ya que tiene un grosor considerable, la serie también ofrece otros de plástico a casi la mitad de precio que seguro son suficientes para los interruptores, para los enchufes son más recomendables los de metal, aún asi como la diferencia y precio simplemente es de unas decenas de céntimos el conjunto completo solo aumenta el precio total unos 10 euros por lo que si no se quiere ajustar el precio al máximo se pueden elegir los bastidores de metal para todos los elementos.

    Las imágenes de la sección anterior de mecanismos eléctricos son de la serie New Unica ya desempaquetados y abierto su embalaje, estas son las imágenes del paquete original y el embalaje de los elementos de la serie. Excepto los bastidores los demás elementos van embalados en una bolsa de plástico en la que se indica el número de la referencia al que corresponde el contenido. Las referencias qu se muestran en las imágenes están los marcos, los bastidores, enchufe schuko, interruptor ancho, interruptor estrecho y placa ciega en color antracita.

    Lo primero a realizar al recibir el paquete es comprobar que no falta nada, que contiene todos los productos y de las referencias solicitadas y están en condición de nuevo.

    Paquete con elementos Schneider New Unica

    Schneider New Unica

    Elementos Elementos Elementos

    Elementos Elementos Elementos

    Elementos Elementos Elementos

    Elementos Elementos

    Elementos de la serie Schneider New Unica

    Un vídeo sobre la serie Schneider New Unica.

    Colocación de interruptores y enchufes

    La colocación de los interruptores y enchufes no es una tarea complicada ya que no requiere más que desatornillar y atornillar y desmontar y montar cables, sin embargo, es muy importante tener unas nociones básicas sobre electricidad y hay que saber y no tener ninguna duda de lo que se está haciendo. Antes de nada dado que se está manipulando electricidad siempre se ha de cortar la electricidad completamente desde el cuadro general de la electricidad de la vivienda para evitar cualquier accidente y manipular los elementos con seguridad. Antes de hacer ningún cambio se pueden tomar unas fotos de la instalación existente para antes de hacer cambio conocer como estaba realizada la instalación.

    En el cuadro eléctrico tengo puestas unas etiquetas para saber que hace cada interruptor individual, sin embargo, algunos elementos eléctricos comparten el mismo interruptor en diferentes estancias (por ejemplo, un enchufe en la habitación y el termo de agua caliente en la cocina) con lo que para que no haya ninguna duda mejor desactivar el cuadro completo o si se apaga únicamente un interruptor comprobar que la luz o el enchufe realmente está cortado en el punto de luz a manipular haciendo caso omiso de las etiquetas indicadas en el cuadro.

    Cuadro eléctrico encendido Cuadro eléctrico apagado

    Cuadro eléctrico encendido y apagado

    Muchos mecanismos nuevos ofrecen un conexionado de fácil instalación sin necesidad de apretar tornillos tanto para los interruptores como para los enchufes. En internet y YouTube hay varios vídeos explicativos sobre cómo realizar estas tareas colocación de mecanismos eléctricos, algunos con información básica y algunos específicos utilizando los mecanismos a utilizar. En caso de no tener los conocimientos básicos antes de nada es mejor ver estos vídeos o ver algunos otros para aclarar las dudas. Hay que comprobar que los cables y bastidores quedan bien fijados, cortar los cables correctamente o limpiar las cajas de cualquier polvo si lo tuviera de construcción. Y evitar empalmes entre los cables, para ello los fabricantes ofrecen dos agujeros. En la serie de mecanismos eléctricos Schneider New Unica los cables se han de pelar con una longitud de 12 milímetros tal y como está serigrafiado en cada uno de los mecanismos con una marca visual y física de la longitud adecuada.

    En mi caso al revisar la instalación eléctrica en algunos elementos había empalmes de cables seguramente porque al utilizar una conexión mediante tornillo esto era más sencillo de colocar cada cable individualmente pero los cables no quedan todo lo mejor que podrían. Para evitar hacer empalmes, tanto los interruptores y enchufes tienen dos agujeros para cada color de cable de modo que si hay que hacer algún empalme mejor hacerlo a través de estos orificios, no solo porque es la forma más correcta y ofrece mejor seguridad sino por al hacer el empalme el grosor de la unión sea demasiada gruesa para el diámetro de un orificio. Por otro lado, en muchas cajas los obreros ni siquiera se molestaron en dejar limpia la caja y tenían gran cantidad de yeso y suciedad dentro de ellas. Así que con el cambio seguramente deje la instalación incluso algo mejor de lo que estaba.

    Los enchufes schuko tiene bastante profundidad y como haya bastante cable sobrante el mecanismo y dependiendo de la caja eléctrica para montarlo en el bastidor no debería hacer falta hacer mucha fuerza ni que se note que entra a presión, sin embargo en mis cajas en alguno si que he tenido que hacer más fuerza de la que me hubiese gustado hacer aún intentando organizar los cables lo mejor que he podido.

    Los mecanismos originales y su desinstalación.

    Mecanismos originales Mecanismos originales Mecanismos originales

    Mecanismos originales

    Mecanismos originales Mecanismos originales Mecanismos originales

    Mecanismos originales

    Los mecanismos nuevos y su instalación.

    Mecanismos nuevos Mecanismos nuevos Mecanismos nuevos

    Mecanismos nuevos Mecanismos nuevos

    Mecanismos nuevos Mecanismos nuevos Mecanismos nuevos

    Mecanismos nuevos

    Trenzar bien los cables es importante para facilitar su inserción en los mecanismos y para el correcto funcionamiento sin problemas de electricidad.

    Cables mal trenzados Cables bien trenzados

    Cables mal y bien trenzados

    Mis apuntes

    Estas son algunas pautas que he seguido para la colocación de los interruptores y enchufes para hacer la tarea correctamente, con más seguridad y sin contratiempos.

    Comprobar la electricidad de los interruptores y enchufes que funcionan correctamente para una vez desconectada la electricidad volver a comprobar y estar seguro que no tienen electricidad. Desconecta la electricidad antes de manipular ningún mecanismo. Las instalaciones más recientes permiten quitar la electricidad por estancias sin tener que quitar la electricidad general, pero en caso alguna duda siempre es mejor desconectar la electricidad general, sobre todo si el cuadro no está debidamente etiquetado. Aún después de desconectar la electricidad comprueba de nuevo que los interruptores y enchufes no tienen electricidad, los puntos de luz comprobando que la bombilla no se enciende y los puntos de electricidad comprobando con algún aparato que el enchufe no entrega electricidad. Seguramente un profesional como experto quizá no necesite estar más seguro y no necesite realizar tantas comprobaciones pero un no profesional que hace estas tareas domésticas cualquier comprobación no está demás. La tensión de la electricidad incluso en un piso doméstico es peligrosa y hay que evitar cualquier riesgo o accidente, en el peor de los casos las consecuencias pueden ser muy graves.

    Herramienta para comprobar si un enchufe tiene electricidad

    Herramienta para comprobar si un enchufe tiene electricidad (a falta de una mejor)

    Ten a mano todas las herramientas necesarias, unos destornilladores planos y unos destornilladores de estrella, del tamaño y tipo que sean necesarios, también un pelacables o en su ausencia unas tijeras que sean capaces de pelar un cable y cortar el cable de cobre. Las herramientas adecuadas que sean necesarias para hacer la tarea. Quizá unos guantes aislantes o que al trenzar las puntas de los cables de cobre eviten daño en los dedos, también para evitar que las manos se ensucien. Como algunos enchufes están bajos hay que arrodillarse, para no hacerse daño en las rodillas se puede utilizar algo como almohada como una sábana vieja doblada. Algún aparato eléctrico para comprobar que los enchufes funcionan correctamente. Un nivel para comprobar que los bastidores y marcos quedan horizontalmente que en los interruptores es más fácil verlo a simple vista pero en los enchufes que suelen estar más bajos es más difícil.

    Por si luego surgen dudas de cómo estaba la instalación y como referencia en un futuro se pueden tomar algunas fotos con un móvil, una vez cambiados los mecanismos antes de volver a dar la corriente y terminar de instalar el elemento en su bastidor y poner el marco también.

    Los cables tienen una normativa de colores y estos han de insertarse en sus orificios correspondientes tanto de los interruptores y enchufes. Los enchufes utilizan tres cables, el de linea por donde entra se entrega la corriente que tiene alguno de los colores gris, negro o marrón, el neutro o de retorno que debe azul, y el de tierra que debe ser amarillo y verde. En los enchufes hay que colocar cada uno de estos cables en sus orificios correspondientes. En los enchufes e interruptores Schneider la ubicación de cada cable está indicado por su palanca de fácil instalación sin atornillamiento. Al embornar los cables en los orificios de los mecanismos mejor hacerlo de tal forma que no queden entrelazados, que cada uno vaya a su orificio sin rodear ningún otro cable.

    Los cables se han de insertar de forma completa, hay que pelar los cables dejando una longitud de cobre al descubierto según la indicada por el fabricante del mecanismo, si se pela el cable trenzar los cables para evitar que al insertarlos se doblen. Los cables al insertarlos han de insertarse hasta el aislante, una vez insertados no debe quedar ninguna parte de cobre al aire. Los cables deben quedar bien sujetos tirando un poco de ellos para comprobar que están firmes ya se coloquen mediante mecanismo de inserción fácil de presa o atornillados. No debe quedar ningún hilo de cobre fuera de su agujero, es fácil que algún hilo rebelde se doble y quede fuera, si ocurre hay que volver a sacar el cable, volver a trenzarlo y repetir la operación de inserción. Si el mecanismo es de instalación fácil sin tornillos al insertar el cable la palanca de presa se ha de apretar completamente y luego insertar el cable, está algo dura y hay que hacer algo de fuerza.

    Una vez insertados los cables es aconsejable tomarse unos segundos para evitar algún despiste comprobando que los cables están insertados en los orificios que les corresponden según su color. El bastidor hay que ponerlo primero antes de conectar los cables al mecanismo dado que los cables han de pasar por el centro del bastidor. Si hay que limpiar las cajas de los registros poner un papel para evitar ensuciar la tarima. Las cajas de registro donde se montan los bastidores son de plástico con lo que al apretar los tornillos hay que evitar apretar en exceso para no pasarse de rosca, tampoco es necesario apretar mucho para que el bastidor quede firmemente sujeto.

    Al limpiar los registros de las cajas si están sucias y tienen mucho polvo que los obreros dejaron en la obra, al hacer la limpieza de la caja no está demás usar una mascarilla para evitar respirar el fino polvo que sale. Al manipular los cables y las cajas si tienen suciedad sin guantes las manos se van a ensuciar, si te las lavas con agua asegúrate de secarlas bien al volver a continuar con la tarea. Si se quitan muchos tonillos que no se van a colocar inmediatamente es muy útil tener un pequeño bote con tapa para guardalos ahí y que no se pierda ninguno.

    Herramientas

    Herramientas

    Para evitar que el polvo caiga a la tarima mejor poner un papel que lo evite en la medida de lo posible, solo es polvo pero al barrer es abrasivo con el barniz de la tarima si no se tiene cuidado. Se aprecia la cantidad de suciedad que dejaron en los registros de las cajas los obreros en la construcción.

    Evitar suciedad Evitar suciedad

    Evitar suciedad

    Tutoriales en vídeo

    Si buscas en YouTube algún vídeo mira primero los del fabricante que suelen subir en sus cuentas videotutoriales de como colocar sus mecanismos. También hay profesionales que suben vídeos con tutoriales explicando los conocimientos básicos sobre electricidad para personas que no tienen los conocimientos básicos. Busca los vídeos en los que estén bien explicados y sean de alguien que demuestre tener conocimientos y ser profesional (porque hay algunos vídeos de algunos profesionales que no lo parecen y están más en un festival de humor), en caso de duda ver algún vídeo más o buscar otro.

    En los siguientes vídeos que forman parte de un curso de electricidad básica en formato vídeo se explican muy bien los conocimientos básicos sobre electricidad, de enchufes e interruptores, conmutadores y de cruzamiento mostrando en vídeo cómo colocar cada uno de ellos, consejos y precauciones.

    Estos son los tutoriales para la instalación de interruptores y enchufes.

    Dónde comprar los mecanismos eléctricos

    Hay numerosos distribuidores que ofrecen mecanismos eléctricos tanto en tienda física como por internet y en algunos casos ambos. No todos tienen todas las marcas, las series y el catálogo completo de referencias de las series con lo que en caso de querer una específica requiere comprobar que entre su catálogo tengan lo deseado.

    En caso de realizar una sustitución completa de los elementos eléctricos es recomendable realizar un inventario de qué elementos se necesitan y que al realizar la compra o el pedido no falte ninguno. Este inventario puede ser una tabla como la siguiente que permite ver rápidamente y comprobar los elementos por estancia y los totales a pedir. Incluso por tener algún repuesto en caso de que alguno falle en el futuro se puede incluir en el pedido alguno adicional más de algún tipo.

    Elemento Total Estancia 1 Estancia 2 Estancia 3 Estancia 4 Estancia 5 Estancia 6
    Bastidor 1 módulo 12 4 2 3 3
    Bastidor 2 modulos 1 1
    Bastidor 3 modulos 2 1 1
    Marco 1 módulo 12 4 2 3 3
    Marco 2 modulos 1 1
    Marco 3 modulos 2 1 1
    Enchufes 8 4 3 1
    Interruptor 2 2
    Interruptor (estrecho) 3 1 2
    Conmutador 3 2 1
    Conmutador (estrecho) 1 1
    Cruzamiento 1 1
    Cruzamiento (estrecho) 0
    Tapa ciega 4 2 2

    Leroy Merlin y Bricomart son dos tiendas especializadas en diferentes áreas de elementos para el hogar y de construcción que tienen canales de venta tanto físico como en línea a través de internet. Hay otras tiendas especializadas que realizar compra por internet como Ilumitec que seguramente tangan cualquier material eléctrico que alguien necesite y a precios económicos, esta ha sido donde he hecho la compra. En caso de realizar la compra por internet permiten hacer el pago utilizando diferentes formas de pago por tarjeta e incluso mediante PayPal que siempre da más seguridad en tiendas que encontramos en los primeros resultados en el buscador de páginas. En mi caso Amazon para esto lo he descartado porque no ofrece el catálogo completo de referencias de la serie y las referencias que están tienen unos precios bastante mayor que en tiendas especializadas.

    En caso de realizar la compra por internet hay que leer siempre siempre las condiciones de compra ya que en ella se detallan las condiciones en caso de devolución y quien se hará cargo de los gastos de envío. Antes de formalizar la compra hay que revisar varias veces el pedido, por ello es recomendable hacer un inventario de los elementos necesarios como la anterior. Hay series con un gran número de referencias, algunos distribuidores ofrecen gran número de referencias y en caso de sustituir todos los mecanismos eléctricos hay que hacer un pedido con un gran número de ellos. Una vez llega el paquete lo primero es comprobar que contiene todos los elementos, del tipo solicitado, comprobar su estado y que no falta ninguno para si fuera el caso ponerse en contacto con el vendedor y solucionar el problema.

    La compra la he realizado en Ilumitec, el envío del paquete ha sido rápido mediante el transportista Seur, con todos los elementos del pedido, en buen estado y cumpliendo el plazo orientativo indicado al hacer la compra. No puedo hablar de la atención al cliente porque no ha sido necesario que me ponga en contacto con ellos pero para realizar la compra en su página web y el pago ha funcionado todo correctamente. Además, ofrece PayPal como medio de pago que proporciona garantías adicionales en caso de disputas, también con PayPal por no tener que proporcionar el número de la tarjeta de crédito.

    Complementos para los interruptores y enchufes

    Además de los elementos eléctricos puede que sea necesario comprar otros productos relacionados. Por ejemplo, en caso de que los marcos sean de diferente tamaño para pintar la pared en caso de que quede marca de suciedad por que la caja no está bien aislada y el polvo que entra deja marca en la pared con la corriente de aire que entra por los tubos y pared. Si se necesita poca pintura para hacer pequeños arreglos Bruger en Amazon hay disponibles unos probadores de color que se pueden utilizar y son suficientes para hacer los pequeños arreglos para corregir esas pequeñas marcas de suciedad.

    Marca de suciedad

    Marca de suciedad en la pared

    Otro productos puede ser algo de escayola para arreglar algún desperfecto en la pared o la caja del registro eléctrico. Unas tapas de enchufes schuko para que no se les acumule polvo mientras no se usan, cable eléctrico en caso de tener que sustituir alguno que puentea mecanismos, pintura, pinceles o brochas junto con disolvente. De todo estos productos están disponibles en tiendas especializadas y en Amazon también se ofrecen.

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

    Blog Bitix

    Por qué y ejemplo de cómo desarrollar un plugin de Gradle

    abril 07, 2022 06:00

    Generalmente cuando se necesita una funcionalidad en Gradle esta suele estar proporcionada por los propios desarrolladores de Gradle, por los propios mantenedores de otras herramientas para integrarlas en Gradle o en último caso por alguien que antes ha tenido la misma necesidad ha publicado un plugin. Si aún así no hay un plugin que ofrezca la funcionalidad que se desea, Gradle ofrece la posibilidad de que cualquiera desarrolle sus propios plugins y los use para sus necesidades específicas o en caso de ser útil para otras personas compartirlo en un repositorio público como cualquier otro.

    Gradle

    Java

    Gradle es una herramienta de construcción y gestión del ciclo de vida de un proyecto principalmente usando en proyectos Java. Realiza importantes tareas como la descarga y gestión de las dependencias y resolución de conflictos entre las diferentes versiones que necesite una aplicación, tareas importantes que ni el sistema de módulos de Java proporciona. Permite ejecutar de forma sencilla la aplicación o las pruebas unitarias de código entre otras muchas tareas que pueden ser automatizadas como pruebas estáticas de código y generación de artefactos además de ser suficientemente flexible para adaptarse a las necesidades que haya en un proyecto.

    Por todas estas importantes tareas que realiza Gradle es una herramienta imprescindible en cualquier cualquier proyecto Java. Su alternativa más usada es Maven que tiene un modelo declarativo y basado en XML con unos archivos más verbosos. Ambas herramientas se consideran ya maduras generalmente equivalentes para la mayoría de funcionalidades más comunes. Dado que los archivos de configuración de Gradle son menos verbosos, más legibles y fáciles de editar que el XML es la herramienta elegida como herramienta de construcción para muchos proyectos.

    Cuando la funcionalidad ofrecida por Gradle no es suficiente, no existe un plugin de un tercero o no está adaptado a las necesidades de un proyecto u organización al igual que otros han desarrollado sus propios plugins cualquiera puede desarrolalr plugins con la interfaz que ofrece Gradle para su desarrollo y extender su funcionalidad.

    Contenido del artículo

    Por qué desarrollar un plugin propio de Gradle

    Es seguro que en una empresa a lo largo del tiempo esta desarrolle varios proyectos, siendo varios una cantidad de unas pocas decenas a cientos dependiendo del tamaño de la organización. Con múltiples proyectos por motivos de mantenimiento el copiar y pegar código entre proyectos no es una opción viable con lo que también seguro que surge la necesidad de reutilizar código propio de la organización entre los diferentes proyectos tal y como se reutiliza código de otras librerías como Spring, Hibernate y otra multitud de librerías desarrolladas por terceros. La forma de reutilizar código en Java es a través de librerías que se publican en un repositorio de Maven igual que cualquier otra librería de terceros.

    También es seguro que con múltiples proyectos surge la necesidad de reutilizar código entre múltiples proyectos incluso en la herramienta de construcción. La forma que ofrece Grade de reutilizar código es a través de plugins. En el caso de la herramienta de construcción un plugin permite aplicar a todos los proyectos de forma sencilla, homogénea, mantenible y sin copiar y pegar elementos comunes considerados un estándar en la organización como comprobaciones estáticas de código con PMD, Checkstyle y SpotBugs entre otras muchas cosas propias de una organización. Muchos terceros publican plugins que cualquiera puede aplicar a un proyecto si este plugin ofrece la funcionalidad que necesita y si no existe ninguno también es posible desarrollar uno propio ajustado a las necesidades propias.

    Gradle ofrece un sistema muy flexible y extensible para desarrollar, publicar y reutilizar plugins. En su documentación hay varias páginas que explican cómo desarrollar un plugin, y otros muchos artículos incluido el presente.

    Por ejemplo, hace tiempo hice un ejemplo en el que generaba un archivo al hacer la construcción y generación del artefacto que incluía información del artefacto como la versión, fecha de construcción, hash del commit y número de build de modo que en tiempo de ejecución el código tenga información para mostrar esa versión en las trazas y conocer la versión exacta del código desplegado en un entorno. Otro caso puede ser que se desee una funcionalidad similar al plugin de Maven Release que permite automatizar la generación de versiones de los proyectos para la que en Gradle la opción equivalente con gradle-release su última versión es del 2017.

    Conceptos de Gradle

    Gradle define varios conceptos propios para la configuración y ejecución. La configuración permite cambiar el comportamiento o adaptarlo a las necesidades propias. La configuración se definen en lo que Gradle denomina extensiones que son simplemente objetos de datos en los que Gradle permite al usuario introducir datos y que en el archivo de construcción se manifiestan como bloques de configuración con propiedades, las tareas al ejecutarse obtienen las extensiones y los datos configurados en ellas, en función de los datos las tareas varían su comportamiento.

    Los plugins a través de la API que ofrece Gradle pueden realizar cualquier acción que permita la API como por ejemplo aplicar nuevos plugins al proyecto, definir objetos de extensiones, definir nuevas tareas o cambiar el comportamiento de tareas existentes. Con estas funcionalidades a disposición de cualquiera es posible crear un plugin de Gradle en el que encapsular cualquier funcionalidad relativa al ciclo de vida del proyecto, aplicarla y utilizarla en cualesquiera proyectos.

    Una vez creado el plugin este se publica y comparte en un repositorio de Maven del que los proyectos que lo quieran usar simplemente han de incluir la URL del repositorio y la referencia al plugin.

    Ejemplo de plugin para Gradle

    Lo que hace este ejemplo es mediante código aplicar cambios a través de la clase Project que representa al proyecto de Gradle. A través de esta clase se añaden nuevos plugins, se configuran las extensiones y las tareas para aplicar la funcionalidad deseada en el plugin.

    El ejemplo añade los plugins y configura sus extensiones para realizar comprobaciones estáticas de código a través de las herramientas PMD, Checkstyle, SpotBugs y sus plugins para Gradle. Además, la funcionalidad del plugin es generar un archivo con información de la versión del artefacto incluyendo su versión, fecha de construcción, hash del commit y número de build para conocer esta información del artefacto.

    Incluir información variable en el artefacto que es diferente en función de la fecha de ejecución hace que la generación no sea reproducible, esto es, no genere exactamente el mismo binario dado que su contenido es diferente con cada build aunque el código no haya cambiado y solo lo haya hecho un archivo de configuración y únicamente ligeramente su contenido. Que la generación de los artefactos sean reproducibles tiene el beneficio de que el artefacto generado sea auditable por motivos de seguridad y es posible que esté libre de modificaciones diferentes del código empleado para la construcción.

    Crear un plugin de Gradle

    Hay varias formas de desarrollar un plugin de Gradle, se puede desarrollar dentro de un proyecto existente o como un proyecto independiente, Gradle ofrece un comando para disponer de la estructura básica de un proyecto para el plugin rápidamente y de forma sencilla al igual que se realiza para disponer de una aplicación normal. En el archivo de construcción del plugin que genera Gradle incluye un plugin propio de Gradle necesario para desarrollar plugins de Gradle, java-gradle-plugin.

    Los plugins de Gradle se crean proporcionando una implementación de la interfaz Plugin, esta clase ofrece el método apply que Gradle invoca para que el plugin modifique el proyecto a través de la instancia de Project que lo representa y se proporciona como argumento del método. La clase Project ofrece métodos para añadir nuevos plugins al proyecto, obtener los objetos que contienen los datos de las extensiones, permite añadir o modificar tareas existentes y crear dependencias entre las tareas. En el siguiente código se observan estas modificaciones en el proyecto en el plugin del ejemplo.

    Dado que el plugin de ejemplo configura otros plugins existentes necesita de las clases de los plugins y de sus extensiones de modo que han de incluirse como una dependencia del plugin desarrollado en el archivo de construcción del plugin. El plugin también puede proporcionar sus propias clases de extensiones.

      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
    
    package io.github.picodotdev.blogbitix.javagradleplugin;
    
    import java.io.File;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.Optional;
    import java.util.stream.Collectors;
    
    import com.github.spotbugs.snom.SpotBugsExtension;
    import com.github.spotbugs.snom.SpotBugsPlugin;
    import org.apache.tools.ant.filters.ReplaceTokens;
    import org.gradle.api.Plugin;
    import org.gradle.api.Project;
    import org.gradle.api.file.DuplicatesStrategy;
    import org.gradle.api.java.archives.Manifest;
    import org.gradle.api.plugins.JavaApplication;
    import org.gradle.api.plugins.quality.CheckstyleExtension;
    import org.gradle.api.plugins.quality.CheckstylePlugin;
    import org.gradle.api.plugins.quality.PmdExtension;
    import org.gradle.api.plugins.quality.PmdPlugin;
    import org.gradle.api.tasks.Copy;
    import org.gradle.api.tasks.bundling.Jar;
    
    public class JavaGradlePlugin implements Plugin<Project> {
    
        private static final String SPOTBUGS_EXCLUDE_RESOURCE = "/spotbugs/spotbugs-exclude.xml";
        private static final String CHECKSTYLE_CONFIG_RESOURCE = "/checkstyle/checkstyle.xml";
        private static final String CHECKSTYLE_SUPPRESSIONS_RESOURCE = "/checkstyle/suppressions.xml";
    
        public void apply(Project project) {
            project.getPluginManager().apply(PmdPlugin.class);
            project.getPluginManager().apply(CheckstylePlugin.class);
            project.getPluginManager().apply(SpotBugsPlugin.class);
    
            JavaGradlePluginExtension javaGradlePluginExtension = project.getExtensions().create("version", JavaGradlePluginExtension.class);
            javaGradlePluginExtension.getVersionEnabled().convention(Boolean.FALSE);
    
            PmdExtension pmdExtension = project.getExtensions().getByType(PmdExtension.class);
            pmdExtension.setToolVersion("6.44.0");
            pmdExtension.setConsoleOutput(true);
            pmdExtension.setIgnoreFailures(false);
            pmdExtension.setRuleSets(List.of("category/java/bestpractices.xml"));
    
            CheckstyleExtension checkstyleExtension = project.getExtensions().getByType(CheckstyleExtension.class);
            checkstyleExtension.setConfigFile(getFileFromResource(project, CHECKSTYLE_CONFIG_RESOURCE));
            checkstyleExtension.setConfigProperties(Map.of("suppressionFile", getFileFromResource(project, CHECKSTYLE_SUPPRESSIONS_RESOURCE)));
            checkstyleExtension.setMaxWarnings(0);
            checkstyleExtension.setMaxErrors(0);
    
            SpotBugsExtension spotBugsExtension = project.getExtensions().getByType(SpotBugsExtension.class);
            spotBugsExtension.getToolVersion().convention("4.2.2");
            spotBugsExtension.getShowProgress().convention(true);
            spotBugsExtension.getIgnoreFailures().convention(true);
            spotBugsExtension.getExcludeFilter().convention(() -> getFileFromResource(project, SPOTBUGS_EXCLUDE_RESOURCE));
    
            project.getTasks().named("processResources", Copy.class).configure(copy -> {
                copy.from("src/main/resources", (itCopySpec) -> {
                    itCopySpec.setDuplicatesStrategy(DuplicatesStrategy.INCLUDE);
                    itCopySpec.from("src/main/resources", (itFrom) -> {
                        itFrom.include("banner.txt");
                        itFrom.exclude("version.properties");
                    });
                    Map<String, String> tokens = new HashMap<>();
                    tokens.put("gradle.app.name", project.getName());
                    tokens.put("gradle.version.version", getPluginVersion(project).get().toString());
                    tokens.put("gradle.version.build", getPluginVersion(project).get().getBuild());
                    tokens.put("gradle.version.hash", getPluginVersion(project).get().getHash());
                    tokens.put("gradle.version.timestamp", getPluginVersion(project).get().getTimestamp());
                    tokens.put("gradle.version.string", getPluginVersion(project).get().getString());
                    tokens.put("gradle.version.formatted-string", getPluginVersion(project).get().getFormattedString());
                    itCopySpec.filter(Map.of("beginToken", "${", "endToken", "}", "tokens", tokens), ReplaceTokens.class);
                });
            });
    
            project.getTasks().named("jar", Jar.class).configure(jar -> {
                jar.manifest((Manifest manifest) -> {
                    Map<String, String> attributes = new HashMap<>();
                    attributes.put("Class-Path", project.getConfigurations().getByName("runtimeClasspath").getFiles().stream().map(it -> String.format("files/%s", it.getName())).collect(
                            Collectors.joining(" ")));
                    if (project.getExtensions().getByType(JavaApplication.class).getMainClass().isPresent()) {
                        attributes.put("Main-Class", project.getExtensions().getByType(JavaApplication.class).getMainClass().get());
                    }
                    attributes.put("App-Name", project.getName());
                    if (getPluginVersion(project).isPresent()) {
                        attributes.put("App-Version", getPluginVersion(project).get().toString());
                    }
                    manifest.attributes(attributes);
                });
            });
        }
    
        private File getFileFromResource(Project project, String resource) {
            return project.getResources().getText().fromUri(getClass().getResource(resource)).asFile();
        }
    
        private Optional<Version> getPluginVersion(Project project) {
            if (project.getVersion() instanceof Version) {
                return Optional.of((Version) project.getVersion());
            }
            return Optional.empty();
        }
    }
    
    JavaGradlePlugin.java
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    package io.github.picodotdev.blogbitix.javagradleplugin;
    
    import org.gradle.api.provider.Property;
    
    public interface JavaGradlePluginExtension {
    
      Property<Boolean> getCheckstyleEnabled();
      Property<Boolean> getVersionEnabled();
    }
    
    JavaGradleExtension.java
      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    
    package io.github.picodotdev.blogbitix.javagradleplugin;
    
    import java.nio.charset.Charset;
    import java.time.ZoneId;
    import java.time.ZonedDateTime;
    import java.time.format.DateTimeFormatter;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    import java.util.Map;
    import java.util.concurrent.TimeUnit;
    import java.util.stream.Collectors;
    
    public class Version {
    
        private String version;
        private String build;
        private String hash;
        private String timestamp;
    
        public Version() {
            this(Collections.emptyMap());
        }
    
        public Version(Map<String, String> properties) {
            this.version = properties.getOrDefault("version", "0.0.0");
            this.build = properties.getOrDefault("build", System.getenv("BUILD_NUMBER"));
            this.hash = properties.getOrDefault("hash", getGitHash());
            this.timestamp = properties.getOrDefault("timestamp", DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ssX").format(ZonedDateTime.now(ZoneId.of("UTC"))));
            if (this.build == null) {
                this.build = "0";
            }
            if (this.hash == null) {
                this.hash = "0000000";
            }
        }
    
        public String getVersion() {
            return version;
        }
    
        public int getVersionMajor() {
            String n = version.split(".")[0];
            return Integer.parseInt(n);
        }
    
        public int getVersionMinor() {
            String n = version.split(".")[1];
            return Integer.parseInt(n);
        }
    
        public int getVersionPatch() {
            String n = version.split(".")[2];
            return Integer.parseInt(n);
        }
    
        public String getBuild() {
            return build;
        }
    
        public String getHash() {
            return hash;
        }
    
        public String getTimestamp() {
            return timestamp;
        }
    
        public String getString() {
            List<String> strings = new ArrayList<>();
            strings.add(String.format("v%s", version));
            strings.add(String.format("b%s", build));
            strings.add(String.format("h%s", hash));
            strings.add(String.format("d%s", timestamp));
            return strings.stream().collect(Collectors.joining("-"));
        }
    
        public String getFormattedString() {
            return String.format(" (%s)", getString());
        }
    
        @Override
        public String toString() {
            return version;
        }
    
        private String getGitHash() {
            try {
                Process process = Runtime.getRuntime().exec("git log -n 1 --format=%h");
                process.waitFor(5000, TimeUnit.SECONDS);
                if (process.exitValue() != 0) {
                    return null;
                }
    
                return new String(process.getInputStream().readAllBytes(), Charset.forName("UTF-8")).trim();
            } catch (Exception e) {
                return null;
            }
        }
    }
    Version.java
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    
    plugins {
        id 'java-gradle-plugin'
        id 'maven-publish'
    }
    
    project.group = 'io.github.picodotdev.blogbitix.javagradleplugin'
    project.version = "1.0"
    
    java {
        sourceCompatibility = JavaVersion.VERSION_11
        targetCompatibility = JavaVersion.VERSION_11
    }
    
    repositories {
        mavenCentral()
        gradlePluginPortal()
    }
    
    dependencies {
        implementation 'com.github.spotbugs.snom:spotbugs-gradle-plugin:5.0.6'
        implementation 'com.puppycrawl.tools:checkstyle:10.1'
        implementation 'net.sourceforge.pmd:pmd:6.44.0'
    }
    
    gradlePlugin {
        plugins {
            javaGradlePlugin {
                id = 'io.github.picodotdev.blogbitix.javagradleplugin'
                implementationClass = 'io.github.picodotdev.blogbitix.javagradleplugin.JavaGradlePlugin'
            }
        }
    }
    
    build.gradle

    Los plugins de Gradle se publican en un repositorio de Maven como cualquier librería o aplicación, Gradle compila el plugin y lo publica. Para desarrollar es posible publicar el plugin en el repositorio de Maven local.

    1
    2
    
    $ ./gradlew publishToMavenLocal
    
    
    gradlew-publishtomavenlocal.sh

    También es posible realizar teses unitarios y funcionales sobre el plugin, al utilizar la tarea de creación del proyecto del plugin Gradle crea unos ejemplos en los basarse para crear más.

    Aplicar el plugin de Gradle a un proyecto

    Una vez el plugin está en el repositorio de Maven usar el plugin y aplicarlo a un proyecto es exactamente igual que cualquier otro plugin de Gradle, basta incluirlo en la sección plugins con su identificador y su versión. Una vez aplicado el plugin como este añade otros plugins al ejecutar la tareas tasks que muestra las tareas existentes en el proyecto se observa que aunque los plugins de PMD, Checkstyle, SpotBugs han incluido sus tareas en el proyecto aunque no se hayan aplicado de forma explícita sino de forma transitiva a través del plugin propio.

    1
    2
    
    $ ./gradlew tasks
    
    
    gradlew-tasks.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
    
    > Task :tasks
    
    ------------------------------------------------------------
    Tasks runnable from root project 'java-application'
    ------------------------------------------------------------
    
    Application tasks
    -----------------
    run - Runs this project as a JVM application
    
    Build tasks
    -----------
    assemble - Assembles the outputs of this project.
    build - Assembles and tests this project.
    buildDependents - Assembles and tests this project and all projects that depend on it.
    buildNeeded - Assembles and tests this project and all projects it depends on.
    classes - Assembles main classes.
    clean - Deletes the build directory.
    jar - Assembles a jar archive containing the main classes.
    testClasses - Assembles test classes.
    
    Build Setup tasks
    -----------------
    init - Initializes a new Gradle build.
    wrapper - Generates Gradle wrapper files.
    
    Distribution tasks
    ------------------
    assembleDist - Assembles the main distributions
    distTar - Bundles the project as a distribution.
    distZip - Bundles the project as a distribution.
    installDist - Installs the project as a distribution as-is.
    
    Documentation tasks
    -------------------
    javadoc - Generates Javadoc API documentation for the main source code.
    
    Help tasks
    ----------
    buildEnvironment - Displays all buildscript dependencies declared in root project 'java-application'.
    dependencies - Displays all dependencies declared in root project 'java-application'.
    dependencyInsight - Displays the insight into a specific dependency in root project 'java-application'.
    help - Displays a help message.
    javaToolchains - Displays the detected java toolchains.
    outgoingVariants - Displays the outgoing variants of root project 'java-application'.
    projects - Displays the sub-projects of root project 'java-application'.
    properties - Displays the properties of root project 'java-application'.
    tasks - Displays the tasks runnable from root project 'java-application' (some of the displayed tasks may belong to subprojects).
    
    Verification tasks
    ------------------
    check - Runs all checks.
    spotbugsMain - Run SpotBugs analysis for the source set 'main'
    spotbugsTest - Run SpotBugs analysis for the source set 'test'
    test - Runs the test suite.
    
    To see all tasks and more detail, run gradlew tasks --all
    
    To see more detail about a task, run gradlew help --task <task>
    
    BUILD SUCCESSFUL in 628ms
    1 actionable task: 1 executed
    gradlew-tasks.out

    Ejecutando la build la tarea se genera el archivo como un recurso que se procesa al que se le realizan varias sustituciones con los valores que permite en tiempo de ejecución conocer información de la versión de la librería o aplicación, este archivo se incluye en el jar de la librería o aplicación y es posible acceder a él como un recurso más.

    1
    2
    3
    4
    5
    6
    7
    
    app.version.name=app
    app.version.version=1.0.0
    app.version.build=0
    app.version.hash=5f9b859
    app.version.timestamp=2022-04-07-17-41-30Z
    app.version.string=v1.0.0-b0-h5f9b859-d2022-04-07-17-41-30Z
    app.version.formatted-string= (v1.0.0-b0-h5f9b859-d2022-04-07-17-41-30Z)
    version.properties
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    
    package io.github.picodotdev.blogbitix.javaapplication;
    
    import java.io.InputStream;
    import java.util.Properties;
    
    public class App {
    
        public static void main(String[] args) throws Exception {
            InputStream inputStream = App.class.getResourceAsStream("/version.properties");
    
            Properties properties = new Properties();
            properties.load(inputStream);
    
            System.out.println(properties.getProperty("app.version.formatted-string"));
    
        }
    }
    
    App.java
    1
    2
    
    $ ./gradlew run
    
    
    gradlew-run.sh
    1
    2
    3
    4
    5
    
    > Task :app:run
    (v1.0.0-b0-h5f9b859-d2022-04-07-17-41-30Z)
    
    BUILD SUCCESSFUL in 614ms
    3 actionable tasks: 1 executed, 2 up-to-date
    gradlew-run.out

    Al ejecutar la tarea de build dado que se han incluido los plugins PMD, CheckStyle y Spotbugs sus tareas de validación se ejecutan y detectan los errores en los archivos del código fuente según las reglas de validación configuradas. En el código de ejemplo Checkstyle indica que hay el código no está formateado de forma apropiada siguiendo las convenciones establecidas para el proyecto.

    1
    2
    
    $ ./gradlew build
    
    
    gradlew-build.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
    
    > Task :app:checkstyleMain FAILED
    [ant:checkstyle] [WARN] /home/picodotdev/Documentos/Software/personal/blog-ejemplos/GradlePlugin/JavaApplication/app/src/main/java/io/github/picodotdev/blogbitix/javaapplication/App.java:8:5: method def modifier en el nivel de sangrado 4 no está al nivel correcto, 2 [Indentation]
    [ant:checkstyle] [WARN] /home/picodotdev/Documentos/Software/personal/blog-ejemplos/GradlePlugin/JavaApplication/app/src/main/java/io/github/picodotdev/blogbitix/javaapplication/App.java:9:9: method def el descendiente en el nivel de sangrado 8 no está al nivel correcto, 4 [Indentation]
    [ant:checkstyle] [WARN] /home/picodotdev/Documentos/Software/personal/blog-ejemplos/GradlePlugin/JavaApplication/app/src/main/java/io/github/picodotdev/blogbitix/javaapplication/App.java:11:9: method def el descendiente en el nivel de sangrado 8 no está al nivel correcto, 4 [Indentation]
    [ant:checkstyle] [WARN] /home/picodotdev/Documentos/Software/personal/blog-ejemplos/GradlePlugin/JavaApplication/app/src/main/java/io/github/picodotdev/blogbitix/javaapplication/App.java:12:9: method def el descendiente en el nivel de sangrado 8 no está al nivel correcto, 4 [Indentation]
    [ant:checkstyle] [WARN] /home/picodotdev/Documentos/Software/personal/blog-ejemplos/GradlePlugin/JavaApplication/app/src/main/java/io/github/picodotdev/blogbitix/javaapplication/App.java:14:9: method def el descendiente en el nivel de sangrado 8 no está al nivel correcto, 4 [Indentation]
    [ant:checkstyle] [WARN] /home/picodotdev/Documentos/Software/personal/blog-ejemplos/GradlePlugin/JavaApplication/app/src/main/java/io/github/picodotdev/blogbitix/javaapplication/App.java:16:5: method def rcurly en el nivel de sangrado 4 no está al nivel correcto, 2 [Indentation]
    
    FAILURE: Build failed with an exception.
    
    * What went wrong:
    Execution failed for task ':app:checkstyleMain'.
    > Checkstyle rule violations were found. See the report at: file:///home/picodotdev/Documentos/Software/personal/blog-ejemplos/GradlePlugin/JavaApplication/app/build/reports/checkstyle/main.html
      Checkstyle files with violations: 1
      Checkstyle violations by severity: [warning:6]
    
    
    * Try:
    > Run with --stacktrace option to get the stack trace.
    > Run with --info or --debug option to get more log output.
    > Run with --scan to get full insights.
    
    * Get more help at https://help.gradle.org
    
    BUILD FAILED in 1s
    7 actionable tasks: 5 executed, 2 up-to-date
    gradlew-build.out
    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 build

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

    Coding Potions

    Mis primeras impresiones usando emacs

    abril 05, 2022 12:00

    En este artículo voy a contar mis primeras impresiones usando el editor de textos Emacs . Lo primero que tengo que decir es que vengo de Vim por lo que fijo que voy a comparar ambos editores. Como digo, esto es mi opinión personal, por lo que para otra persona la experiencia sea completamente distinta.

    Por qué probar emacs

    Lo primero que tengo que decir es que me molaba la idea de usar Emacs porque parece un editor muy bien integrado con todo. Como suelen decir los usuarios de emacs es un sistema operativo en sí mismo con un editor de textos incorporado.

    Y es que Vim está más limitado en ese aspecto porque trata de ser muy simple, y además está pensado para utilizarse en consola (aunque tiene versión gráfica gvim, pero las limitaciones son las mismas).

    Y es que me molaba la idea de tenerlo todo en emacs: consolas, debuggers, notas, clientes HTTP, correo, etc. Se supone que la gente que usa emacs para todo no abre otra aplicación en todo el día, incluso navegan por Internet desde el editor.

    También quería comprobar que tal las cosas que en Vim están más limitadas o hay que hacer malabares para poder usarlas: LSP, Dap, etc.

    Por último está el tema de Org, que es una manera que tiene Emacs de escribir ficheros de notas que son muy potentes. Por lo que he visto puedes crear secciones que se pueden expandir y colapsar, tablas automáticas, tareas integradas, etc.

    Aquí tengo que decir que soy muy fan de Markdown por su simplicidad y porque me sirve para lo que quiero, pero quiero probar Org igualmente.

    Bien, una vez visto por encima lo que me llama la antención de Emacs vamos al lío.

    Cómo instale y configuré emacs

    Una vez instalado, cuando lo abres de cero aparece una pantalla en blanco muy fea de bienvenida a Emacs. Esto no me sorprende ni me da miedo porque en Vim pasa un poco lo mismo, lo abres y no tienes nada más, al menos en Emacs tienes un menú.

    Aquí lo primero que hice fue buscar ficheros de config que usa la gente para ver un poco mis posibilidades. También encontré dos configs muy populares ya creadas: ^spacemacs y doom-emacs. Ambas configs utilizan keybindings de Vim, por cierto.

    Decidí tirar por config propia porque, aunque esas configs están muy bien hechas, cambian demasiado la experiencia de usar Emacs (aunque fijo que las pruebo).

    Lo primero es saber que Emacs emplea una variante del lenguaje Lisp para generar estos ficheros de configs y crear plugins (en concreto se llama Emacs Lips o Elisp para abreviar).

    Este lenguaje supongo que tendrá su utilidad para programar y tal, pero para algo simple creo que lia bastante. Aquí tengo que decir que Vim con su Vimscript tampoco es que sea mejor (aunque ahora con Neovim y Lua la cosa puede cambiar).

    Miré la serie de vídeos muy recomendada de System Crafters, en la que produce una config de Emacs desde 0 explicada paso por paso.

    Tengo que decir que la config que empleo es muy parecida a la de esa serie, salvo que he cambiado un par de keybindings para que sean parecidos a los que tenía en Vim, además de añadir evil-mode, un paquete que añade todos los keybindings de Vim a la hora de editar ficheros.

    Mi Emacs luce tal que así:

    Pantalla de emacs con el tema night owl

    Opiniones tras usar emacs

    Tras usar emacs con la config mencionada durante unos días tengo que decir que hay cosas que me gustan y otras que no me gustan nada. Aviso: hay muchas cosas no me gustan porque todavía tengo que buscar más config y actualizar la que tengo.

    Para empezar el plugin de projectile está guay porque permite abrir varios proyectos que estés desarrollando a la vez. En vim lo que hacía era abrir otra tab de la terminal y abrir otro Vim.

    Projectile tiene un comando para buscar ficheros en los proyectos (nada que no se haya visto ya en vscode o vim), simplemente escribes y busca ficheros con ese nombre.

    Cuando busco ficheros hay un tema que no me gusta y es que no hace fuzzy fidning, es decir, aunque puedo simplemente poner nombre de fichero o carpeta, si por ejemplo quiero buscar el fichero userList.js, si escribo “usli” no me sale ningún resultado. Esto con Vim y el plugin te Telescope está resuelto sin tener que escribir bien el nombre completo todo el rato.

    Supongo que tendré que buscar otra config para Projectile (aunque no he encontrado mucho en Internet) o usar otro plugin solo para esto.

    Respecto a los keybindings los de emacs se me hacen muy extraños (hablo de los comandos que no tienen que ver con editar texto porque como ya he dicho utilizo los de vim). Son comandos de pulsar el control + otra tecla + luego otra vez control + otra tecla y así, cuestión de acostumbrarse..

    Como muchos keybindings son de pulsar el control pues han cambiado las teclas hasta para hacer el mítico Control C + Control V, cosa que tampoco me gusta mucho.

    Otra cosa que no me mola es lo de la terminal. Osea mola mucho poder abrir terminales (como pasa en vscode) pero debe ser que las eshells no las tengo bien configuradas porque no me cargan los colores dentro de la terminal (puede que pase por el tema que estoy utilizando, el de night owl), ah y no funciona el Control R para buscar comandos, tendré que investigar.

    También con las terminales odio que no puedas abrir varias eshells. Lo que he visto por Internet es que la gente renombra el buffer de la terminal para poder abrir más (pereza).

    Tengo que investigar más sobre las terminales porque al parecer hay muchas (esell, vterm y unas pocas más).

    También he instalado ivy para poder tener un menú algo más cómodo para ejecutar los comandos de M-x. El caso es que he isntalado también witch-key para saber qué teclas apretar si no recuerdo el comando, pero a la hora de buscarlos como tampoco tiene fuzzy tengo que escribir el nombre del comando bien a la primera para encontrarlo.

    Respecto a tema importante, el LSP (Language server protocol). Por si no lo sabes, el LSP es una cosa maravillosa, permite que los lenguajes saquen información de forma estándar para poder tener autocompletado, vamos, que si me instalo el LSP de typescript por ejemplo, puedo tener el mismo autocompletado que en el vscode.

    Para vim uso el paquete de vim-coc que ya te lo da todo, lo instales y ale. Te da hasta maneras de instalar los language servers desde dentro de Vim.

    En emacs estoy usando lsp-mode que lo usa la mayoría de gente. Es cierto que te da una forma de instalar los language servers, pero además necesita instalar otros tantos paquetes para tener popup de autocompletado o de documentación.

    En concreto utilizo: company, lsp-ui y company-box. La cosa es que hace cosas raras. A veces me abre los ficheros sin tener el LSP activado y tengo que activarlo a mano. A veces no me autocompleta nada y otras sí.

    Otra cosa que me pasa es que no autocompleta cosas del fichero (a veces sí que lo hace, veo que pone file al lado, pero no autocompleta casi nada). Con vim-coc da igual en que fichero esté, o con qué LSP, que siempre autocompleta algo de los ficheros que tenga abiertos.

    Con el de Emacs muchas veces me quedo sin autocompletado porque me dice que no hay opciones, debe ser que el LSP no devuelva nada, miraré si hay más config para que funcione con el de vim (o buscar otros paquetes).

    También tengo problemas con Svelte, precisamente como el LSP no devuelve nada, en Svelte en la parte de Javascript casi no autocompleta nada, y eso hace que se vuelva muy tedioso andar escribiendo todo.

    Una cosa que me molestó mucho al principio es que Emacs al parecer guarda archivos autosave en el propio proyecto en el que estás, incluso me guardaba mensajes de log. Tuve que cambiar las carpetas de todas esas cosas por la carpeta temp del sistema.

    Conclusiones

    Como digo en el momento de escribir este artículo llevo cosa de unos días de uso, todavía tengo que habituarme, cambiar cosas de la config, aprender comandos y funciones, etc.

    Mirando vídeos de gente usando emacs le veo mucho potencial, es como la mezcla perfecta entre la simplicidad de Vim en cuanto a interfaz y la potencia de un editor gráfico como Vscode .

    Ahora bien, si por estar en ese punto medio va a tener las desventajas de Vim sumadas a las desventajas del Vscode pues para eso me vuelvo a Vim.

    El tiempo lo dirá.

    (Por cierto, acepto toda clase de recomendaciones, feedback, tips y tal, me puedes escrbir a mi Twitter @CodingPotions)

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

    Blog Bitix

    Novedades de Java 18

    marzo 31, 2022 07:00

    Las novedades de Java 18 no añaden nada en el lenguaje pero sí incorpora algunas relevantes en la plataforma como el uso de UTF-8 por defecto, una utilidad de línea de comandos para disponer de un servidor web simple, poder añadir fragmentos de código en los comentarios de la documentación Javadoc así como el marcado para su eliminación en futuras versiones de la finalización de objetos. También publican otras novedades en incubación, nuevas versiones en vistas previa de otras características se publicarán de forma definitiva en siguientes versiones y otros numerosos cambios menores.

    Java

    Las mejoras incrementales se siguen añadiendo en cada nueva versión lanzada cada seis meses. En marzo de 2022 ha sido publicada la versión de Java 18 como siguiente versión después de Java 17 que es una versión con soporte extendido o LTS. Seguramente no muchos van a poder utilizar esta nueva versión por restricciones en los proyectos que seguirán usando versiones ya consideradas bastante antiguas incluyendo Java 8 y más en los casos que utilizan versiones anteriores. Por otro lado, otra parte de usuarios quizá esperen a la siguiente versión LTS para actualizar las aplicaciones en el caso de que ya estén utilizando Java 17.

    La lista de características de Java 18 no es muy amplia pero hay algunas destacadas.

    Contenido del artículo

    Introducción

    Con el paso de los meses muchas librerías y entornos de desarrollo irán publicando nuevas versiones compatibles con Java 18 y añadiendo soporte. Cuatro de las características más destacada son la utilización de la codificación de caracteres UTF-8 por defecto, la inclusión de un pequeño servidor web, soporte para añadir fragmentos de código en la documentación Javadoc y finalmente marcar para ser eliminada en una siguiente versión la finalización de objetos. Otras mejoras son nuevas vistas previas de características que están disponibles para obtener comentarios pero que en una siguiente versión podrían cambiar.

    Las mejoras incluidas en esta versión son:

    En los siguientes vídeos hace una explicación de estas nuevas características.

    Con el nuevo calendario de publicaciones se observa claramente que los desarrolladores pueden predecir de forma más mucho fiable cuando se publicará una nueva versión. Se observa que el tiempo entre versiones se ha reducido considerablemente respecto a lo que tardaron las versiones Java 6 y 7 y se observa la incorporación de novedades de forma constante.

    Publicaciones de Java

    Publicaciones de Java

    Nuevas características

    Codificación de caracteres UTF-8 por defecto

    Las operaciones que hacían entrada y salida como en el caso del sistema de archivos se utilizaban por defecto si no se indicaba uno explícitamente la codificación del sistema operativo. Dado que cada sistema operativo es capaz de definir su codificación de caracteres esto creaba algunas inconsistencias cuando las aplicaciones se ejecutan en diferentes sistemas operativos. Ahora en caso de que no se indique una codificación de caracteres se utiliza UTF-8 ofreciendo una mejor consistencia entre las diferentes plataformas.

    Servidor web simple

    Se añade una utilidad de línea de comandos y una API para iniciar un sencillo servidor web para archivos estáticos. La finalidad es que no haya que recurrir a utilidades externas al JDK y sirva para hacer pruebas. No es su intención reemplazar servidores web más completos como Apache o Nginx ni ofrece funcionalidades dinámicas como un contenedor de servlets como Tomcat.

    Dado que es un servidor web simple tiene algunas limitaciones, como que solo soporta el protocolo HTTP/1.1, no soporta el protocolo seguro HTTPS, solo soporta operaciones idempotentes de los verbos HEAD y GET devolviendo el resto de versos un código de error 501 Not Implemented o 405 Not Allowed Response. Algunos MIME types son configurados de forma automática como los archivos con extensión html que son servidos con la cabecera de contenido text/html.

    1
    2
    
    $ jwebserver
    
    
    jwebserver.sh
    1
    2
    3
    
    Binding to loopback by default. For all interfaces use "-b 0.0.0.0" or "-b ::".
    Serving /home/picodotdev and subdirectories on 127.0.0.1 port 8000
    URL http://127.0.0.1:8000/
    
    jwebserver.out

    Además de la línea de comandos se ofrece una API para iniciar el servidor web mediante código.

    Fragmentos de código en comentarios Javadoc

    Algunos de los comentarios de Javadoc incluyen ejemplos de código. Hasta ahora los fragmentos de código insertaban con el taglet @code que tenía varias deficiencias como no ofrecer resaltado de sintaxis, no poder incluir fragmentos de código de archivos existentes con lo que puede quedar obsoleto y no poder hacer pruebas unitarias sobre este código con lo que podría no funcionar.

    Se añade el taglet @snippet que permite incluir fragmentos o snippets de código en los comentarios de Javadoc, con resaltado de sintaxis y soporte para acceder a los taglets para procesar el código de la anotación. La anotación permite incluir en los comentarios de Javadoc regiones de archivos externos y aplicar transformaciones en el contenido a incorporar en el Javadoc. Pudiendo añadir fragmentos de código de archivos externos y pudiendo realizar transformaciones no hace falta copiar código y pegar código en los comentarios Javadoc sino que los fragmentos de código se extraen directamente de los archivos de código fuente.

    Además se ofrece una API para acceder a esos fragmentos de código pudiendo hacer pruebas unitarias del código incluido en el Javadoc, esto no es solo para los desarrolladores del JDK sino también para cualquier programador que añada fragmentos de su código Java en la documentación Javadoc.

    Los fragmentos de código no están limitados a archivos de código Java sino que también es posible incluir otros formatos utilizados comúnmente en aplicaciones Java como archivos properties, html u otros. En esta guía se detalla como usar los fragmentos de código con ejemplos de código.

    Reimplementación de la reflexión con manejadores de métodos

    Se reimplementan varias funcionalidades relacionadas con la reflexión utilizando los manejadores de eventos con la intención de facilitar el mantenimiento del JDK. Los MethodHandlers ofrecen una alternativa a la reflexión con mejor rendimiento a la vez que es más legible. Es un cambio interno más para los desarrolladores del JDK que para los usuarios.

    Proveedor para resolver direcciones IP

    Hasta ahora el JDK utilizaba el mecanismo del sistema operativo para resolver direcciones IP. Este es compartido por todas las aplicaciones y la operación de resolución es bloqueante que es un problema para la incorporación de los threads ligeros del project Loom. Se ha añadido un mecanismo extensible para proporcionar otras formas de resolución y soportar nuevos protocolos como DNS sobre QUIC, TLS y HTTPS. Ahora las aplicaciones tiene más control sobre el mecanismo de resolución y es útil en el contexto de pruebas automatizadas.

    Nuevas características en vista previa

    Como ya es habitual en el JDK se van incluyendo algunas características en modo vista previa que pueden ser utilizadas pero que en una siguiente versión y el código que las usen deberá ser modificado. Se ofrecen para que los usuarios puedan experimentar con ellas y los desarrolladores obtengan comentarios y si es necesario hacer cambios en siguientes versiones.

    Vector API

    Se proporciona una nueva versión de la Vector API que permite aprovechar las instrucciones SIMD de los procesadores con una API de Java común para todas las arquitecturas de procesadores. Se aprovechan las características disponibles de los procesadores y en aquellos que no tengan alguna se ofrece un modo de funcionamiento degradado.

    En esta nueva versión se soportan las instrucciones Scalar Vector Extension (SVE) de la plataforma ARM. También se mejora el rendimiento de las operaciones que aceptan enmascaramiento en las arquitecturas hardware que soportan enmascaramiento.

    Foreign Function & Memory API

    Esta API permite acceder a memoria de procesos externos y utilizar librerías programadas en otros lenguajes como una alternativa más fácil de usar, de mayor rendimiento, más general para diferentes arquitecturas y más simple que la anterior alternativa con JNI. En esta nueva versión se mejora la API para soportar y facilitar operaciones con diferentes tipos y accesos a memoria.

    Pattern Matching para las sentencias switch

    El parttern matching en las sentencias switch permite al compilador comprobar de la expresión del switch contra los casos de la expresión del switch. En esta nueva revisión de esta característica el compilador lanza un error en caso de que un patrón domine al siguiente, sea más general siempre se cumpla antes que uno menos general. Ahora también el compilador es más preciso al comprobar la completitud de todos casos del switch en las clases sealed.

    Otros cambios

    Finalización de objetos marcado para ser eliminado

    Java es un lenguaje que ha ofrecido recolección de basura desde las primeras versiones. Los programadores nunca han tenido que liberar la memoria de los objetos de forma explícita sino que de esta tarea se encarga la máquina virtual de Java. Pero también Java desde las primeras versiones ha ofrecido un mecanismo para la finalización de objetos que el tiempo ha demostrado que tiene varios fallos de diseño que no lo hacen útil y se desaconseja su utilización.

    Algunos fallos de su diseño son que tiene una latencia impredecible y arbitraria sin garantía de que la finalización del objeto se realice. Las acciones de finalización no tienen ninguna restricción pudiendo revivir una referencia de objeto. Siempre está activo para cada instancia de una clase se use o no, ni se puede cancelar. Tampoco hay un orden predefinido en un entorno multihilo de modo que la ejecución de la finalización se puede ejecutar en cualquier orden.

    Por los defectos anteriores la eliminación de la finalización de objetos en Java ha sido algo pendiente de realizar, en esta versión de Java aunque no se elimina se marca para la eliminación en versiones futuras de Java de modo que los que lo usen tengan tiempo de actualizar sus librerías y aplicaciones.

    Esto solo impactará a algunos usuarios que realicen tareas avanzadas en las que necesiten la finalización de objetos, no es algo que en circunstancias normales se use. La alternativa a la finalización de objetos es usar la sentencia try-with-resources y en los objetos que tengan un ámbito mayor de vida utilizar la clase Cleaner que permite asociar acciones de finalización a una referencia de objeto cuando esta se convierte en una referencia phantom.

    Otros cambios

    Los anteriores son los cambios más destacados de Java 18 pero otro buen número de cambios menores e internos en el JDK. En las notas de publicación se incluye una lista detallada de todos.

    Estos son artículos que también hacen resúmenes de las novedades de Java 18.

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

    Coding Potions

    Cómo ignorar en git ficheros o carpetas tras añadirlos al .gitignore

    marzo 28, 2022 12:00

    Si en un proyecto Git quieres ignorar ficheros o carpetas que has añadido recientemente al gitignore, es posible que no funcione porque ya existen commits anteriores con esos ficheros.

    Para arreglar esto hay que quitar de la caché de git esos ficheros para que se puedan ignorar, para ello

    Primero haz commit de todos los cambios que tengas y luego ejecuta:

    git rm -rf --cached .
    git add .
    

    Esto lo que hará será quitarlos de la caché y añadirlo al stage, ahora solo tienes que hacer commit de esto para que funcione:

    git commit -m "Arreglando el gitignore"
    

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

    Header Files

    Flags fuertemente tipadas

    marzo 24, 2022 06:45

    Introducción

    En muchos sistemas es frecuente tener que saber si determinada característica, opción, componente, etc. está habilitado o no. Para ello se suelen usar flags (banderas), definidas como constantes o enumeraciones, y vectores de booleanos o std::bitset.

    enum CompilationFlags {
        CompilationFlags_CrossCompilation,
        CompilationFlags_Debug,
        CompilationFlags_Count
    };
    std::bitset<CompilationFlags_Count> compilation_flags;
    
    compilation_flags.set(CompilationFlags_Debug, true);
    

    El principal problema de estas soluciones es que se basan en convertir un identificador en un índice en el vector / bitset, lo que lleva a que no haya comprobación en tiempo de compilación de que la característica esté soportada. Por ejemplo, puede ocurrir un desbordamiento de buffer si el índice supera el tamaño máximo del contenedor, o un error de lógica si se consulta un flag no correspondiente a dicho conjunto (pero con el mismo valor numérico).

    Propuesta

    Una posible solución es definir las banderas como tipos booleanos fuertemente tipados y usarlos en una tupla. En este artículo extenderemos la sintaxis que propusimos en una entrega anterior (Argumentos expresivos 1):

    class Flag
    {
        bool m_value;
    
    public:
        Flag() = default;
        explicit Flag(bool value) noexcept : m_value{value} {}
    
        operator bool() const { return m_value; }
    };
    
    #define FLAG(name) struct name : Flag { using Flag::Flag; }
    
    FLAG(CrossCompilation);
    FLAG(Debug);
    
    using CompilationFlags = std::tuple<CrossCompilation, Debug>;
    

    Así, podemos aprovechar el método std::get basado en tipos para consultar el estado de la bandera:

    CompilationFlags comp_flags;
    
    std::get<CrossCompilation>(comp_flags) = CrossCompilation{true};       // to set a value
    auto const cross_compilation = std::get<CrossCompilation>(comp_flags); // to get a value
    

    Ahora bien, esta sintaxis puede ser mejorada en varios aspectos; veamos cuáles son.

    Estado inicial de la bandera

    Lo primero es que no todas las banderas estarán en un estado off al inicio, por lo que podemos modificar el tipo Flag para considerar este escenario y dotarlas de un estado inicial explícito:

    template<bool default_value>
    class Flag
    {
        bool m_value{default_value};
    
    public:
        Flag() = default;
        explicit Flag(bool value) noexcept : m_value{value} {}
    
        operator bool() const { return m_value; }
    };
    
    #define FLAG(name, value) struct name : Flag<value> { using Flag::Flag; }
    
    FLAG(CrossCompilation, false);
    FLAG(Debug, true);
    

    Encapsulamiento

    Lo siguiente es dotar de una mejor interfaz a nuestra solución. Para ello definiremos una clase Flags que se hará cargo de dichas funciones. Veremos esta solución en conjunto con la siguiente mejora.

    Inicialización selectiva

    Aunque las banderas tengan un estado inicial, éste puede que no sea apropiado en algunos casos. Una solución podría ser tener un constructor que reciba todas las banderas, pero claramente no es la opción más limpia, especialmente si el conjunto es grande. En su lugar aprovecharemos el tipado fuerte de las banderas para poder definir un constructor más flexible.

    template<typename... Types>
    class Flags
    {
    public:
        Flags() = default;
    
        template<typename Flag, typename... Args>
        explicit Flags(Flag flag, Args&&... args) : Flags{args...}
        {
            std::get<Flag>(m_flags) = flag;
        }
    
        template<typename T>
        bool is_enabled() const noexcept
        {
            return std::get<T>(m_flags);
        }
    
        template<typename T>
        void set_enabled(T const& state) noexcept
        {
            std::get<T>(m_flags) = state;
        }
    
    private:
        std::tuple<Types...> m_flags;
    };
    

    Ejemplo de uso

    using CompilationFlags = Flags<CrossCompilation, Debug>;
    
    CompilationFlags const compilation_flags{Debug{false}};
    
    auto const is_debug = compilation_flags.is_enabled<Debug>();
    

    El ejemplo completo puede conseguirse acá.

    Conclusión

    Como se ha podido ver, el uso de tipos fuertemente tipados aumenta la expresividad del código, permiten soluciones máx flexibles y robustaz, y da una mayor cercanía entre la sintaxis y la semántica.

    Por otro lado, permiten sacar partido a una de mis características favoritas de C++: el compilador. Si algo se puede hacer en tiempo de compilación, ¿por qué hacerlo en tiempo de ejecución? Si un fallo se puede detectar cuando sólo nosotros (los desarrolladores) somos los afectados, ¿por qué dejar que el cliente sea el que lo descubra? De todo esto hablaremos en una entrega futura, mientras tanto, y como diría Sheldon Cooper: ¡diversión con banderas!

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

    Una sinfonía en C#

    Parámetros, entrypoints y comandos en Kubernetes, ¿cómo funcionan?

    marzo 05, 2022 12:00

    Si estamos desplegando en Kubernetes en probable que si algo sale mal y necesitamos hacer troubleshooting, entre las herramientas más útiles (quitando los logs) poder ejecutar un comando o “entrar” en un container puede ser muy útil. El problema es si nuestro ejecutable es el que hace que el Pod se reinicie y no podemos obtener acceso al bash del Pod, una forma de solucionar eso es sobre-escribir el comando por defecto, vamos a hablar de eso.

    Docker exec, Kubectl exec

    La forma de ejecutar un comando (y obtener acceso a la línea de comandos) contra un container esté o no en Kubernetes es utilizando exec (varia un poco la sintáxis entre ambos pero es igual) algo así:

    docker exec -it mycontainer bash
    

    o en Kubernetes

    kubectl exec -it mypod -- bash
    

    Y con esto obtener acceso a la línea de comandos ya que ejecutamos bash y solicitamos modo interactivo con -it

    Nuestro Pod no para de reiniciarse

    El problema es que muchas veces nuestra aplicación no terminar de iniciar y genera que el Pod se reinicie todo el tiempo, entonces no podemos acceder a la línea de comando, entonces lo que podemos hacer el sobre-escribir el comando que ejecuta nuestra app y así obtener acceso a la línea de comando y ejecutarla desde ahí y hacer las pruebas correspondientes

    Entrypoint, CMD, args, Commands.

    Acá comienza la confusión

    Si creamos una imagen de algo que no tiene un comando

    FROM alpine
    
    docker build -t test .
    

    Y creamos un contenedor

    docker run -d test
    

    el mismo se ejecuta y finaliza inmeditamente porque la idea es que sea un proceso continuo, por eso necesitamos un comando

    FROM alpine
    CMD ["tail", "-f", "/dev/null"]
    

    o un Entrypoint

    FROM alpine
    ENTRYPOINT ["tail", "-f", "/dev/null"]
    

    ¿Pero cuál es la diferencia entre ambos?

    En principio ninguna en este caso, pero si lo que queremos es dar la posiblidad de que nuestro comando reciba parámetros (es decir algo detrás del nombre del ejecutable o script, en este caso “f” “/dev/null”) ahí sí que hay diferencia:

    Cómo funciona el pasaje de parámetros en Docker?

    Al final todo se resume a cómo funciona en Docker ya que Kubernetes se basa en ese comportamiento. Para no ser largo con ejemplos:

    Lo que se defina con CMD se sobre-escribe por completo con parámetros en la línea de comandos, entonces esto

    FROM alpine
    CMD ["echo", "hola"]
    

    Si lo ejecuto imprimer “hola” y finaliza. Pero es completamente sobre-escrito si hago esto:

    docker run test echo chau
    

    Estos parámetros reemplaza a todo lo que esté definido con CMD en el Dockerfile

    Si hago esto dará error

    docker run test hola
    

    porque sobre-escribe todo, y el comando que intenta ejecutar es “chau” que no es válido. Entonces CMD me permite sobre-escribir todo pero no me da la posibilidad de cambiar parte de lo que es el comando original.

    ¿Qué pasa si quiere pasar parámetros pero que se agregar a mi ejecutable o script?

    Para esto existe Entrypoint, si pasamos parámetros en la línea de comandos se toman como argumentos del Entrypoint, es como si se agregasen, por ejemplo esto:

    FROM alpine
    ENTRYPOINT ["echo"]
    
    docker run test hola
    

    En el ejemplo anterior daría error porque no existe un comando “hola” pero este caso imprime “hola” porque se pasa como argumento a echo

    Genial, pero qué pasa si queremos tener un argumento por defecto que se pueda sobre-escribir, bien, combinamos ambos.

    FROM alpine
    ENTRYPOINT ["echo"]
    CMD ["hola"]
    

    Viéndolo así es simple, pero también podemos sobre-escribir el entrypoint en caso que querramos hacerlo

    docker run --entrypoint ls test
    

    Y sobre-escribimos el entrypoint y el cmd, de este modo tenemos todas opciones para poder evitar que el comando por defecto del Dockerfile se ejecute para lograr tener un contenedor estable que nos permita trabajar.

    Kubernetes

    Y cómo se hace todo esto en Kubernetes, con dos opciones, pero lo confuso es el nombre

    • args: es equivalente a CMD en Docker
    • COMMAND: es equivalente a ENTRYPOINT en Docker

    entonces, para el ejemplo anterior en un Pod quedaría así:

     apiVersion: v1
    kind: Pod
    metadata:
      creationTimestamp: null
      labels:
        run: test
      name: test
    spec:
      containers:
      - image: test
        command: ["echo"]
        args: ["hola desde pod"]
        name: test
        resources: {}
      dnsPolicy: ClusterFirst
      restartPolicy: Always
    status: {}
    

    Y listo, un ejemplo de cómo tener un Pod que se quede esperando para poder ingresar en él sería:

     apiVersion: v1
    kind: Pod
    metadata:
      creationTimestamp: null
      labels:
        run: test
      name: test
    spec:
      containers:
      - image: test
        command: ["tail", "-f", "/dev/null"]
        name: test
        resources: {}
      dnsPolicy: ClusterFirst
      restartPolicy: Always
    status: {}
    

    y ya podemos ingresar a su línea de comandos

     kubectl exec -it test -- sh
    

    Nos leemos.

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

    Coding Potions

    Cómo crear tu primer código en Javascript. Hello world!

    marzo 05, 2022 12:00

    En este artículo voy a tratar de explicarte cómo hacer tu primer código con Javascript.

    Te recomiendo que te pases por el artículo de Entorno de desarrollo para frontend para que tengas las herramientas listas para empezar.

    Hello world usando editor online (codepen)

    La manera más rápida y sencilla de hacer un hola mundo es usar una web en la que puedes programar sin instalar nada.

    Una de las que recomiendo es Codepen, simplemente le das a Start coding y ya te abre una pantalla tal que así:

    En la imagen se ve la página de codepen abierta y 3 secciones para escribir código

    Como ves se te abre un editor muy simple, con el que puedes escribir HTML , CSS Y Javascript (JS) que es lo que nos interesa para este artículo. Si no sabes lo que son estos lenguajes pásate por el post de Frontend.

    Por cierto, en codepen puedes crearte una cuenta para ir guardando los proyectillos que vayas creando.

    Vale, pues para escribir el hola mundo tan solo tienes que escribir lo siguiente en la caja de JS:

    console.log("Hello world!");
    

    Si ahora le das al botón de abajo a la izquierda que pone “Console”, podrás ver que en la pantalla pone Hello world!.

    En eso consiste hacer un hello world, en crear un programita o web que simplemente pinte hello world en la pantalla, así de fácil.

    Hello world con ficheros

    ¿Pero es así de fácil crear un hello world? Pues la realidad es que estás páginas precisamente lo que hacen es facilitarnos la vida para no tener que montar un entorno para desarrollar páginas web.

    Si quieres crear un hello world usando ficheros en tu ordenador lo primero que te recomiendo es que tengas un editor de textos de código, puedes usar el que quieras, aunque para empezar te recomiendo que uses el Vscode que además es gratis.

    Una vez descargado tienes que crear una carpeta en tu ordenador y abrirla con el editor de código. Dentro de esta carpeta crea un fichero llamado index.html

    En realidad lo puedes llamar como quieras, pero al fichero principal de una web se le suele llamar index por convención.

    El contenido del fichero index.html es el siguiente:

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Hello world</title>
      </head>
    
      <body>
        <script>
          console.log("Hello world!")
        </script>
      </body>
    
    </html>
    

    No me voy a parar mucho en explicar HTML, simplemente tienes que saber que con la etiqueta HTML de script lo que se puede hacer es ejecutar código Javascript, en este caso pues el console.log que lo que hace es escribirlo en la consola del navegador.

    Si ahora abres este fichero en el navegador (botón derecho y abrir con firefox o chrome o el que uses) verás que no aparece nada, es normal.

    El código que hemos escrito se ejecuta y se imprime en la consola del navegador, y no en la propia página web.

    Para abrir la consola del navegador dale a botón derecho en la página y selecciona la opción de inspeccionar elemento o inspect, también puedes usar la combinación de teclas de Control + Shift + I (en MAC ni idea, supongo que Comando + Shift + I).

    Se te ha debido de abrir una ventana, bienvenido a las Developers tools del navegador (o herramientas para desarrolladores). Si quieres ser desarrollador web te recomiendo que te habitúes a usar esta herramienta porque la vas a usar mucho.

    Con esta herramienta puedes ver el código fuente de una página web, puedes ver lo que se está ejecutando, hacer análisis de la ejecución, ver las llamadas que se hacen a servidor, etc.

    Para nuestro caso nos interesa la pestaña de la consola (console). En esta pestaña puedes ver algunos errores y también el código que se ejecuta en los console.log.

    Si has seguido bien los pasos deberías poder ver el Hello world.

    Código Javascript en fichero independiente

    Esto está muy bien, pero la realidad es que escribir código Javascript dentro de los ficheros .html se considera mala práctica, lo mejor es no mezclar lenguajes y separar las cosas en distintos ficheros.

    Para el Hello World lo que puedes hacer es crear en la carpeta un fichero llamado index.js (o como quieras llamarlo pero que tenga extensión .js).

    Dentro del fichero index.html tienes que modificar la etiqueta de script para que llame al fichero en lugar de ejecutar el código Javascript directamente.

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Hello world</title>
      </head>
    
      <body>
        <script src="index.js"></script>
      </body>
    
    </html>
    

    Y dentro del fichero .js tan solo tienes que escribir:

    console.log("Hello world!");
    

    Y listo, si ahora guardas ambos ficheros y vuelves a abrir las developers tools en el navegador podrás ver que el resultado es el mismo.

    Prueba ahora a cambiar el texto entre las comillas dobles y a guardar el fichero. Si vuelves al navegador verás que no ha ocurrido nada, eso es porque tienes que recargar la página para que el navegador refresque los cambios, simplement4e pulsa F5 en la página o dale al botón de recargar web.

    Y poco más la verdad. Si eres un programador o programadora que está empezando te recomiendo que tengas paciencia, es normal al principio sentirse abrumado por la cantidad de información que hay y que tienes que aprender, con práctica al final todo sale, buena suerte!

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

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

    Sourceforge premia de nuevo a FileOptimizer

    marzo 04, 2022 07:09


    Siguen llegando reconocimientos y galardones a mi FileOptimizer. El último fue el Building Good with C++ Builder Contest 2021, un galardón que además tenía una contrapartida económica. Ahora le toca a Sourceforge, quienes en el pasado lo premiaron en varias ocasiones como Project of the Week y que expliqué en el recopilatorio sobre Galardones FileOptimizer. …

    Sourceforge premia de nuevo a FileOptimizer Leer más »



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

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

    Coding Potions

    Comandos de Vim para movimientos entre líneas del fichero

    marzo 02, 2022 12:00

    En el artículo de Comandos de Vim para movimientos horizontales ya vimos algunos comandos del Modo normal de Vim para movernos dentro de las propias líneas y ahora toca justo lo contrario, movernos entre todas las líneas.

    Lo primero, lo que ya vimos en Movimientos básicos en Vim, puedes usar h j k l para moverte, en concreto j k para moverte arriba o abajo una línea.

    También puedes combinar j k con números para desplazarte más líenas, por ejemplo: 20 k para moverte 20 líneas hacia arriba.

    Aquí te recomiendo que te pongas :set relativenumber dentro de tu fichero .vimrc, más info en Configuración básica de Vim.

    Ir al principio y al final del fichero

    Para ir al principio del documento existe el comando gg (regla memotécnica good game jejeje).

    Mientras que para ir al final del fichero existe la tecla G, ojo porque es mayúscula, tienes que pulsar SHIFT.

    Por ejemplo, si quieres borrar todo el documento puedes hacer: g g 0 d G (ve al principio del fichero, ponte al principio de la líena y borra hasta el final del fichero).

    Ir a una línea en concreto

    Para ir a una línea en concreto del fichero tienes dos variantes que se comportan igual, elige la que más te guste (o mejor recuerdes):

    • 20 G: Ir a la líena 20 del fichero
    • :24 + Enter: Ir a la líena 24 del fichero

    Moverte entre líneas vacías

    Este par de comandos viene bien para moverte por el fichero sin tener que usar tantas veces jjjjjj y kkkkkk.

    Con `{ te mueves hacia atrás y cada vez que lo pulses el cursor se pondrá en una líena vacía del fichero.

    Con } es lo mismo solo que te mueves hacia adelante en las líneas vacías.

    Como muchas veces al programar separamos el fichero por funciones, pues normalmente vas a tener una línea vacía siempre al comienzo de cada función, por eso este par de comandos puede ser bastante útil.

    Mover el cursor en la pantalla

    Otra cosa que puedes hacer es mover el cursor al principio, al final o al medio de la pantalla, en concreto se hace con las teclas mayúsculas de H M L.

    • Shift + H: Mueve el cursor al principio de la pantalla
    • Shift + M: Mueve el cursor a la mitad
    • Shift + L: Mueve el cursor al final de la pantalla

    Scroll por el fichero sin mover el cursor

    Para esto Vim tiene unos cuantos comandos:

    • Control + y: Mueve la pantalla una línea hacia arriba
    • Control + e Mueve la pantalla una línea hacia abajo
    • Control + u: Mueve la pantalla hacia arriba ½ página
    • Control + d: Mueve la pantalla hacia abajo ½ página
    • Control + b: Mueve la pantalla hacia una página entera hacia arriba
    • Control + f: Mueve la pantalla hacia una página entera hacia abajo

    Por cierto, pulsando dos veces zeta zz puedes centrar el cursor en mitad de la pantalla sin moverlo de la línea que estaba.

    Con el plugin de vim-sneak

    https://github.com/justinmk/vim-sneak

    Este plugin lo uso mucho a lo largo del día y lo recomiendo mucho. La idea es muy simple, una vez instalado, le das a la tecla s y escribes dos letras, a continuación en la pantalla te saldrán marcadas las coincidencias de esas dos letras en las palabras que hay en la pantalla.

    Lo que mola es que para ir a una coincidencia solo tienes que pulsar la letra que te sale en la pantalla, por lo que puedes navegar a cualquier parte de la pantalla usando solo 3 letras.

    Vamos, que es como el comando f y t que vimos en Comandos de Vim para movimientos horizontales pero más chetado porque puedes escribir dos caracteres. De hecho, este plugin también puede sustituir a f y t para que funcionen también con dos caracteres.

    Echa un ojo a Plugins interesantes para Vim si quieres descubrir más plugins que recomiendo usar.

    https://camo.githubusercontent.com/9f1def2dd226c47f4cce9fb1b12bdb20db1f062d037ee9bcb1343aa8447552c2/68747470733a2f2f7261772e6769746875622e636f6d2f6a757374696e6d6b2f76696d2d736e65616b2f666c7566662f6173736574732f726561646d655f6469616772616d2e706e67

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

    Una sinfonía en C#

    Acceder a un repository de imágenes con autenticación desde Kubernetes

    marzo 01, 2022 12:00

    Los Pods en Kubernetes utilizan imágenes, y lo más probable es que estas imágenes estén en un registro fuera del cluster, y lo segundo más probable es que necesite autenticación. Entonces nos encontramos con la pregunta “Cómo hago para que un Pod o Deployment en Kubernetes se autentique para descargar una imagen desde un repositorio que no es público?”. Bien, es post es acerca de cómo resolver este caso en Azure Container Registry, pero podría ser cualquier otro repository.

    Secrets al rescate

    La respuesta es bastante sencilla, necesitamos crear un secret, pero de un tipo especial en este caso kubernetes.io/dockerconfigjson sin embargo como casi siempre con los secrets lo más adecuado es crearlos en el momento de utilizarlos y no dejar el YAML en en repository de código porque pierden un poco el sentido, el comando para crearlo sería así:

    kubectl create secret docker-registry mysecreto --docker-username=username --docker-password=password --docker-server=urldemiregistro
    

    Y el resultado es el siguiente (notemos que ya el password está encriptado)

    apiVersion: v1
    type: kubernetes.io/dockerconfigjson
    data:
      .dockerconfigjson: eyJhdXRocyI6eyJ1cmxkZW1pcmVnaXN0cm8iOnsidXNlcm5hbWUiOiJ1c2VybmFtZSIsInBhc3N3b3JkIjoicGFzc3dvcmQiLCJhdXRoIjoiZFhObGNtNWhiV1U2Y0dGemMzZHZjbVE9In19fQ==
    kind: Secret
    metadata:
      creationTimestamp: null
      name: mysecreto
    

    ¿Cómo usamos el secret para acceder en nuestro pod / deployment?

    Bien, esto es relativamente sencillo, solo debemos agregar una opción a nivel de containers (que es imagepullsecrets, porque podrían ser varios)

    apiVersion: v1
    kind: Pod
    metadata:
      labels:
        run: busybox
      name: busybox
    spec:
      imagePullSecrets: # indicamos que si se necesita autenticación se utilice el user y password del secret
      - name: mysecreto
      containers:
      - image: busybox
        args: ["tail", "-f", "/dev/null"]
        name: busybox
        resources: {}
      dnsPolicy: ClusterFirst
      restartPolicy: Always
    status: {}
    

    Dejo los ejemplos por acá

    Y listo, nos leemos en la próxima.

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

    Coding Potions

    Listado de plugins interesantes para Vim y Neovim

    febrero 28, 2022 12:00

    En este artículo voy a tratar de hacer una lista de algunos plugins de Vim que a mi me encantan y que recomiendo mucho su uso.

    Antes de empezar hay que aclarar que algunos plugins funcionan para vim y neovim, pero algunos solo funcionan para neovim.

    Te recomiendo que te pases por el artículo de Cómo instalar plugins en vim y por el de Temas de color recomendados para Vim para que termines de completar tu Vim.

    Ya que en el artículo de Configuración básica de Vim no puse nada de config de plugins, voy a tratar de poner aquí la config que uso de cada uno.

    Lualine

    https://github.com/nvim-lualine/lualine.nvim

    Lualine es un plugin que añade una barra de estado en Vim, para saber en qué modo estás, para ver el número de líneas del fichero, la rama de git, etc.

    Hace años la gente usaba mucho lightline y el mítico airline, pero los he cambiado por este que es más ligero.

    Mi config es la siguiente:

    require("lualine").setup {
    
    options = {
     theme = "tokyonight",
    },
    
    sections = {
      lualine_a = { "mode" },
      lualine_b = { "filename" },
      lualine_c = { "g:coc_status" },
      lualine_x = { "branch" },
      lualine_y = { "encoding" },
      lualine_z = { "location" }
    }
    
    

    nvim-telescope

    https://github.com/nvim-telescope/telescope.nvim

    Mi plugin preferido para neovim. Se trata de un popup que se abre en medio de la pantalla y que contiene un buscador. Dependiendo del comando que ejecutes para abrir el popup puedes buscar una cosa o otra.

    Yo por ejemplo tengo un comando para abrir buscador de ficheros y otro para hacer una búsqueda de un texto de forma global en todos los ficheros del proyecto.

    Funciona incluso mejor que el Control + P de vscode porque tiene una pequeña previsualizaciñón del fichero antes de abrirlo.

    Mi config de telescope es la siguiente:

    telescope.setup {
       defaults = {
          vimgrep_arguments = {
             "rg",
             "--color=never",
             "--no-heading",
             "--with-filename",
             "--line-number",
             "--column",
             "--smart-case",
          },
          prompt_prefix = "   ",
          selection_caret = "  ",
          entry_prefix = "  ",
          initial_mode = "insert",
          selection_strategy = "reset",
          sorting_strategy = "ascending",
          layout_strategy = "horizontal",
          layout_config = {
             horizontal = {
                prompt_position = "top",
                preview_width = 0.55,
                results_width = 0.8,
             },
             vertical = {
                mirror = false,
             },
             width = 0.87,
             height = 0.80,
             preview_cutoff = 120,
          },
          file_sorter = require("telescope.sorters").get_fuzzy_file,
          file_ignore_patterns = {},
          generic_sorter = require("telescope.sorters").get_generic_fuzzy_sorter,
          path_display = { "absolute" },
          winblend = 0,
          border = {},
          borderchars = { "─", "│", "─", "│", "╭", "╮", "╯", "╰" },
          color_devicons = true,
          use_less = true,
          set_env = { ["COLORTERM"] = "truecolor" }, -- default = nil,
          file_previewer = require("telescope.previewers").vim_buffer_cat.new,
          grep_previewer = require("telescope.previewers").vim_buffer_vimgrep.new,
          qflist_previewer = require("telescope.previewers").vim_buffer_qflist.new,
          -- Developer configurations: Not meant for general override
          buffer_previewer_maker = require("telescope.previewers").buffer_previewer_maker,
       },
       extensions = {
          fzf = {
             fuzzy = true, -- false will only do exact matching
             override_generic_sorter = false, -- override the generic sorter
             override_file_sorter = true, -- override the file sorter
             case_mode = "smart_case", -- or "ignore_case" or "respect_case"
             -- the default case_mode is "smart_case"
          },
          media_files = {
             filetypes = { "png", "webp", "jpg", "jpeg" },
             find_cmd = "rg", -- find command (defaults to `fd`)
          },
       },
    }
    

    Y mis keybindings para abrir los popups son los siguientes:

    nmap <C-P> :Telescope git_files hidden=true <CR>
    nmap <C-T> :Telescope live_grep <CR>
    

    Es decir, con Control P (como en el vscode) abro el popup y puedo escribir el nombre del fichero a buscar en el proyecto. Con ControlT lo que se abre es un buscador para buscar cualquier texto en los ficheros del proyecto.

    Bufftabline

    https://github.com/ap/vim-buftabline

    Esta extensión la llevo usando varios años, se trata de una barra que se añade arriba para tener una lista de los buffers abiertos como si fueran pestañas en un editor de textos moderno.

    Hay muchas alternativas a este plugin pero al final siempre vuelvo a este por su sencillez y que funciona perfecto.

    Config para este plugin creo que no tengo, debo de estar usando la que viene por defecto.

    nvim-treeshitter

    https://github.com/nvim-treesitter/nvim-treesitter

    Plugin para neovim que lo que hace es parsear el código que estás desarrollando para mejorar el coloreado de la sintaxis y el identado. Este plugin muchas veces es necesario para otros.

    En la captura puedes ver cómo el código de la derecha tiene más colores debido al parseo que hace treeshitter del código.

    Mi config es esta:

    ts_config.setup {
       ensure_installed = {
          "lua",
          "javascript",
          "typescript",
          "html",
          "css",
          "vue",
          "svelte"
       },
       highlight = {
          enable = true,
          use_languagetree = true,
       },
    }
    

    vim-coc

    https://github.com/neoclide/coc.nvim

    Este plugin es el que uso para el autocompletado y la instalación de lenguage servers (un lenguage server es un sistema independiente del editor de textos que permite añadir autocompletado y funciones del lenguaje a cualquier editor).

    Es cierto que en neovim ya se puede instalar de forma nativa los language servers (LSP), pero a mi me gusta más usar coc porque funciona también para vim y además es plug & play.

    Tras instalar la extensión te tienes que acordar de instalar también los language servers, para ello tienes que ejecutar un comando dentro de vim tal que así:

    :CocInstall coc-tsserver
    

    La lista de language servers la puedes encontrar aquí

    Mi config es esta:

    set updatetime=100
    set pumheight=20
    
    inoremap <silent><expr> <TAB>
          \ pumvisible() ? coc#_select_confirm() :
          \ coc#expandableOrJumpable() ?
          \ "\<C-r>=coc#rpc#request('doKeymap', ['snippets-expand-jump',''])\<CR>" :
          \ <SID>check_back_space() ? "\<TAB>" :
          \ coc#refresh()
    
        function! s:check_back_space() abort
          let col = col('.') - 1
          return !col || getline('.')[col - 1]  =~# '\s'
        endfunction
    
        let g:coc_snippet_next = '<tab>'
    

    Esto lo que hace es hacer que el plugin se comporte más o menos como el autocompletado del vscode, es decir, según escribes te sale un popup con las opciones, y con la tecla Tab seleccionas la opción que quieres añadir

    También tengo estos keybindings para poder navegar mejor por el código:

    nmap <leader>gd <Plug>(coc-definition)
    nmap <leader>gr <Plug>(coc-references)
    nmap <leader>gi <Plug>(coc-implementation)
    

    Es decir, con , g d voy a la definición de la función o de la clase, con , g r voy a todas los sitios en los que use usa la función sobre la que estoy y con , g i a su implementación (lo de la coma es porque tengo definida la tecla coma como tecla leader).

    Aparte de esta config, vim-coc también tiene otra que se guarda en un fichero aparte llamado coc-settings.json, que en mi caso es este:

    {
      "coc.preferences.hoverTarget": "preview",
      "signature.enable": false,
      "suggest.echodocSupport": true,
      "suggest.enablePreview": false,
      "suggest.floatEnable": false,
      "suggest.triggerCompletionWait": 200,
      "suggest.maxCompleteItemCount": 16,
      "typescript.preferences.quoteStyle": "double",
      "javascript.preferences.quoteStyle": "double",
      "typescript.suggest.completeFunctionCalls": false,
      "javascript.suggest.completeFunctionCalls": false,
      "coc.preferences.formatOnSaveFiletypes": ["css", "svelte", "vue", "javascript", "typescript"]
    }
    

    Tengo desactivado el cuadradito que sale con documentación de la función a autocompletar porque me he dado cuenta de que me ralentiza bastante.

    nvim-comment

    https://github.com/terrortylor/nvim-comment

    Esta extensión básicamente lo que hace es comentar líneas que tengas seleccionadas, en muchos lenguajes de programación.

    Mis keybindings son los siguientes:

    nmap <Leader>t :CommentToggle<cr>
    vmap <Leader>t :CommentToggle<cr>
    

    Lo que hago simplemente es seleccionar el código que quiera comentar y le doy a , t, y lo mismo para descomentar.

    NERDTree

    https://github.com/preservim/nerdtree

    NerdTree también lleva mucho tiempo en mi config. Se trata de un árbol de carpetas y ficheros que se abre a un lado del editor, como en el vscode.

    Lo que me mola es que es muy simple, abres el editor y con el enter entras en el fichero que te interesa.

    Otra cosa que mola es que desde el propio árbol puedes crear ficheros, moverlos y borrarlos, todo a golpe de teclado.

    Mi config es muy simple:

    :let g:NERDTreeWinSize=40
    

    Y el keybinding que tengo para abrirlo es el siguiente:

    nmap <Leader>nt :NERDTreeToggle<cr>
    

    Aunque tengo también otro para que se abra directamente en el fichero en el que estoy:

    map <Leader>nf :NERDTreeFind<CR>
    

    Por cierto, dentro del árbol, con la tecla m activas la opción de crear borrar y modificar ficheros o directorios.

    vim-sneak

    https://github.com/justinmk/vim-sneak

    Este plugin sirve para moverte más rápido por la pantalla. El funcionamiento es muy simple, le das a la tecla s y escribes dos caracteres a los que te quieras mover, luego en la pantalla te salen letras y puedes escribir una de ellas para saltar rápidamente a esa posición.

    Mi config es la siguiente:

    let g:sneak#label = 1
    map f <Plug>Sneak_f
    map F <Plug>Sneak_F
    

    vim-gitgutter

    https://github.com/airblade/vim-gitgutter

    Este plugin lo que hace es añadir los típicos iconos de otros editores de los cambios de git de los ficheros (los de + para las líneas añadidas y el - para las eliminadas).

    Para este no tengo config porque hace tiempo que no lo uso.

    Otros plugins que tengo pendiente probar

    Nvim DAP

    https://github.com/mfussenegger/nvim-dap

    Este plugin para neovim al parecer permite hacer debugging de unos cuantos lenguajes de programación desde dentro del propio editor de vim.

    Para estas cosas ya existían otros plugins en vim, pero este me ha resultado interesante porque tiene también otro plugin asociado llamado nvim-dap-ui que mejora bastante la interfaz.

    Lens.vim

    https://github.com/camspiers/lens.vim

    Al parecer este plugin lo que hace es redimensionar automáticamente los splits dependiendo de cuál tengas el focus, para así poder ver todo el contenido sin que se corte.

    Pone que lo hace de forma inteligente para que se adapte al contenido del split, de tal forma que si ocupa poco el split no sea demasiado grande y viceversa.

    nvim-spectre

    https://github.com/nvim-pack/nvim-spectre

    Plugin que permite reemplazar de forma global en varios ficheros a la vez. Mola porque soporta regex y además puedes especificar glob de ficheros para que se modifiquen solo ciertos tipos de fichero de una ruta.

    Sinceramente, hasta ahora usaba la funcionalidad de vscode de buscar y reemplazar porque no encontraba manera de poder hacer esto de forma simple en Vim. Tengo ganas de probarlo a ver si me convence.

    sniprun

    https://github.com/michaelb/sniprun

    Sniprun es una herramienta que permite ejecutar una o varias líenas de código sin salir de Vim. Soporta varios lenguajes y lo que mola es que puedes configurar dónde quieres que te salgal el resultado, si en un popup, al lado de las líneas, etc.

    Otros plugins recomendados por la gente

    Ya que estoy, voy a publicar también algunos plugins que recomienda la gente y que yo no he probado.

    Harpoon

    https://github.com/ThePrimeagen/harpoon

    Harpoon permite añadir marcas en cualquier parte del código de tal forma que puedes navegar posteriormente entre las marcas sin tener que andar con buffers o buscando los ficheros que has abierto.

    Ale

    Ale lo que permite es que puedas pasar el linter del código cuando modificas ficheros, lo bueno es que te pinta los errores que saque en el propio código para que puedas moficiarlo.

    También permite configurar el fixer para que automáticamente corrija el código si puede hacerlo.

    Vim goyo

    https://github.com/junegunn/goyo.vim

    Goyo es un plugin mítico que lo que hace es quitar elementos de pantalla para que puedas escribir en Vim sin distracciones.

    project.nvim

    https://github.com/ahmedkhalf/project.nvim

    Plugin que premite administrar proyectos, es decir, permite poder cambiar entre proyectos y buscar entre ellos.

    Conclusiones

    Y esto es un poco la lista de plugins que tengo instalados y recomiendo. Si usas alguno y cosideras que es muy interesante mándame un mensaje en Twitter para chekearlo y añadirlo a esta lista.

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

    Coding Potions

    Cómo configurar Vim y su configuración recomendada

    febrero 23, 2022 12:00

    Dónde esta el fichero de config de vim

    Lo primero que tienes que saber es que Vim no tiene algo como vscode para configurar el editor de forma cómoda. Vim usa su propio fichero de config que tienes que modificar a mano.

    Para el caso de Vim este fichero se encuentra dentro de tu carpeta personal y se tiene que llamar .vimrc.

    Para el caso de Línux sería tal que así:

    ~/.vimrc
    

    Mientras que el de Neovim estaría en:

    ~/.config/nvim/init.vim
    

    Para el caso de Windows estaría en:

    `C:/Users/<TU USUARIO>/_vimrc`
    

    En Mac debería estar aquí, aunque no lo tengo claro porque no uso Mac:

    /usr/share/vim/vimrc
    

    Si no tienes este fichero creado lo tienes que crear de forma manual.

    La configuración que uso en mi día a día

    Para no andar explicando cada config que tiene Vim porque es mucha, voy a explicar directamente la config que tengo en mi Vim y luego ya modificas tú lo que necesites.

    Tengo que aclarar que yo tengo dos configs, una para vim asecas y otra para neovim. Esto es así porque al principio usaba vim y luego me pasé a neovim.

    La config para neovim es la misma que para vim asecas, solo que tienes que poner alguna línea menos.

    Por cierto, si ves en la config dobles comillas “ significa que es un comentario, en este artículo voy a poner comentarios con el nombre del fichero de config que uso para diferenciar entre vim y neovim

    IMPORTANTE: Voy a dejar de lado los plugins, ya que para eso existe el artículo de Plugins interesantes para Vim. Entre los plugins se encuentra uno para poder tener autocompletado en Vim como el del vscode, por si has entrado en este artículo buscando eso.

    También te recomiendo que eches un ojo al artículo de Configuración de Vim para frontend y al de Temas de color recomendados para Vim .

    Config general

    Lo primero que tengo en mi .vimrc (vim asecas) es lo siguiente:

    " .vimrc
    set nocompatible
    

    Esto lo que hace es anular la compatibilidad con Vi, el editor antiguo del que se basa Vim. En neovim no necesitas poner esta línea en la config.

    También tengo justo debajo esta línea:

    " .vimrc
    set history=1000
    

    Esta opción lo que hace es aumentar la cantidad de comandos y de cosas que guarda Vim para que luego puedas volver atrás, por defecto es de 20. En neovim esta línea no la tengo en la config porque no es necesaria.

    Luego tengo esta línea que lo que hace es que la terminal dibuje mejor el color de fondo, ya que con ciertos temas de color el fondo de la terminal solo se dibuja en la línea con texto. Más info en este issue

    " .vimrc
    let &t_ut=''  " To render properly background of the color scheme
    

    Una vez más, esta líena no la tengo en el fichero de neovim, pero si en el de vim asecas.

    Config de ficheros

    Una cosa muy recomendable es desactivar los ficheros swap que crea Vim ya que son muy molestos. Los ficheros swap lo que permiten es que aunque cierres Vim puedas volver atrás a cambios anteriores y que no pierdas el fichero original.

    Hoy en día esto no es muy recomendable porque por cada fichero se va a crear un fichero swap en el proyecto, recomiendo mejor usar un sistema de control de versiones como git.

    Para desactivar los ficheros swap, en el vimrc tengo estas 3 líneas (esto tampoco te hace falta si usas neovim).

    " .vimrc
    
    set nobackup
    set nowritebackup
    set noswapfile
    

    La siguiente líena que tengo en mi .vimrc sirve para poder usar el backspace del teclado en modo insert en cualquier sitio:

    .vimrc
    set backspace=indent,eol,start    " backspace everywhere in insert mode
    

    La línea anterior tampoco la tengo en mi config de neovim, supongo que porque tampoco hará falta.

    Las siguientes líneas de la config tienen que ver con el identado:

    ".vimrc y init.vim
    
    set autoindent " autoindent always ON.
    set expandtab " expand tabs
    set shiftwidth=2 " spaces for autoindenting
    set softtabstop=2 " remove a full pseudo-TAB when i press <BS>
    

    El autoident sirve a la hora de crear nuevas líenas en el fichero, que dependiendo de donde la crees te meta indentado de forma automática.

    Con expandtab lo que hago es transformar los tabs del identado en espacios (cuestión de gustos), y con shiftwidth y softtabstop configuro los espacios para que sean por defecto de 2 espacios (no te preocupes porque luego puedes definir que para x lenguaje se aplique una config de 4 o de 8), por ejemplo:

    autocmd BufRead,BufNewFile *.java setlocal shiftwidth=4 softtabstop=4
    

    Para el caso de vim asecas también tengo esta config (en neovim no hace falta):

    " .vimrc
    set encoding=utf-8          " always use unicode  
    set hidden                  " to hide warning when opening files
    set ignorecase              " to ignore case in searchs
    

    Como dicen los comentarios con la primera línea le digo a vim que abra los ficheros en UTF-8, con la segunda línea desactivo un warning molesto al abrir un fichero y tener el actual sin guardar y en la última línea le digo a vim que las búsquedas las haga sin tener en cuenta las mayúsculas y minúsculas. Toda esta config no es necesaria en neovim.

    La siguiente config la añadí recientemente. Se trata de una opción que lo que hace es añadir un márgen de unas líneas cuando haces scroll bajando o subiendo el cursor por la pantalla (no me mola que el cursor esté en la última línea de la pantalla al bajar por ejemplo). Esta config también la tengo en neovim.

    " .vimrc y init.vim
    set scrolloff=8               " Keep at least 8 lines below cursor
    

    Config de interfaz

    Sobre la config de interfaz y de UI lo primero que tengo es una opción para habilitar los números relativos. Esto de los números relativos lo que hace es que a la izquierda, en lugar de salirte los números de la línea, te salen de forma relativa, es decir:

    https://jeffkreeftmeijer.com/vim-number/toggle.gif

    Esto sirve para que luego sea más sencillo hacer los saltos de línea, ya que puedes leer directamente el número sin tener que hacer sumas y restas para saber el número de líneas a saltar.

    Para activar esto lo tengo así:

    " .vimrc y init.vim
    
    set number relativenumber   " Relative numbers for jumping               
    set nu rnu  "Hybrid. Relative numbers and the current line number 
    

    También tengo esta config para que a la hora de dividir la pantalla en varios ficheros a la vez, siempre se abran a la derecha y abajo. Echa un ojo también al artículo de Splits en vim .

    " .vimrc y init.vim
    
    set splitbelow splitright   " Set the splits to open at the right side and below 
    

    También tengo esta opción para mejorar un pelín el rendimiento, lo que hace es desactivar el fold (el plegado y desplegado, las típicas flechitas de otros editores para contraer funciones), como no lo uso pues lo quito.

    " .vimrc y init.vim
    
    set foldmethod=manual "To avoid performance issues, I never fold anything  
    

    También relacionado con la performance tengo este par de opciones para hacer que la terminal se pinte cuando se necesite y para aprovechar las ventajas de las terminales rápidas.

    " .vimrc y init.vim
    
    set lazyredraw  
    set ttyfast
    

    Para el caso particular de vim asecas también tengo esta config en esta sección:

    " .vimrc
    
    set showmatch      " higlight matching parentheses and brackets  
    set wildmenu       " enable visual wildmenu
    set nohlsearch     " clear highlight after a search
    

    La primera opción lo que hace es que cuando te pongas con el cursor sobre un paréntesis o llave, automáticamente te señala el de cierre (o el de apertura si estás en el de cierre).

    Con wildmenu lo que consigues es que tengas un pequeño autocompletado de los comandos que escribes con los dos puntos, por ejemplo cuando escribes :color y le das al Tab.

    La última opción es para que al buscar cosas en un fichero, cuando navegues a los resultados se borre el higlight, ya que me pone muy nervioso que se mantenga cuando ya he buscado algo.

    Config de macros y atajos

    Por último vamos a ver la config que tengo de atajos de teclado que uso habitualmente.

    Lo primero es saber que tengo la tecla leader usando la coma por comodidad. La tecla leader se suele usar para crear otros atajos, por lo que a partir de ahora cuando veas <leader en la config estoy hablando de esta tecla.

    " .vimrc y init.vim
    
    let mapleader = ","  
    

    Lo primero que tengo es un snippet para poner un console.log(), como lo tengo mapeado con leader pues para meter el console solo tengo que pulsar , , c

    Por cierto, cuando veas nmap significa que es un mapeo para el Modo normal de Vim, mientras que los de noremap lo que hacen es anular mapeos anteriores (hacerlos no recursivos).

    " .vimrc y init.vim
    
    nmap <leader><leader>c oconsole.log({});<Esc>0t{la  
    

    Este mapeo lo tengo desde hace poco y muy contento. Lo que hace es que al escribir de forma normal en modo insertar, si te da por usar las teclas de dirección del teclado, que no cree puntos de guardado, así cuando pulsas u para volver atrás no tiene en cuenta la pulsación de las flechas.

    " .vimrc y init.vim
    
    inoremap <Left> <c-g>U<Left> 
    inoremap <Right> <c-g>U<Right>  
    

    También tengo estos comandos para poder mover el cursor entre los splits abiertos a la vez en pantalla.

    " .vimrc y init.vim
    
    map <C-h> <C-w>h 
    map <C-j> <C-w>j 
    map <C-k> <C-w>k
    map <C-l> <C-w>l  
    

    Es decir, con los mapeos anteriores puedo pulsar por ejemplo Control + l para moverme al split de la derecha o puedo pulsar Control + k para moverme al de arriba.

    Los siguientes comandos son para trabajar con los buffers. Cuando abres varios ficheros en Vim vas abriendo buffers, y para nevegar entre ellos tengo esto:

    " .vimrc y init.vim
    
    map <C-d>  :bnext<CR>  
    map <C-a>  :bprev<CR>
    imap <C-D> <Esc>:bnext<CR>a 
    imap <C-A> <Esc>:bprev<CR>a
    

    Con esto puedo hacer Control + d para ir al buffer anterior y Control + a para ir al buffer siguiente.

    Siguientes comandos que tengo:

    " .vimrc y init.vim
    
    noremap <silent> <Up> gk  
    noremap <silent> <Down> gj 
    

    Lo que hace es que cuando tienes puesto el editor que haga wrap de las líneas (que si hay una líena muy larga hace un salto de línea “virtual” el editor para que quepa en pantalla), al moverte por las líneas que han saltado puedas hacerlo como si fueran líneas normales.

    También tengo estos comandos para poder hacer resize de los splits de manera más comoda:

    " .vimrc y init.vim
    
    nnoremap <silent> <Leader>h+ :exe "resize " . (winheight(0) * 5/4)<CR> 
    nnoremap <silent> <Leader>h- :exe "resize " . (winheight(0) * 4/5)<CR>   
    
    nnoremap <silent> <Leader>w+ :exe "vertical resize " . (winwidth(0) * 5/4)<CR>  
    nnoremap <silent> <Leader>w- :exe "vertical resize " . (winwidth(0) * 4/5)<CR>  
    

    Es decir, pulsando , h + lo que hago es aumentar el tamaño del split de forma horizontal, mientras que con , h - lo disminuyo, y lo mismo para el verticual pero usando la w en lugar de la h.

    Estos dos son truquitos que he aprendido recientemente.

    " .vimrc y init.vim
    
    nnoremap Y y$
    
    nnoremap n nzzzv 
    nnoremap N Nzzzv 
    nnoremap * *zzzv  
    

    El primero lo que hace es hacer que la letra Y mayúsculas en modo normal se comporte como el resto de letras mayúsculas (como la D por ejemplo).

    Las otras líneas sirven para que al hacer búsquedas y usar la tecla n para ir nevegando entre los resultados, siempre se te mantenga el cursor centrado en pantalla.

    Por último tengo este comando que lo que hace es que al usar :bd para cerrar un buffer, en caso de que lo tengas abierto a la vez con otro fichero (en un split), al ejecutarlo no te reviente el split.

    " .vimrc y init.vim
    
    nnoremap <silent> <C-q> :lclose<bar>b#<bar>bd #<CR>    
    

    Fichero completo de config

    Te comparto también ambos ficheros con mi config. No he incluído plugins y config de plugins para que no sea un lío.

    .vimrc:

    " TABLE OF CONTENTS:
    
    " 1. Generic settings
    " 2. File settings
    " 3. UI
    " 4. Maps and functions
    
    "-----------------------------------------
    " 1. GENERIC SETTINGS
    "-----------------------------------------
    
    set nocompatible " disable vi compatibility mode
    set history=1000 " increase history size
    
    "-----------------------------------------
    " 2. FILE SETTINGS
    "-----------------------------------------
    
    " Stop creating backup files, please use Git for backups
    
    set nobackup
    set nowritebackup
    set noswapfile
    set backspace=indent,eol,start
    
    " Modify indenting settings
    
    set autoindent " autoindent always ON.
    set expandtab " expand tabs
    set shiftwidth=2 " spaces for autoindenting
    set softtabstop=2 " remove a full pseudo-TAB when i press <BS>
    
    " Modify some other settings about files
    
    set encoding=utf-8 " always use unicode
    set hidden
    set ignorecase
    set scrolloff=8 " Keep at least 8 lines below cursor
    set foldmethod=manual " To avoid performance issues, I never fold anything so...
    
    "-----------------------------------------
    " 3. UI
    "-----------------------------------------
    
    set fillchars+=vert:\ " Remove unpleasant pipes from vertical splits
    
    " Sauce on this: http://stackoverflow.com/a/9001540
    
    set wildmenu " enable visual wildmenu
    set number " show line numbers
    set showmatch " higlight matching parentheses and brackets
    set nohlsearch
    set lazyredraw
    set ttyfast
    set hidden
    
    "-----------------------------------------
    " 4. MAPS AND FUNCTIONS
    "-----------------------------------------
    
    let mapleader=","
    
    " Snippet for console.log
    nmap <leader><leader>c oconsole.log({});<Esc>==f{a
    
    " To avoid undo points when using arrow keys
    inoremap <Left> <c-g>U<Left>
    inoremap <Right> <c-g>U<Right>
    
    " Whit leader p you can delete things without saving to register so you can
    " paste what you have before
    vnoremap <leader>p "_d
    
    " Make window navigation less painful.
    map <C-h> <C-w>h
    map <C-j> <C-w>j
    map <C-k> <C-w>k
    map <C-l> <C-w>l
    
    " Working with buffers is cool.
    map <C-d> :bnext<CR>
    map <C-a> :bprev<CR>
    imap <C-D> <Esc>:bnext<CR>a
    imap <C-A> <Esc>:bprev<CR>a
    
    " Capital Y to copy to the end of the line like C or D
    nnoremap Y y$
    
    " To move in the search list but keeping the cursor in the middle of screen
    nnoremap n nzzzv
    nnoremap N Nzzzv
    nnoremap * *zzzv
    
    " To close buffers without closing splits
    nnoremap <silent> <C-q> :lclose<bar>b#<bar>bd #<CR>   
    
    

    También te dejo la config para neovim, aunque es muy similar simplemente tiene menos cosas.

    "------------------------
    " General options
    "----------------------------
    
    set lazyredraw
    set ttyfast
    set number relativenumber " Relative numbers for jumping
    set nu rnu " Hybrid numbers, you have relative numbers and the current line number
    
    set autoindent " autoindent always ON.
    set expandtab " expand tabs
    set shiftwidth=2 " spaces for autoindenting
    set softtabstop=2 " remove a full pseudo-TAB when i press <BS>
    
    set scrolloff=8 " Keep at least 8 lines below cursor
    
    set foldmethod=manual " To avoid performance issues, I never fold anything so...
    
    set noshowmode " We don't need to know the insert/normal mode casue we have lualine
    
    set ignorecase
    set nohlsearch " Clear search highlights
    
    set splitbelow splitright " Set the splits to open at the right side and below
    
    
    "---------------------------
    " Keybindings
    "----------------------------
    
    
    let mapleader = ","
    
    " Snippet for console.log
    
    nmap <leader><leader>c oconsole.log({});<Esc>==f{a
    
    " To avoid undo points when using arrow keys
    
    inoremap <Left> <c-g>U<Left>
    inoremap <Right> <c-g>U<Right>
    
    " Whit leader p you can delete things without saving to register so you can
    
    " paste what you have before
    
    vnoremap <leader>p "_d
    
    " Make window navigation less painful.
    
    map <C-h> <C-w>h
    map <C-j> <C-w>j
    map <C-k> <C-w>k
    map <C-l> <C-w>l
    
    " Working with buffers is cool.
    
    set hidden
    
    map <C-d> :bnext<CR>
    map <C-a> :bprev<CR>
    imap <C-D> <Esc>:bnext<CR>a
    imap <C-A> <Esc>:bprev<CR>a
    
    " Move up/down in wrapped lines by display lines
    
    noremap <silent> <Up> gk
    noremap <silent> <Down> gj
    
    " To resize window height
    
    nnoremap <silent> <Leader>h+ :exe "resize " . (winheight(0) * 5/4)<CR>
    nnoremap <silent> <Leader>h- :exe "resize " . (winheight(0) * 4/5)<CR>
    
    " To resize window width
    
    nnoremap <silent> <Leader>w+ :exe "vertical resize " . (winwidth(0) * 5/4)<CR>
    nnoremap <silent> <Leader>w- :exe "vertical resize " . (winwidth(0) * 4/5)<CR>
    
    " Capital Y to copy to the end of the line like C or D
    
    nnoremap Y y$
    
    " To move in the search list but keeping the cursor in the middle of screen
    
    nnoremap n nzzzv
    nnoremap N Nzzzv
    nnoremap * *zzzv
    
    " To close buffer without closing splits
    
    nnoremap <silent> <C-q> :lclose<bar>b#<bar>bd #<CR>
    
    

    » 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