Weblogs Código

Blog Bitix

Herramientas para mejorar una página web en SEO, conformidad estándares y rendimiento

mayo 08, 2021 11:00

Hay múltiples herramientas que permiten evaluar y mejorar un sitio web en la conformidad de estándares web, rendimiento y SEO. Con los resultados de estas herramientas se han de realizar correcciones en el sitio web para mejorar las páginas del sitio web. La conformidad a estándares web, rendimiento, SEO y enlaces rotos son criterios por los que los buscadores clasifican las páginas en las páginas de resultados. Con un mejor posicionamiento es posible mejorar el número de visitas que los buscadores atraen al sitio web y realizando cambios mejorar la experiencia de usuario.

HTML

Para todos los sitios web es importante y para algunos la fuente más importante de visitas que recibe un sitio web es a través de búsquedas orgánicas de buscadores como Google o como el buscador DuckDuckGo que respeta tu privacidad.

El número de visitas depende de la calidad del contenido, el número de búsquedas que coincide con ese contenido y la competencia por las palabras clave con otros sitios web o algo tan simple como el título de los artículos.

Sin embargo, otra parte para maximizar el rendimiento de un sitio web se debe a otros factores que los rastreadores e indexadores web utilizan para mostrar en las páginas de resultados de las búsquedas y su posición con otros resultados. Conviene que el HTML y CSS de la página cumpla con los estándares, tenga un buen rendimiento, la estructura de la página y contenido tenga palabras clave o no haya enlaces rotos a otras páginas o recursos en el sitio web.

Contenido del artículo

Evaluar SEO

El SEO es un arte ya que no hay una medida precisa de qué criterios emplean los buscadores para clasificar las páginas indexadas en las páginas de resultados. Sin embargo, sí hay algunas pautas que sí contribuyen a un mejor posicionamiento.

Incluir palabras clave y conocer la intención de búsqueda de los usuarios para satisfacer su búsqueda con un contenido apropiado. Asignar un título adecuado y preciso teniendo en cuenta la intención de búsqueda del usuario no mejora el SEO pero si mejora el número de clics que los usuarios lo acceden.

Los datos estructurados o enriquecidos web permiten a los buscadores mostrar en la página de resultados las páginas con un formato que destaca sobre el resto, como incluir una imagen o vídeo. Los datos enriquecidos al igual que un buen título mejoran el porcentaje de usuarios que hacen click en el resultado y por tanto ayuda a conseguir más visitas.

La herramienta Google Search Console proporciona métricas de visitas, informa de los errores que se detectan en la indexación o mejoras a realizar en las páginas asi como cuales son las principales palabras clave, artículos, tasa de clics o CTR y posición de las páginas en los resultados. Otros análisis de SEO son evaluar las páginas según las palabras clave y las pálabras clave de la competencia, algunas de estas herramientas son de pago pero ofrecen unas métricas básicas de modo gratuito.

Evaluar conformidad a estándares web

La organización W3C es la encargada de definir los estándares de la web. Cumplir los estándares es importante ya que de lo contrario es posible que algún navegador o versión de los mismo no muestre correctamente el contenido del sitio web, lo que ocasiona la pérdida de una visitas por una mala experiencia de usuario. Al mismo tiempo en caso de que el contenido de la página no cumpla los estándares los rastreadores quizá no sean capaces de indexar todo el contenido del sitio web o en la clasificación de las páginas de resultados acabe posicionado peor que otros artículos.

La W3C proporciona tres herramientas para evaluar la conformidad de una página a los estándares web para el HTML y feeds. En caso de que el sitio web genere contenido en formato amp promovido por Google hay otra herramienta para evaluar la conformidad. Conociendo los elementos en los que la página no es conforme se han de realizar cambios para solventar los errores.

Accesibilidad

Otro aspecto de conformidad de estándares que ha de ser tenido en cuenta es hacer que las páginas del sitio web sean accesibles para que el acceder a la páginas no suponga ninguna barrera a ningún usuario incluyendo a aquellos que poseen algún tipo de discapacidad. Algunas pruebas de accesibilidad es incluir un texto alternativo para todas las imágenes de la página web y que el contraste de color de la fuente y de fondo tenga un mínimo de diferencia.

Evaluar rendimiento

El tiempo que tarda en descargar una página es otro criterio que los buscadores tiene en cuenta para clasificar los resultados. Se considera como positivo para la experiencia de usuario que una página tarde el menor tiempo posible en descargarse por ello los motores de búsqueda lo tienen en cuenta en la indexación. En el tiempo de descarga influyen factores como el tamaño en KiB de la página, número de peticiones y recursos que carga la página.

Estas dos herramientas proporcionan información sobre la página, con resultado proporcionado es posible hacer modificaciones para tratar de mejorar en los puntos con peor evaluación.

Buscar enlaces rotos

Con el paso de tiempo algunos de los enlaces incluidos en los artículos quedarán rotos al cambiarlos de ubicación el propietario de esos sitios web. Que un sitio web contenga enlaces rotos proporciona una mala experiencia de usuario y posiblemente los buscadores lo tomen como un criterio negativo si el sitio web tiene muchos enlaces rotos.

De forma periódica conviene analizar el sitio web para buscar enlaces o recursos rotos. También hay herramientas para automatizar la búsqueda y con los resultados corregirlos.

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

Header Files

Introducción a boost::program_options

mayo 07, 2021 03:16

Introducción

Toda aplicación de C++ (y C) tienen una función que sirve de punto de entrada, es decir, es la función que el sistema operativo llama cuando ha terminado de preparar al proceso y va a comenzar la ejecución del código propiamente dicho (puede que ocurran algunas cosas antes, pero no entraremos en eso). Esta función es la tradicionalmente conocida como main, y tiene la siguiente sintaxis base:

int main(int argc, char *argv[]) {}

Donde el valor de retorno es el valor de retorno del proceso, y los dos parámetros son el número de argumentos recibidos, y una lista de dichos argumentos previamente separados por espacios. El primer argumento es el nombre del ejecutable (aunque puede variar dependiendo cómo haya sido lanzado el proceso).

C y C++ no limitan la forma de utilizar los argumentos de entrada, pero cada sistema operativo tiene sus estándares (costumbres). Por ejemplo, en Windows lo normal es usar / como prefijo para indicar opciones, mientras que Unix y Linux usan - para opciones en formato corto (una sola letra), y -- para el formato largo. Pero de nuevo, cada programador es libre de usar el formato que desee, aunque lo mejor es adherirse al estándar del sistema.

La forma de extraer e interpretar los argumentos también se deja a merced de cada programador, y normalmente es un proceso tedioso ya que hay que lidiar con listas de opciones, formato de cada una, comandos no reconocidos, argumentos inválidos, etc. Por suerte, hay algunas ayudas como getopt en sistemas GNU, QCommandLineParser de Qt, y boost::program_options, que es mi preferida y de la que hablaré hoy. Aunque no pueda cubrirla al 100%, ya que es bastante extensa, trataré de indicar algunos de los casos de uso más frecuentes.

Gestión de opciones

Antes que nada, comentar una metodología de trabajo habitual cuando se desarrolla una aplicación con argumentos por línea de comandos: delegar todo este trabajo en una clase. Esto reduce la cantidad de código en el main (recomendable), desacopla la gestión de parámetros de su interpretación, abstrae de los detalles de implementación (nombre del parámetro, biblioteca para interpretarlos, tipo de dato, gestión de errores, etc.), y centraliza toda la variabilidad propia de los parámetros de ejecución. Así, un ejemplo (aleatorio) sería:

// command_line_options.h
#include <string>

struct CommandLineOptions {
    std::string input_path;
    std::string output_path;

    std::string lang;

    int error_level = 0;
    bool verbose = false;

    bool parse(int argc, char* argv[]);
};
#include "command_line_options.h"

int main(int argc, char* argv[]) {
    CommandLineOptions options;

    if (!options.parse(argc, argv)) { return 1; }

    // Use 'options'
    setLanguage(options.lang);
    initLog(options.error_level, options.verbose);
    // ...
}

boost::program_options

Boost, como en muchas cosas, es la gran navaja suiza de C++ (otro tanto es la biblioteca Poco, que la dejo para quien no la conozca, así como mi querido Qt). De entre todos sus módulos, suelo sacar mucho provecho de program_options, que simplifica la gestión de argumentos de entrada de un programa. A lo largo del artículo usaré el alias po para referirme a este espacio de nombres.

Su funcionamiento podríamos dividirlo en tres partes:

  • Definición de opciones
  • Análisis de los argumentos
  • Uso de las opciones

Definición de opciones

Acá listaremos todas las opciones que nuestra aplicación reconoce, indicando su nombre, tipo y descripción. Para ello usamos la clase options_description.

En el siguiente ejemplo definimos los posibles comandos -? / --help, --input / -i, --output / -o, --language, --error-level, -v / --verbose:

po::options_description po_desc("Allowed options");
po_desc.add_options()
  ("help,?", "shows this help message")
  ("input,i", po::value<std::string>()->required(), "input path")
  ("output,o", po::value<std::string>()->required(), "output path")
  ("language", po::value<std::string>()->default_value("en"), "UI language")
  ("error-level", po::value<int>()->default_value(0), "error level")
  ("verbose,v", po::bool_switch()->default_value(false), "show verbose log")
  ;

Cada opción se define con el nombre de la misma, pudiendo añadir el formato corto. A continuación se puede especificar el tipo (con un valor por defecto si fuese el caso), o si es obligatoria. Por último, se añade una descripción de la opción, que será la mostrada en la línea de comandos al solicitar la ayuda.

En lo particular me gusta darle valores por defecto a las opciones no obligatorias; de esta forma se simplifica el flujo posterior, la validación de la entrada y hace nuestro código un poco más robusto ante omisiones.

Un ejemplo de argumentos para nuestra aplicación anterior sería: app --input file.txt -o output.txt --error-level 5 -v.

Parámetros ocultos

Es posible definir los parámetros en diversos options_description. Los principales usos son el de poder discriminar cuáles se usan (por ejemplo, en base a la versión del sistema anfitrión, licencia del cliente, variables de entorno, etc.), o el de definir parámetros ocultos (ya veremos a qué me refiero).

Boost sólo puede interpretar un único conjunto de opciones, así que la solución pasa por unificar las que necesitemos como paso previo a la interpretación:

po::options_description po_desc_hidden("Hidden options");
po_desc_hidden.add_options()
  ("gold", po::bool_switch()->default_value(false), "give you a lot of gold")
;

po::options_description cmdline_options;
cmdline_options.add(po_desc).add(po_desc_hidden);

Sugerencia👀

Como nota de experiencia, sugiero desactivar el formateo automático de código para esta sección, a fin de mantener cada opción en una línea. Esto mejora la lectura del códguo y mantiene más limpio el historial de cambios en el repositorio. For ejemplo, si usáis clang-format:

// clang-format off
po_desc.add_options()
  // ...
  ;
// clang-format on

Análisis de los argumentos

El siguiente paso es parsear (analizar gramaticalmente) la línea de comandos:

po::variables_map po_vm;
try {
  po::store(po::command_line_parser(argc, argv).options(cmdline_options).run(), po_vm);
  po::notify(po_vm);
} catch (po::error &e) {
  std::cout << e.what() << '\n';
  std::cout << po_desc << '\n';
  return false;
} catch (...) {
  std::cout << "Unknown error\n";
  std::cout << po_desc << '\n';
  return false;
}

Si la línea de comandos tiene algún error (normalmente parámetros desconocidos o formato incorrecto), capturaremos la excepción (mostrando el error si lo conocemos) y luego mostramos una ayuda para que el usuario sepa cuál es la sintaxis correcta (std::cout << po_desc << '\n'). Nótese que en esta línea no usamos cmdline_options sino po_desc, que es la que contiene la lista de opciones pública; si mostrásemos cmdline_options estaríamos revelando todas las opciones del programa (y en este ejemplo no nos interesa). Por último, indicamos que la función parse ha fallado devolviendo un false.

Uso de las opciones

Ahora tenemos la línea de comandos descompuesta en las opciones que hemos definido, y almacenadas en la variable po_vm; solamente nos queda poner los valores correctos a las variables.

Existen varias formas de acceder a estas opciones, aunque las tres más comunes son:

  • Verificando si la opción ha sido escrita por el usuario: po_vm.count("option_name") > 0.
  • Sabiendo que existe (bien por el método anterior, o porque hemos indicado que siempre tenga un valor por defecto), podemos acceder a su valor: po_vm["option_name"].as<T>, donde T es el tipo de datos que hemos indicado en la definición. Aviso⚠: acceder de esta forma a una opción no definida o sin valor lanza una excepción. Por mi parte, en lo posible trato de que todas las opciones tengan un valor por defecto
  • Asociando una opción a una variable: esta opción es muy práctica, aunque no la suelo usar simplemente porque me gusta separar mentalmente el análisis de la interpretación, sabiendo que no tengo valores a medias en caso de error. Para asociar una opción a una variable solamente tenemos que indicarlo en la definición de la opción: ("language", po::value<std::string>(&lang), "UI language").
if (po_vm.count("help")) {
  std::cout << po_desc << '\n';
  return false;
}

input_path = po_vm["input"].as<std::string>();
output_path = po_vm["output"].as<std::string>();

lang = po_vm["language"].as<std::string>();

error_level = po_vm["error-level"].as<int>();
verbose = po_vm["verbose"].as<bool>();

Otros tópicos

Argumentos posicionales

Los argumentos posicionales son aquellos cuya semántica viene dada por su posición en la lista de argumentos. Por ejemplo app input.txt output.txt podría tener dos argumentos posicionales, donde el primero representa al ruta del fichero de entrada y el segundo la ruta del de salida.

De nuestro ejemplo anterior, supongamos queremos que el fichero de entrada y el salida sean posicionales:

po::positional_options_description po_pos;
po_pos.add("input", 1);
po_pos.add("output", 1);

Los argumentos se seleccionan en el orden en el que se definen, y se asocian a la opción con el nombre que se indica. El número después del nombre indica cuántos argumentos de ese tipo se esperan, donde -1 indica ilimitados (como dice la lógica, no se pueden definir nuevos argumentos posicionales una vez se define uno ilimitado).

Por último, es necesario añadirlos al analizador:

po::store(po::command_line_parser(argc, argv).options(cmdline_options).positional(po_pos).run(), po_vm);

Argumentos en UNICODE

Me gustaría hacer un comentario aparte acerca de cuando los argumentos no usan una codificación ANSI: si necesitamos leer un fichero y su ruta (path) viene dado como argumento de la línea de comandos, es probable que dicha ruta contenga caracteres fuera del espectro de ANSI: vocales acentuadas, la española Ñ, caracteres en cirílico, un nombre de usuario en chino tradicional, etc. Por supuesto, aunque este quizá sea el escenario más tradicional, podríamos encontrar el mismo problema en muchos otros.

Este problema lo planteé en Stack Overflow hace ya un tiempo; expongo acá la respuesta como complemento del artículo. Importante⚠: esta solución está enfocada a Windows.

  • Cambiar el punto de entrada para que acepte cadenas de texto en UNICODE: int wmain(int argc, wchar_t* argv[]).
  • Usar boost::program_options::wvalue en lugar de boost::program_options::value cuando el argumento espere valores en UNICODE.
  • Usar un tipo de datos std::wstring para estos argumentos.
  • Usar boost::program_options::wcommand_line_parser en lugar de boost::program_options::command_line_parser para aceptar la lista de argumentos en wchar_t*.

Aun más

Este breve tutorial deja por fuera algunas otras opciones, que enumero a continuación:

  • Uso de sintaxis no estándar).
  • Permitir argumentos no registrados (por ejemplo, para re-enviarlos a otro comando).
  • Uso de argumentos provenientes del punto de entrada WinMain.
  • Validadores personalizados (por ejemplo, que sea requiera un e-mail y sea el propio Boost el que compruebe que la entrada corresponde con un formato de e-mail válido).

Estos tópicos están documentados en este anexo de Boost.

Ejemplo completo

Se puede probar la mayoría del código de este artículo en vivo.

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

Blog Bitix

La tinta electrónica y los mejores lectores de libros electrónicos

mayo 06, 2021 05:30

Un lector de libros electrónico ofrece mayor comodidad frente a los libros en formato físico, en cuanto a peso y volumen de libros ni los libros ocupan espacio una vez leídos. Son ligeros, de tamaño reducido, ofrecen una lectura bajo el sol equivalente al formato impreso y añaden algunas funciones adicionales como luz integrada y un diccionario de palabras. Tienen un precio asequible y muchos libros electrónicos un precio inferior a la versión en formato físico en papel.

Hace ya bastante tiempo que están disponibles para comprar dispositivos de lectores de libros electrónicos como sustitución a los tradicionales libros de formato en papel. Los libros en formato electrónico mejoran algunos aspectos de los libros en formato en papel, su tinta electrónica de escala de grises es equivalente a un libro en formato impreso.

En el mercado hay varios lectores de libros electrónicos a unos precios bastante asequibles con ofertas puntuales cada cierto tiempo.

Contenido del artículo

La tinta electrónica

La experiencia de lectura de los libros electrónicos es equivalente a la de formato en papel. Las pantallas de tinta electrónica son legibles con luz natural ni ofrecen reflejos al contrario de lo que ocurre con el tipo de pantallas que usan los teléfonos móviles inteligentes.

La resolución de las pantallas de tinta electrónica llega a 300 ppp y unos 1024x758 píxeles ofreciendo una escala de grises comúnmente de 16 tonos. Las pantallas de la mayoría de dispositivos tienen un tamaño de 6 pulgadas de diagonal.

Cuando se generalice comercialización de lectores con tinta electrónica a color supondrá otro paso en la sustitución del formato en papel pudiendo reemplazar algunos formatos como los comics. Incluso si en el futuro mejoran su tiempo de actualización quizá ofrezcan la reproducción de contenido como vídeos o imágenes en movimiento proporcionando una característica que no tiene el formato en papel.

Utilizan una batería y requieren ser cargados cada cierto tiempo. Las pantallas de tinta electrónica sólo consumen energía cuando se cambia de página, una sola carga de batería es suficiente para la lectura de una novela de 300 páginas. El dispositivo puede estar un mes en modo reposo antes de necesitar ser cargado de nuevo. La carga se realiza igual que un smartphone y tarda menos de 4 horas en cargarse por completo.

Ventajas de los libros electrónicos

Los libros electrónicos tienen varias ventajas sobre los libros en formato en papel. En primer lugar el formato físico es reemplazado por un dispositivo lector de libro electrónico, los libros ya no son físicos sino que son electrónicos con el consiguiente ahorro de espacio para los mismos una vez ya leídos.

El lector de libros electrónicos es capaz de contener la totalidad de los libros físicos en formato electrónico. Dado que el libro electrónico de una novela de 300 páginas apenas ocupa 1 MB en formato electrónico y que los libros electrónicos tienen una memoria de 2 o más GB, los lectores son capaces de contener gran cantidad de libros. En desplazamientos como viajes o vacaciones el libro electrónico es mucho más cómodo ya que contiene los varios libros a leer no siendo necesario transportar los libros físicos individuales.

El peso del dispositivo lector de libros electrónicos es más liviano que los libros en formato en papel. Un libro voluminoso de 500 o 1000 páginas ocupa espacio y pesa bastante lo que los hace incómodos de leer en algunas situaciones como en en transporte público.

Algunos lectores de libros electrónicos ofrecen luz integrada lo que permite la lectura en situaciones de baja luz natural sin necesidad de luz artificial adicional.

En los libros electrónicos ofrecen funciones adicionales que no tiene un libro en formato físicos como la posibilidad de cambiar el tamaño de la fuente, el espaciado entre líneas y el tipo de la fuente. Otra función es tener un diccionario integrado para consultar la definición de alguna palabra.

En algunos casos el libro electrónico es más barato que el equivalente en formato físico. Si se es un lector habitual que lee varios libros al año, el precio del dispositivo se ve compensado por el ahorro en los libros electrónicos.

Lectores de libros electrónicos

En el mercado hay varios modelos de libros electrónicos con un precio entre 80 y 300 €. Los lectores electrónicos más populares son los Amazon y los modelos de Kobo.

Amazon Kindle

Los dispositivos de libros electrónicos de Amazon son de los más populares, ofrece varios modelos en diferentes franjas de precios. Amazon al vender libros electrónicos en su tienda y dado que los dispositivos están integrados con sus servicios es fácil dotarles de contenido.

Lector de libros electrónicos Kindle Touch del año 2011

Lector de libros electrónicos Kindle Touch del año 2011

Hay varios modelos de Kindle con una gama de lectores que se ha ido renovando a lo largo del tiempo con versiones que mejoran paulatinamente las anteriores. Los modelos actuales se catalogan en los siguientes:

  • Kindle: es la versión más básica y económica de los tres modelos, tiene un tamaño de pantalla de 6 pulgadas táctil con luz integrada, una resolución de 167 ppp y una capacidad de 8 GB de memoria para almacenar libros.
  • Kindle Paperwhite: tiene un tamaño de pantalla de 6 pulgadas táctil con luz integrada, una resolución de 300 ppp y una capacidad de 8 o 32 GB de memoria para almacenar libros. Tiene un diseño sin bordes y es resistente al agua.
  • Kindle Oasis: es la opción de gama alta, tiene un tamaño de pantalla de 7 pulgadas táctil con luz integrada ajustable, botones físicos para el paso de página con un diseño ergonómico para diestros o zurdos, una resolución de 300 ppp y una capacidad de 8 o 32 GB de memoria para almacenar libros.

La conectividad de los Kindle se realiza mediante red WIFI o cable USB aceptando los siguiente formatos de forma nativa (Formato 8 Kindle (AZW3), Kindle (AZW), TXT, PDF, MOBI sin protección, PRC de forma nativa) y otros formatos por conversión.

Un accesorio para el lector de libros electrónicos es una funda para los modelos Kindle que lo proteja de golpes y suciedad.

Kobo

Otra empresa que fabrica lectores de libros electrónicos es Kobo que en características son similares a los de Amazon. Estos también se venden en la propia tienda de Amazon y algunas tiendas físicas.

  • Kobo Nia: es la versión más básica y económica, tiene un tamaño de pantalla de 6 pulgadas táctil con luz integrada, una resolución de 212 ppp y una capacidad de 8 GB de memoria para almacenar libros.
  • Kobo Clara HD: tiene un tamaño de pantalla de 6 pulgadas táctil con luz integrada, una resolución de 300 ppp y una capacidad de 8 GB de memoria para almacenar libros.
  • Kobo Libra H2O: tiene un tamaño de pantalla de 7 pulgadas táctil con luz integrada, botones físicos para el paso de página con un diseño ergonómico para diestros o zurdos, una resolución de 300 ppp y una capacidad de 8 GB de memoria para almacenar libros.
  • Kobo Forma: tiene un tamaño de pantalla de 8 pulgadas táctil con luz integrada resistente al agua, botones físicos para el paso de página con un diseño ergonómico para diestros o zurdos, una resolución de 300 ppp y una capacidad de 8 GB o 32 GB de memoria para almacenar libros.

La conectividad de los Kindle se realiza mediante red WIFI o cable USB aceptando 15 formatos de libros electrónicos de forma nativa (EPUB, EPUB3, FlePub, PDF, MOBI, JPEG, GIF, PNG, BMP, TIFF, TXT, HTML, RTF, CBZ, CBR) y otros formatos por conversión.

También hay fundas para los modelos de Kobo en Amazon.

Otras opciones

Otras tiendas como El Corte Ingles o PcComponentes también ofrecen algunos otros dispositivos de libros electrónicos. Sus precios son similares pero los de Amazon y Kobo son dispositivos en algunos aspectos mejores.

El modelo PocketBook InkPad Color destaca por ser de los pocos que utilizan tinta electrónica a color, para la lectura de novelas el color es prescindible pero es muy interesante para la lectura de comics, manga o libros con ilustraciones.

Dónde comprar libros electrónicos

Amazon además de los lectores Kindle en su tienda ofrece la compra de una gran variedad de libros en formato electrónico en Amazon. La Casa del Libro también tiene su tienda de libros electrónicos.

Dado que los libros electrónicos son un formato digital con una distribución más sencilla su precio si no son más baratos tiene el mismo precio que las ediciones en formato físico.

Estos son algunos ejemplos de libros electrónicos que Amazon vende en su tienda, entre ellos los libros electrónicos más vendidos.

Si el libro deseado a leer no se encuentra en una de estas tiendas porque ya tiene varios años de publicación ni son las últimas novedades o está descatalogado hay algunas páginas de descargas de libros electrónicos al igual que hay páginas de descargas de películas y series que permiten obtener los libros en formato digital.

Cómo añadir libros electrónicos al lector

Hay dos formas de añadir los libros electrónicos al lector de libros. Una de ella es conectando el dispositivo con un cable USB al ordenador que es reconocido como un dispositivo de memoria y posteriormente copiando el archivo del libro electrónico al dispositivo.

Otra forma en el caso de los Amazon Kindle a través de la red WIFI, si se ha comprado el libro en la tienda de Amazon aparecerá como descarga y se trata de un libro obteniendo de otra forma enviándolo a una dirección de correo especial que añade el libro al contenido digital descargable en el dispositivo.

Cómo convertir libros electrónicos a un formato soportado por el lector

Dependiendo del lector de libro electrónico soportará unos formatos u otros. Los dos más comunes son el EPUB soportado por los Kobo y el AZW o MOBI soportado por los Kindle.

Si se necesita convertir el formato de libro electrónico a otro formato que soporte el dispositivo la aplicación gestor de libros electrónicos Calibre permite además para catalogar los libros de la biblioteca digital para realizar la conversión entre formatos.

Gestor de biblioteca y conversor de libros electrónicos Calibre

Gestor de biblioteca y conversor de libros electrónicos Calibre

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

Picando Código

Siete días en el Picandoverso: Mayo – 2021

mayo 05, 2021 10:30

La última semana estuvo bastante complicada y pasé poco rato en la computadora fuera del horario de trabajo. Por eso tocó un post un poco corto, pero acá van algunos enlaces interesantes para compartir de la última semana:

Siete días en el Picandoverso Mayo 1 2021

Tecnología y Programación

🎤 EMEA on Rails es un meetup de meetups con el objetivo de unir distintos meetups de Ruby/Rails en la zona horaria de Europa, el Medio Oriente y África. El próximo encuentro (virtual obviamente) es el 9 de junio. Podemos entrar a su sitio web para ver más o seguirles en Twitter para mantenerlos al tanto de más novedades. Por ahora hay meetups registrados de Austria, Escocia, Inglaterra, Israel, Suiza, Alemania y más.

📼 En posts anteriores he mencionado a Jemma Issroff y su trabajo con Ruby. El mes pasado dio una charla en el Ruby Meetup de Berlín, y el video está subido a YouTube. La charla se llama “A Day in the Life of a Ruby Object” y explica detalles sobre el Garbage Collector, el uso de memoria instanciando objetos, herramientas que podemos usar para analizar la memoria y más.

💎 Leyendo Emacs News me enteré de RBS mode, un modo de Emacs para editar RBS (el lenguaje para definir tipos de Ruby). Tengo que probar este nuevo sistema de tipados… ¡algún día tendré tiempo!

🛤 Con todo el lío con Basecamp y las cagadas que se mandó management, Rails publicó un artículo donde aclaran cómo se gobierna el proyecto. Era necesario para calmar en parte a quienes sin haber colaborado con una línea de código a Rails ya estaban “pidiendo fork”. El equipo central de Rails cuenta con 11 personas, de las cuales 2 trabajan en Basecamp. Lo más importante relacionado al tema es: Hay un proceso de consenso y nadie en el equipo central, o sus empleadores, tiene control único sobre el framework o la comunidad. No hay un individuo o sub grupo de individuos que tengan el poder de ejecutar políticas unilateralmente en los espacios de la comunidad Rails que operan. Así que a calmarnos que usar Rails no implica que estemos de acuerdo ni aprobemos lo que hace o dice su creador…

🐧 El código fuente de Linux superó el millón de commits, se puede ver más claro en el mirror en GitHub.

🎨 Volví a cambiar mi tema de Emacs, hace un par de semanas (o meses 🤷🏻‍♂️) cambié a curry-on , pero ahora pasé a wilmersdorf, un tema oscuro, sutil y sin mucho contraste.

🌐 Apache ya no es el servidor web más usado en el mundo. Por primera vez Nginx supera en uso al viejo y querido Apache, aunque siguen estando bastante parejos.

📚 El bundle de ebooks Head First Programming por O’Reilly sigue estando activo hasta el 10 de este mes, podemos adquirir un montón de libros muy buenos para iniciarnos en distintos temas de programación al precio que elijamos.

Cómics

🧙‍♂️ Alan Moore vuelve a los cómics después de haberse “retirado” hace un par de años. Va a publicar una serie de cinco volúmenes de fantasía y una colección de cuentos cortos.

💬 Creo que este mes aflojan un poco los cómics que voy a leer. Marvel está pasando por otro de esos mega eventos aislados que pasan sólamente una vez cada 3 meses y nunca nada volverá a ser como antes. Los esquivo como a la gente sin máscara en el supermercado, así que voy a evitar comprar todos los tie-ins y crossovers con Heroes Reborn que haya…

Mientras tanto Immortal Hulk se va acercando a sus números finales, si es que va a terminar en el número 50 😱 Y sigo leyendo: BRZRKR que va por el segundo número y viene bien. Beta Ray Bill que tiene un arte excelente y la historia está muy entretenida. Daredevil de Chip Zdarsky que como todo lo que escribe Zdarsky está bueno (Spider-Man: Spider’s Shadow, el “What If?” donde Spider-Man se quedaba con el traje extraterrestre en vez de Venom, está tremendo también). Non-Stop Spider-Man por Joe Kelly y Chris Bachalo que está muy bien pero lamentablemente atrasó los próximos números un mes para adelante. En breve vuelvo a leer DC con Superman and The Authority de Grant Morrison. En su momento leí todo lo que había de The Authority y me gustó mucho, vamos a ver cómo andan Apollo, Midnighter y el resto de la pandilla. También agregué a mis suscripciones el nuevo título de Shazam!

Películas/TV

🌌 Ayer 4 de mayo, fue día de celebración de Star Wars (por May the Fourth/May the Force). En Disney+ se estrenó Star Wars: The Bad Batch, una serie secuela/spin-off de la serie The Clone Wars. La premisa:

La “Fuerza Clon 99”, también conocidos como “Bad Batch”, es un grupo de soldados clon de élite con mutaciones genéticas que se presentaron por primera vez en Star Wars: The Clone Wars, tomando misiones mercenarias tras haber terminado la Guerra de los Clones.

YouTube Video

Miré el primer capítulo y me gustó mucho. Seguiré mirando…

🍿 También miré la película animada de Netflix The Mitchells vs. The Machines y me encantó. ¡La recomiendo! En este tweet (¡spoilers!) publiqué un clip de la película donde expresan perfectamente lo que se siente ser programador 😆

❤ Marvel Studios publicó un video “Celebrando las Películas”. No sólo hicieron un repaso del Universo Cinematográfico de Marvel con un voice over de Stan Lee que me erizó todo, también adelantan por primera vez imágenes de The Eternals y fechas y nombres de películas que se vienen en los próximos años. Creo que las novedades además de las fechas son el nombre de la secuela de Black Panther – Black Panther: Wakanda Forever y Captain Marvel – The Marvels (¡con la S de Ms Marvel!). Al final del video un logo de los Fantastic Four, aunque ya estábamos al tanto que estaba en pre-producción y por fin puede que haya una película decente de la primera familia de Marvel.

YouTube Video

Otros 7 días en el Picandoverso:

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

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

Picando Código

ngrok – expone tus servidores locales a través de NATs y Firewalls a la internet pública sobre túneles seguros

mayo 04, 2021 11:00

ngrokHace poco tuve que usar ngrok para exponer un servidor de desarrollo local como redireccionamiento para probar el proceso de OAuth. ngrok es una herramienta que expone tus servidores locales a internet a través de túneles seguros por NATs y firewalls.

Es una herramienta muy práctica que nos permite compartir lo que estemos ejecutando en local con cualquier persona con acceso a internet. Sumamente útil para tareas de desarrollo o demos, si tenemos una aplicación corriendo en local pero todavía no hemos subido los cambios a un servidor público.

Para empezar a usar ngrok, tenemos que descargarlo (está disponible para FreeBSD, Linux, Mac OS y Windows). Se nos provee un zip con un archivo ejecutable y ya lo podemos empezar a usar ni bien lo descomprimimos. En mi sistema tengo un directorio bin en mi directorio personal. Éste está agregado al path de mi bash, así puedo ejecutar cualquier comando que deje en ese directorio llamándolo directamente.

En este ejemplo levanté un servidor con Rack en el puerto 9292, después ejecuté ngrok con ngrok http 9292. De ahí podemos o bien copiar la URL pública que nos da ngrok o abrirla desde el navegador web:

ngrok incluye una interfaz web que podemos ver visitando http://localhost:4040 cuando ngrok se está ejecutando. Nos muestra detalles de los pedidos web y detalles del estado de la aplicación.

Su uso es gratuito para demos y necesidades simples como desarrollo. Los puertos y URL generados son al azar y podemos tener 1 proceso ngrok online a la vez, entre otras limitaciones. Trabaja con un modelo de pago que nos provee más opciones como subdominios personalizados, SSO con Google Apps, dominios reservados y más recursos. Los precios parecen bastante razonables para empresas.

Sitio oficial de ngrok

El post ngrok – expone tus servidores locales a través de NATs y Firewalls a la internet pública sobre túneles seguros fue publicado originalmente en Picando Código.

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

Variable not found

Cómo mostrar por consola las líneas que se van añadiendo a logs o archivos de texto, en tiempo real

mayo 04, 2021 06:05

Logging

Hace unos días pasaba a un amigo una instrucción de PowerShell para visualizar en tiempo real el contenido que iba añadiéndose al final de un archivo de log en Windows, y pensé que igual podía ser útil para alguien más, así que aquí va :)

El asunto es tan simple como abrir un terminal o consola PowerShell en la carpeta donde tengamos el archivo y ejecutar la siguiente orden:

Get-content log.txt -Tail 0 -Wait

A partir de ese momento, la consola quedará bloqueada e irá mostrando en tiempo real las últimas líneas añadidas al archivo:

Ventana de consola mostrando las últimas líneas añadidas a un archivo de texto

Esta idea tan sencilla podría ser combinada en scripts que nos simplifiquen alguna tarea más; por ejemplo, si estamos en una carpeta con archivos de trazas de distintos días, es sencillo conseguir que se abra el fichero de log más reciente, de forma que no tengamos que introducir su nombre cada vez que queramos utilizarlo:

# File: ViewLog.ps1
$file = Get-ChildItem -Filter *.txt | Sort-Object LastAccessTime -Descending | Select-Object -First 1
if($file)
{
Get-content $file -Tail 0 -Wait
}

¡Espero que os sea útil!

Publicado en Variable not found.

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

Variable not found

Enlaces interesantes 442

mayo 03, 2021 06:05

Enlaces interesantes

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

Por si te lo perdiste...

.NET Core / .NET

ASP.NET Core / ASP.NET / Blazor

Azure / Cloud

Conceptos / Patrones / Buenas prácticas

Data

Machine learning / IA / Bots

Web / HTML / CSS / Javascript

Visual Studio / Complementos / Herramientas

Xamarin

Otros

Publicado en Variable not found.

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

Coding Potions

Cómo crear un reloj analógico con Javascript - Sortilegios 02

mayo 03, 2021 12:00

Qué vamos a hacer

Seguimos con la serie de artículos en las que vamos a construir pequeños proyectos como excusa para aprender programación. En este segundo episodio vamos a seguir con el día 2 de #Javascript30, el reto de construir 30 pequeñas aplicaciones web con Javascript.

Este tiene un enunciado sencillo, pero no te dejes engañar, si no sabes cómo abordarlo puede que al principio te cueste. Para este reto se pide crear un reloj analógico con CSS y JS.

🗺️ Hoja de ruta

  • Crear el HTML con los elementos a dibujar
  • Dar estilos a los elementos para que parezcan un reloj
  • Pasar la hora actual a grados
  • Coger los elementos del HTML y pasarle los estilos para que marquen la hora

Manos a la obra 👷

Creado la vista y los estilos

Lo que voy a hacer es hacerlo con SVG. Aunque también se puede hacer con elementos HTML he preferido hacerlo así para dar alguna pincelada sobre SVG.

Empecemos por el círculo:

<div class="clock">
  <svg class="circle" viewBox="0 0 120 120" version="1.1"
    xmlns="http://www.w3.org/2000/svg">
    <circle cx="60" cy="60" r="60" />
  </svg>
</div>

Creamos un div simplemente para meter el SVG que contendrá la esfera del reloj y las manecillas.

Como ves, en SVG existe un elemento destinado a crear círculos. Las propiedades cx y cy marcan la posición del círculo dentro del reloj, en esta caso al ser la mitad que la viewBox, se situará en el centro.

De momento simplemente voy a posicionar el reloj en el centro usando CSS.

.clock {
  margin: 0px auto;
  width: 650px;
  height: 650px;
}

Como no hemos definido un color para el círculo por defecto se pintará en negro. Para añadir un color tienes que hacerlo mediante la propiedad fill, la puedes añadir en el HTML o en el CSS:

<circle cx="60" cy="60" r="60" fill="#fabada" />
circle {
  fill: #fabada;
}

Creando las manecillas

Vamos ahora con las manecillas. La idea es crear 3 líneas dentro del SVG (una para cada manecilla). En principio las voy a crear para que salgan desde la parte de arriba y vayan hasta el centro del reloj.

Las líneas serían así:

<line x1="60" y1="0" x2="60" y2="60" class="hours" />
<line x1="60" y1="0" x2="60" y2="60" class="minutes" />
<line x1="60" y1="0" x2="60" y2="60" class="seconds" />

Los parámetros x1 y y1 sirven para indicar la posición dentro del SVG del punto de partida. En este caso el punto de partida es 60 (el radio del círculo) para el eje X y 0 en el Y para que se coloque arriba en el centro del reloj.

Los parámetros x2 y y2 son para el punto de destino de la línea, en nuestro caso el centro del reloj, por lo tanto 60 y 60.

También he añadido clases CSS para poder cambiar el color de las líneas usando la propiedad stroke. Esto no lo hago con el fill porque con stroke quiero que sea como una propiedad de un borde, así puedo añadir stroke-linecap para redondearlo y que no sea una línea rectangular.

Además, para las 3 líneas he puesto que el transform-origin esté en el centro para que al rotar la línea se haga desde el centro del reloj.

.hours,
.minutes,
.seconds {
  transform-origin: center;
  stroke-linecap: round;
  stroke-width: 3px;
}
.hours {
  stroke: cyan;
}
.minutes {
  stroke: lime;
}
.seconds {
  stroke: fuchsia;
}

Vamos ahora con el Javascript.

Calculando la rotación de las manecillas

El Javascript parece que puede ser muy complicado pero si lo piensas no lo es tanto.

Simplemente lo que necesitamos es calcular los grados de rotación de cada manecilla pasando la hora actual. Haz una prueba, en el CSS pon esto:

.minutes {
  stroke: lime;
  transform: rotate(90deg);
}

¿Ves que la manecilla de los minutos ahora apunta hacia la derecha? Eso es gracias al transform-origin, tan solo tenemos que sacar los grados entre 0 y 360 (360 porque una circunferencia tiene 360 grados). Ya puedes quitar lo del transform.

Lo primero que he hecho es crear una función que se autoejecuta para que se lance cuando se cargue el Javascript.

(function () {
   calculateHourDegrees();
   calculateMinuteDegrees();
   calculateSeconds();
})();

Simplemente llamo a 3 funciones que voy a crear ahora para calcular los grados de cada manecilla.

Lo siguiente que hago es crear una función que servirá para hacer una especie de regla de 3 para poder calcular los grados:

function linearMap(value, min, max, newMin, newMax) {
    return newMin + (newMax - newMin) * (value - min) / (max - min);
}

Es muy simple, pasas un número value y con min y max pones el rango que tiene ese valor, es decir, el mínimo valor y el máximo que puede tener ese número. Por último, pasas el nuevo valor mínimo con newMiny el nuevo máximo con newMax y la función te devolverá el nuevo valor en el nuevo rango.

Pongamos un ejemplo. Imagina que queremos calcular los grados (entre 0 grados y 360 grados como hemos dicho) de la manecilla de los minutos. Pongamos que son las 12:33, la llamada a esa función sería así:

linearMap(33, 0, 60, 0, 360);

El primer parámetro son los minutos, 33, min y max son 0 y 60 porque los minutos como mucho pueden ser 60 y el nuevo valor mínimo y el máximo es 0 y 360. En otras palabras, es una simple regla de 3 que uso para sacar los grados.

Sabiendo esto ya podemos crear la función para calcular la manecilla de las horas:

function calculateHourDegrees() {
  const currentHour = new Date().getHours() - 12;
  const angle = linearMap(currentHour, 0, 12, 0, 360);
  document.querySelector(".hours").style.transform = `rotate(${angle}deg)`;
}

Lo primero que hago es sacar la hora actual y le resto 12 (porque puede ir hasta 24 pero en un reloj analógico nos vale con 12).

Saco el ángulo con la función que he explicado antes y lo que hago es seleccionar con el querySelector el elemento del HTML con la línea de las horas para ponerle como estilo el transform con los grados.

Las otras funciones, la de los minutos y segundos es igual:

function calculateMinuteDegrees() {
  const currentMinutes = new Date().getMinutes();
  const angle = linearMap(currentMinutes, 0, 60, 0, 360);
  document.querySelector(".minutes").style.transform = `rotate(${angle}deg)`;
}

function calculateSeconds() {
  const currentMinutes = new Date().getSeconds();
  const angle = linearMap(currentMinutes, 0, 60, 0, 360);
  document.querySelector(".seconds").style.transform = `rotate(${angle}deg)`;
}

Con eso ya se calculan los grados del reloj cuando cargamos el HTML y el Javascript, pero falta algo, ir actualizando el reloj según cambia la hora. Para ello voy a envolver el calculo de los grados dentro de un setInterval:

(function () {
  setInterval(() => {
   calculateHourDegrees();
   calculateMinuteDegrees();
   calculateSeconds();
  }, 1000);
})();

El setInterval lo que va a hacer es llamar a las 3 funciones cada segundo (por eso pone 1000 porque son 1000 milisegundos). El reloj quedaría así:

En la imagen se aprecia un círculo negro con 3 manecillas

Por cierto, en el HTML, en cada línea, he ajustado el valor y1 para que cada manecilla mida distinto, como en los relojes analógicos. Esto va al gusto de cada uno.

Por último para dejarlo fino fino voy a meter dentro del CSS una transición de la propiedad transform de las manecillas de las horas y de los minutos para que cuando cambie el valor del ángulo el cambio no sea brusco.

.hours,
.minutes,
.seconds {
  transform-origin: center;
  stroke-linecap: round;
}

.hours {
  stroke: fuchsia;
  stroke-width: 3px; 
  transition: transform 1s ease-in-out;
}
.minutes {
  stroke-width: 2px; 
  stroke: lime;
  transition: transform 1s ease-in-out;
}
.seconds {
  stroke: white;
}

Pero esto no acaba aquí, como detalle final voy a pintar las típicas líneas para marcar las horas alrededor de las manecillas.

Ahora lo que voy a hacer es crear 12 líneas (una para señalar cada hora) dentro del SVG:

<line x1="60" y1="5" x2="60" y2="10" class="line" />
<line x1="60" y1="5" x2="60" y2="10" class="line" />
<line x1="60" y1="5" x2="60" y2="10" class="line" />
<line x1="60" y1="5" x2="60" y2="10" class="line" />
<line x1="60" y1="5" x2="60" y2="10" class="line" />
<line x1="60" y1="5" x2="60" y2="10" class="line" />
<line x1="60" y1="5" x2="60" y2="10" class="line" />
<line x1="60" y1="5" x2="60" y2="10" class="line" />
<line x1="60" y1="5" x2="60" y2="10" class="line" />
<line x1="60" y1="5" x2="60" y2="10" class="line" />
<line x1="60" y1="5" x2="60" y2="10" class="line" />
<line x1="60" y1="5" x2="60" y2="10" class="line" />

He ajustado el x e y de cada punto para que midan poquito y se dibujen cerca del borde. Ahora, como pasa con las manecillas hay que calcular los grados de cada una de las líneas para que se dibujen alrededor del círculo. Lo primero el CSS, parecido a las manecillas:

.line {
  stroke-width: 1px;
  stroke: white;
  stroke-linecap: round;
  transform-origin: center;
}

Y por último el Javascript. Antes de seguir leyendo piensa primero cómo lo harías e intenta hacerlo sin mirar cómo lo he hecho yo.

Yo lo que se me ha ocurrido es tener en una lista de objetos todas las líneas para recorrerla con bucle for e ir poniendo los ángulos a cada línea.

function calculateLines() {
  const lines = document.querySelectorAll(".line");
  const numberLines = lines.length;
  for (let i = 0; i < numberLines; i++) {
    const line = lines[i];
    const angle = linearMap(i, 0, numberLines, 0, 360);
    line.style.transform = `rotate(${angle}deg)`;
  }
}

Con querySelectorAll pillo en forma de lista todos los elementos del HTML con la clase “line”. Usando un bucle for recorro las líneas y con la función de linearMap que hemos creado antes calculo los grados para cada línea. Fíjate en el detalle que ahora el primer parámetro que paso es i, es decir, el número de esa línea, que va desde 0 al número de líneas que haya, así se reparten las líneas entre la circunferencia y se quedan a la misma distancia.

Lo bueno de hacerlo así es que si ahora decides que quieres más o menos líneas alrededor de la esfera simplemente tienes que añadir o quitar las líneas del HTML. Automáticamente se calculará su posición para que queden repartidas en el reloj.

Resultado final:

En la imagen se aprecia un círculo negro con 3 manecillas y líneas alrededor para cada 5 minutos

Demo y código fuente

https://codepen.io/Frostq/pen/XQNXpq

Deberes

Si quieres seguir practicando cosas con el reloj te propongo este par de ejercicios:

  • Añadir los números del reloj en su posición, es decir los números del 1 al 12. Para que quede mejor haz que los números 1, 3, 6 y 9 sean más grandes y el resto más pequeños.

  • Añade una esfera interna al reloj, en pequeño con las iniciales de los días de la semana: L, M, X, J, V, S y D. Añade otra manecilla que se mueva indicando el día de la semana actual.

Conclusiones

Este tipo de proyectos te recomiendo que primero los intentes hacer sin mirar el código que aparece aquí (puedes leer más o menos como lo planteo por encima) porque cuando lo haces por ti mismo y te sale sin mirar la solución te sientes muy bien.

Si lo has hecho mirando y copiando mi código no pasa nada, al principio este tipo de ejercicios suele costar, pero te recomiendo que vuelvas a intentar hacerlo sin mirar dentro de un tiempo.

También te digo que el código que yo explico puede que no sea el mejor o el más óptimo, simplemente es mi solución, seguramente haya otras mucho mejores.

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

Blog Bitix

Qué son los datos estructurados y para que sirven con ejemplos

mayo 02, 2021 07:00

Los datos estructurados son datos que describen los elementos relevantes que contiene la página, facilitan la tarea a los buscadores de analizar el contenido y extraer la información para su indexación y la aparición en las páginas de resultados. Incluir datos estructurados en cada página mejora el SEO y permite que en las páginas de resultados de los buscadores se muestre con un formato enriquecido que destaca sobre el resto de resultados.

HTML

Los buscadores rastrean la web en busca de páginas que una vez indexadas les permite mostrarlas en la página de resultados las más relevantes para las palabras clave introducidas al realizar la búsqueda.

Los archivos sitemap.xml permiten a los buscadores conocer todas páginas de las que se compone un sitio web. Los rastreadores los descargan cada cierto tiempo, de forma paulatina analizan los enlaces proporcionados en el sitemap.xml y los indexa para mostrarlos como resultados si es un contenido relevante para las búsquedas de los usuarios.

Mostrar los enlaces más relevantes de una búsqueda no es una tarea sencilla, el algoritmo de indexación y del motor de búsqueda han de conocer qué es lo que trata de buscar el usuario y han de conocer cúal es el contenido de cada página. Conocer el contenido de una página no es sencillo ya que las páginas están en formato HTML que ofrece poca ayuda a los buscadores de la información que contienen.

Contenido del artículo

Qué son los datos estructurados en una página web

Los buscadores hacen el mejor esfuerzo por entender el contenido de las páginas, los datos estructurados facilitan en gran medida el análisis del contenido. Los datos estructurados son un formato estandarizado que permite proporcionar de forma más precisa cuál es el contenido e información de una página. Para los buscadores obtener la información de la página es más sencillo y preciso obtener de los datos estructurados que analizando el texto del contenido HTML sin ninguna estructura.

Además, en las páginas de resultados los buscadores para las páginas que proporcionan datos estructurados son capaces de mostrar los resultados enriquecidos, por ejemplo, incluyendo una imagen, una descripción, una imagen o ciertos datos específicos del dato estructurado como ubicación o fecha.

Los datos estructurados son buenos para el SEO ya que los buscadores conocen mejor el contenido de la página. Por otro lado, los resultados enriquecidos destacan más sobre los que no son consiguiendo que los usuarios hagan más clics en la página de resultados y atrayendo más visitantes a un sitio web.

El siguiente es un ejemplo de contenido que contiene datos como un título o fecha pero que no utiliza ningún formato de datos estructurados.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<h1>Apple Spring Forward Event Live Blog</h1>
<p>Welcome to live coverage of the Apple Spring Forward …</p>
<h2>See the new flagship Apple Retail Store in West Lake, China.</h2>
<p>March 9, 2015 1:17 PM</p>
<img src="http://images.apple.com/live/2015-mar-event/images/908d2e_large_2x.jpg" />
<h2>iPhone is growing at nearly twice the rate of the rest of the smartphone market.</h2>
<p>March 9, 2015 1:13 PM</p>
<img src="http://images.apple.com/live/2015-mar-event/images/573cb_xlarge_2x.jpg"/>
<h2>Coming this April, HBO NOW will be available exclusively in the U.S. on Apple TV and the App Store.</h2>
<p>March 9, 2015 1:08PM</p>
<p>It's $14.99 a month.<br> And for a limited time, …</p>
no-structured-data.html

Formatos de datos estructurados

Hay varios formatos de datos estructurados, el formato recomendado por Google es utilizar JSON-LD.

JSON-LD

JSON for Linking Data o JSON-LD es un formato de datos estructurados que se especifica en formato JSON y se incluye en la página normalmente en la cabecera separada del contenido, también se puede incluir en el cuero de la página. La diferencia de este formato es que el contenido no está mezclado con los datos estructurados.

 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
<script type="application/ld+json">
  {
    "@context":"https://schema.org",
    "@type":"LiveBlogPosting",
    "@id":"http://techcrunch.com/2015/03/08/apple-watch-event-live-blog",
    "about":{
      "@type":"Event",
      "startDate":"2015-03-09T13:00:00-07:00",
      "name":"Apple Spring Forward Event"
    },
    "coverageStartTime":"2015-03-09T11:30:00-07:00",
    "coverageEndTime":"2015-03-09T16:00:00-07:00",
    "headline":"Apple Spring Forward Event Live Blog",
    "description":"Welcome to live coverage of the Apple Spring Forward …",
    "liveBlogUpdate":[
      {
        "@type":"BlogPosting",
        "headline":"Coming this April, HBO NOW will be available exclusively in the U.S. on Apple TV and the App Store.",
        "datePublished":"2015-03-09T13:08:00-07:00",
        "articleBody": "It's $14.99 a month.<br> And for a limited time, …"
      },
      {
        "@type":"BlogPosting",
        "headline":"iPhone is growing at nearly twice the rate of the rest of the smartphone market.",
        "datePublished":"2015-03-09T13:13:00-07:00",
        "image":"http://images.apple.com/live/2015-mar-event/images/573cb_xlarge_2x.jpg"
      },
      {
        "@type":"BlogPosting",
        "headline":"See the new flagship Apple Retail Store in West Lake, China.",
        "datePublished":"2015-03-09T13:17:00-07:00",
        "video":{
          "@type":"VideoObject",
          "thumbnail":"http://images.apple.com/live/2015-mar-event/images/908d2e_large_2x.jpg"
        }
      }
    ]
  }
</script>
json-ld.html

Microdatos

El formato HTML Microdata define nuevos atributos HTML para embeber datos simples legibles por computadoras en documentos HTML. Es similar a RDFa pero menos expresivo, simple de aprender y procesar pero no ofrece el mismo nivel para la internacionalización, por ello en su lugar se suele recomendar usar RDFa o JSON-LD.

 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
<div itemid="http://techcrunch.com/2015/03/08/apple-watch-event-live-blog" itemscope itemtype="https://schema.org/LiveBlogPosting">
  <div itemprop="about" itemscope itemtype="https://schema.org/Event">
    <span itemprop="startDate" content="2015-03-09T13:00:00-07:00">March 9, 2015 1:17 PM</span>
    <meta itemprop="name" content="Apple Spring Forward Event" />
  </div>
  <meta itemprop="coverageStartTime" content="2015-03-09T11:30:00-07:00" />
  <meta itemprop="coverageEndTime" content="2015-03-09T16:00:00-07:00" />
  <h1 itemprop="headline">Apple Spring Forward Event Live Blog</h1>
  <p itemprop="description">Welcome to live coverage of the Apple Spring Forward …</p>
  <div itemprop="liveBlogUpdate" itemscope itemtype="https://schema.org/BlogPosting">
    <h2 itemprop="headline">See the new flagship Apple Retail Store in West Lake, China.</h2>
    <p><span itemprop="datePublished" content="2015-03-09T13:17:00-07:00">March 9, 2015 1:17 PM</span></p>
    <div itemprop="video" itemscope itemtype="https://schema.org/VideoObject">
      <img itemprop="thumbnail" src="http://images.apple.com/live/2015-mar-event/images/908d2e_large_2x.jpg" />
    </div>
  </div>
  <div itemprop="liveBlogUpdate" itemscope itemtype="https://schema.org/BlogPosting">
    <h2 itemprop="headline">iPhone is growing at nearly twice the rate of the rest of the smartphone market.</h2>
    <p><span itemprop="datePublished" content="2015-03-09T13:13:00-07:00">March 9, 2015 1:13 PM</span></p>
    <img itemprop="image" src="http://images.apple.com/live/2015-mar-event/images/573cb_xlarge_2x.jpg"/>
  </div>
  <div itemprop="liveBlogUpdate" itemscope itemtype="https://schema.org/BlogPosting">
    <h2 itemprop="headline">Coming this April, HBO NOW will be available exclusively in the U.S. on Apple TV and the App Store.</h2>
    <p><span itemprop="datePublished" content="2015-03-09T13:08:00-07:00">March 9, 2015 1:08PM</span></p>
    <p itemprop="articleBody">It's $14.99 a month.<br> And for a limited time, …</p>
  </div>
</div>
microdata.html

RDFa

RDFa es una extensión de HTML que ayuda a marcar los datos de la página, embebiendo ciertos atributos en las etiquetas HTML.

 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
<div vocab="https://schema.org/" typeof="LiveBlogPosting" resource="http://techcrunch.com/2015/03/08/apple-watch-event-live-blog">
  <div property="about" typeof="Event">
    <span property="startDate" content="2015-03-09T13:00:00-07:00">March 9, 2015 1:17 PM</span>
    <meta property="name" content="Apple Spring Forward Event" />
  </div>
  <meta property="coverageStartTime" content="2015-03-09T11:30:00-07:00" />
  <meta property="coverageEndTime" content="2015-03-09T16:00:00-07:00" />
  <h1 property="headline">Apple Spring Forward Event Live Blog</h1>
  <p property="description">Welcome to live coverage of the Apple Spring Forward …</p>
  <div property="liveBlogUpdate" typeof="BlogPosting">
    <h2 property="headline">See the new flagship Apple Retail Store in West Lake, China.</h2>
    <p><span property="datePublished" content="2015-03-09T13:17:00-07:00">March 9, 2015 1:17 PM</span></p>
    <div property="video" typeof="VideoObject">
      <img property="thumbnail" src="http://images.apple.com/live/2015-mar-event/images/908d2e_large_2x.jpg" />
    </div>
  </div>
  <div property="liveBlogUpdate" typeof="BlogPosting">
    <h2 property="headline">iPhone is growing at nearly twice the rate of the rest of the smartphone market.</h2>
    <p><span property="datePublished" content="2015-03-09T13:13:00-07:00">March 9, 2015 1:13 PM</span></p>
    <img property="image" src="http://images.apple.com/live/2015-mar-event/images/573cb_xlarge_2x.jpg"/>
  </div>
  <div property="liveBlogUpdate" typeof="BlogPosting">
    <h2 property="headline">Coming this April, HBO NOW will be available exclusively in the U.S. on Apple TV and the App Store.</h2>
    <p><span property="datePublished" content="2015-03-09T13:08:00-07:00">March 9, 2015 1:08PM</span></p>
    <p property="articleBody">It's $14.99 a month.<br> And for a limited time, …</p>
  </div>
</div>
rdfa.html

Tipos de datos estructurados

Hay múltiples tipos de datos estructurados según el contenido de la página. Por ejemplo, si el contenido de una página trata sobre un producto un dato es la imagen del producto, su nombre y descripción, su precio o su valoración. En el caso de un evento, por ejemplo un evento deportivo o concierto, sus datos específicos son la ubicación en la que tiene lugar, su hora de comienzo y final, además de también los participantes en el evento una su descripción.

Algunos datos son compartidos por múltiples tipos de datos estructurados, como un nombre o una descripción otros son específicos según el tipo de datos estructurados y contenido de la página. También algunos datos estructurados son comunes a todas las páginas como el autor del contenido o la organización que lo publica.

En la página schema.org está documentados los tipos de datos estructurados y que datos tiene cada uno. Algunas propiedades son obligatorias otras son opcionales.

Algunos tipos de datos estructurados son:

  • Trabajos creativos: libro, película, música, receta, series de televisión, …
  • Objetos embebidos no de texto: objeto de audio, imagen, vídeo, …
  • Evento como un espectáculo deportivo o musical.
  • Organización, como empresas.
  • Persona
  • Lugares, negocios locales, restaurantes, comercios, museos, …
  • Productos, ofertas, …
  • Análisis de productos
  • Acciones

Ejemplo de datos estructurados

Hay múltiples formas de incluir los datos estructurados en una página web. Una de ellas es embebiendo en el HTML los datos estructurados añadiendo ciertos atributos a etiquetas HTML.

Para separar el contenido HTML de los datos estructurados se puede utilizar json-ld, es la forma que recomienda Google para incluir datos estructurados en una página. Los datos estructurados json-ld se suelen incluir en la cabecera de la página en formato JSON.

El el caso de mi blog en el que publico artículos el dato estructurado adecuado para cada publicación es BlogPosting. Este tipo de dato estructurado tiene un título del artículo, una imagen que represente el contenido del artículo, una descripción, fecha de publicación y fecha de última actualización entre otros datos.

 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
<!DOCTYPE html>
<html lang="es">
<head>

...

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "BlogPosting",
  "mainEntityOfPage": {
      "@type": "WebPage",
      "@id": "https://picodotdev.github.io/blog-bitix/2021/01/analitica-web-con-matomo-como-alternativa-a-google-analytics/"
  },
  "headline": "Analítica web con Matomo como alternativa a Google Analytics",
  "image": {
      "@type": "ImageObject",
      "url": "https://picodotdev.github.io/blog-bitix/assets/images/structured-data/matomo-750.png"
    },
  "datePublished": "2021-01-15T17:00:00+01:00",
  "dateModified": "2021-01-15T17:00:00+01:00",
  "inLanguage": "es",
  
  "wordCount": "1181",
  "license": "https://creativecommons.org/licenses/by-sa/4.0/",
  "author": {
      "@type": "Person",
      "name": "picodotdev",
      "description": "Ingeniero de software. I ♥ Java, GNU/Linux and libre software.",
      "url": "https://twitter.com/picodotdev/"
  },
  "publisher": {
      "@type": "Organization",
      "name": "Blog Bitix",
      "logo": {
        "@type": "ImageObject",
        "url": "https://picodotdev.github.io/blog-bitix/assets/images/structured-data/blogbitix-750.png"
      }
  },
  "description": "Matomo es una alternativa a Google Analytics con funciones similares que cubren las necesidades de la mayoría de sitios web. Es software libre con algunas funciones <em>premium</em> que requieren comprar una licencia anual de uso. Matomo se puede hospedar <em>on-premise</em> que requiere administrar esa infraestructura o en la nube ofrecida por la propia Matomo. En el artículo muestro en un ejemplo como empezar a usar Matomo en un sitio web con Docker."
}
</script>

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "Organization",
  "name": "Blog Bitix",
  "description": "Blog sobre al lenguaje de programación Java y la distribución GNU/Linux que uso habitualmente, Arch Linux, lo que aprendo sobre el software libre, la programación web y otros temas relacionados con la tecnología y la informática. El contenido puede contener trazas de asuntos fuera de tema.",
  "url": "https://picodotdev.github.io/blog-bitix/",
  "logo": {
      "@type": "ImageObject",
      "url": "https://picodotdev.github.io/blog-bitix/assets/images/structured-data/blogbitix-750.png"
  }
}
</script>

...

</head>
<body>
  ...
</body>
</html>
json-ld-blogbitix.html

Herramienta para validar los datos estructurados

Una vez incluidos los datos estructurados es recomendable validarlos, esto permite conocer con exactitud qué está extrayendo un buscador. Google ofrece una herramienta de prueba de datos estructurados, basta con proporcionar la URL de la página y en el resultado se muestran los distintos tipos de datos estructurados que ha extraído de la página y sus propiedades. Para uno de los artículos del blog, Analítica web con Matomo como alternativa a Google Analytics, la herramienta de análisis de Google muestra como resultado tipos de datos estructurados que reconoce que están incluídos en la cabecera de la página.

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

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

Preload del OPCache en PHP

mayo 02, 2021 05:29

Sigo profundizando en el rendimiento de WordPress y también de tu web. En esta ocasión hablaré de las mejoras en cuando al Zend Opcache que si bien se introdujeron en PHP 7.4, no han empezado a despertar el interés hasta el lanzamiento de PHP 8.

Opcache (php_opcache) es una vieja extensión introducida en PHP 5.5, aunque estaba disponible de manera separada desde el 5.3 creo recordar. Su misión es esencialmente cachear el código parseado/compilado de PHP en memoria. Ya sabéis que tanto si usamos JIT como si no, cada vez que se carga una página el motor de PHP lee de disco sus archivos, lo interpreta, carga sus include/require y finalmente la ejecuta. Ese proceso es lento y por eso Opcache suele producir bastantes beneficios.



Preload del OPCache en PHP

El inconveniente de Opcache es que para cada instancia que se lanza de PHP, ya sea esta vía CGI como FastCGI se debe regenerar el contenido de ese caché, lo cual lleva tiempo. Eso es lo que viene a solucionar el preload o preloading que mencionaba. La directiva preload le indica a Opcache qué archivo PHP debe ejecutar al cargarse. Para ello modificamos nuestro php.ini o el archivo de configuración de PHP que usemos para que contenga lo siguiente:

opcache.preload = "/home/htdocs/www/_opcache.preload.php"

Efectivamente /home/htdocs/www/_opcache.preload.php es la ruta física (del sistema de archivos del sistema) que contiene el archivo con los contenidos a precargar. Este ejemplo lo que indica son las clases de WordPress necesarias y que he obtenido de internet aplicándole algunas mejoras:

declare(strict_types=1);
$wp_dir = dirname(__FILE__) . '/';
$preload_patterns =
[
	$wp_dir . 'wp-includes/Text/Diff/Renderer.php',
	$wp_dir . 'wp-includes/Text/Diff/Renderer/inline.php',
	$wp_dir . 'wp-includes/SimplePie/**/*.php',
	$wp_dir . 'wp-includes/SimplePie/*.php',
	$wp_dir . 'wp-includes/Requests/**/*.php',
	$wp_dir . 'wp-includes/Requests/*.php',
	$wp_dir . 'wp-includes/**/class-*.php',
	$wp_dir . 'wp-includes/class-*.php',
];

$exclusions =
[
	$wp_dir . 'wp-includes/class-simplepie.php',
	$wp_dir . 'wp-includes/SimplePie/File.php',
	$wp_dir . 'wp-includes/SimplePie/Core.php',
	$wp_dir . 'wp-includes/class-wp-simplepie-file.php',
	$wp_dir . 'wp-includes/class-snoopy.php',
	$wp_dir . 'wp-includes/class-json.php',
];

foreach ($preload_patterns as $pattern)
{
	$files = glob($pattern);
	foreach ($files as $file)
	{
		if (!in_array($file, $exclusions, true))
		{
			opcache_compile_file($file);
		}
	}
}



Preload del OPCache en PHP

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

Blog Bitix

Guía de instalación y uso básico de FreeBSD

abril 30, 2021 02:30

Aún con su reducida cuota de uso las distribuciones GNU/Linux son conocidas por muchas personas como alternativa a los sistemas operativos comerciales Windows de Microsoft y macOS de Apple para propósitos de entorno de escritorio. Las distribuciones BSD también son conocidas, cualquier usuario de GNU/Linux con seguridad las conoce. FreeBSD es una abanderada de las BSD, aún así no son tantos los usuarios que deciden instalarla como su sistema operativo de uso cotidiano. Es fácil y rápido de instalar y a un usuario de GNU/Linux e incluso macOS el cambio al nuevo sistema resulta conocido ya que el entorno de escritorio y muchos comandos son exactamente los mismos.

FreeBSD

La cuota de uso entre los diferentes sistemas operativos para computadoras de escritorio está dominada con más de un 80% por el sistema operativo Windows de Microsoft, un sistema operativo comercial con una licencia de uso privativo dirigido a ser fácil de usar incluso para usuarios sin ser expertos en informática. El éxito de Windows se debe a que es la opción preinstalada por la mayoría de ordenadores y portátiles a la venta, posee el paquete ofimático Office también de Microsoft imprescindible en muchos puestos de trabajo, se puede usar sin licencia con algunas limitaciones o se puede comprar una licencia de Windows 10 completamente válida a un precio significativamente más reducido que el oficial.

El siguiente sistema operativo de escritorio más usado es macOS de Apple, un sistema operativo comercial con licencia privativa exclusivo de las computadoras Mac. Los Mac se consideran ordenadores que suelen incorporar las últimas tecnologías y cuidando más diseño que las que se encuentran en ordenadores con Windows, sin embargo, la exclusividad se ve reflejada en un significativo precio comparado con PC de características equivalentes. A pesar del precio son computadoras con cierta popularidad, deseadas y vendidas.

La tercera opción son alguna de las distribuciones de GNU/Linux siendo una de las más populares Ubuntu. Las distribuciones y sistema operativo GNU/Linux se caracterizan por tener una licencia de software libre basada en la GPL y ser generalmente gratuitas incluyendo la práctica totalidad de los programas. Las distribuciones GNU/Linux actualmente son tan fáciles de instalar y usar que los sistemas operativos Windows o macOS, incluyendo ser compatible con la mayoría del hardware. Sin embargo, dado que no hay tantas empresas que vendan y distribuyan equipos con algún GNU/Linux preinstalado no tiene en el escritorio una cuota tan alta como las anteriores, dos empresas que distribuyen GNU/Linux en sus equipos son Slimbook y Vant. En el área de los servidores y computación en la nube, por el contrario, GNU/Linux sí es la opción que domina el mercado, por su licencia, flexibilidad, fiabilidad y potencia.

La cuarta opción mucho menos conocida y usada son alguna de las distribuciones BSD. Las distribuciones BSD también tienen una licencia de software libre incluso más permisiva que la licencia GPL. La mayor permisividad de las licencias BSD la hace atractiva para algunas empresas, que al contrario de la licencia GPL con la licencia BSD no están obligadas a distribuir el código fuente de los programas lo que les permite proteger sus desarrollos de competidores. Es utilizada por empresas como Netflix, Sony en las consolas PlayStation e incluso macOS está basado en partes de BSD. Aunque las licencias BSD permiten usar el software sin obligar a colaborar en el desarrollo de su software se ven beneficiadas por colaboraciones puntuales dado que las empresas están interesadas en mejorar el software en el basan su negocio.

Contenido del artículo

La distribución FreeBSD

Entre las distribuciones BSD una popular es FreeBSD, que es posible utilizar con propósitos de computadora de escritorio, su uso también está destinado a software de servidor que es conocida por su pila TCP/IP de gran rendimiento para comunicación por red.

El mérito de las distribuciones BSD como FreeBSD es ciertamente notable, aunque no tienen la popularidad ni el apoyo por parte de las empresas ni disponer del mismo número de desarrolladores dedicado a su mejora de las distribuciones GNU/Linux consigue proporcionar un sistema operativo de gran calidad con funcionalidades equivalentes a las existentes GNU/Linux o incluso más innovadoras con un modelo de desarrollo diferente de GNU/Linux.

Es perfectamente capaz de realizar las tareas comunes con el propósito de ordenador de escritorio. Posee programas de navegadores web, multimedia como vídeo y audio, ofimática, visor de documentos e imágenes y una colección formada por más de 36000 paquetes de software compatibles. Otras funciones de software que posee son virtualización, Jails para crear procesos separados del resto del sistema que es la base de los contenedores de Docker, DTrace también desarrollada originalmente por Sun Microsystems, WINE para ejecutar programas de Windows y la posibilidad de agregar compatibilidad binaria con Linux lo que hace posible utilizar programas cuando no están disponibles de forma nativa.

La mayor dificultad de usar FreeBSD es en que sea compatible con todo el hardware de la computadora, si bien la compatibilidad con el hardware en GNU/Linux actualmente no es un problema en FreeBSD dado el mayor limitado de desarrolladores que tiene el interés de las compañía en ofrecer soporte para su hardware puede presentar algún problema de compatibilidad.

Las novedades de destacadas de FreeBSD 13 publicada en abril de 2021 es el soporte de la arquitectura de procesadores arm64 al mismo nivel que la arquitectura de procesadores amd64, actualización de paquetes de compiladores, eliminación de algunos programas obsoletos de GNU, soporte en el kernel de TLS y otras mejoras de menor relevancia.

FreeBSD Beastie

Logotipo y mascota de FreeBSD

El sistema de archivos ZFS, ¿qué lo hace diferente?

Una de las opciones como sistema de archivos es la posibilidad de utilizar ZFS. La licencia BSD permite utilizar más fácilmente el avanzado sistema de archivos ZFS desarrollado originalmente por la difunta Sun Microsystems.

Lo que hace diferente a ZFS es que combina el rol de gestor de volúmenes con el rol de sistema de archivos. El sistema de archivos ZFS es consciente de la estructura subyacente de discos. Al contrario que los sistemas de archivos tradicionales que solo pueden crearse en un único disco de almacenamiento, esto obliga a que si hay dos discos sea necesario crear dos sistemas de archivos diferentes.

La combinación de ZFS como gestor de volúmenes y sistema de archivos permite la creación de varios sistemas de archivos todos compartiendo un conjunto de almacenamiento disponible. Una de las mayores ventajas de ZFS de la disposición física de los discos es que los sistemas de archivos existentes pueden ser agrandados automáticamente al añadir discos adicionales al conjunto. Este nuevo espacio queda disponible para todos los sistemas de archivos. También tiene propiedades que pueden ser aplicadas a cada sistema de archivos en vez de crear un único sistema de archivos monolítico.

OpenZFS

OpenZFS

Guía de instalación

El primer paso de la instalación es descargar la última de las imágenes de medio de instalación disponibles, ya sea la versión de menor tamaño para realizar la instalación por red o la más completa sin necesidad de descargar nada adicionalmente desde la página de descargas de FreeBSD. En caso de duda en la instalación tiene disponible un manual completo de la instalación y uso o como documentación de referencia.

En este caso como primera toma de contacto con FreeBSD realizo la instalación en una máquina virtual con VirtualBox que está disponible también para Windows como macOS que permite probarla sin necesidad de eliminar el sistema existente en la computadora. En la definición de la máquina virtual se especifican las características de la máquina virtualizada desde el tamaño de memoria, almacenamiento de disco o tipo de BIOS, adicionalmente se proporciona la imagen del medio de instalación y se inserta en la unidad DVD virtual de la máquina.

El siguiente error de VirtualBox impide iniciar FreeBSD en modo UEFI, hasta que no sea resuelto requiere iniciar el sistema como BIOS, para la prueba el tipo de sistema BIOS o UEFI no tiene relevancia.

Configuración de máquina virtual con VirtualBox

Configuración de máquina virtual con VirtualBox

La instalación de FreeBSD utiliza un asistente que guía y hace la instalación sencilla, rápida y fiable. Descargado el medio de instalación e iniciado el sistema desde él se presenta un menú de opciones que permiten iniciar la instalación. En los diferentes pasos del asistente se van introduciendo las preferencias de configuración desde la disposición del teclado, particionado del sistema de almacenamiento, copiado de archivos del sistema base, establecimiento de contraseña del usuario root, configuración de red, zona horaria y usuarios adicionales.

Inicio de la instalación.

Inicio de la instalación de FreeBSD Inicio de la instalación de FreeBSD Inicio de la instalación de FreeBSD

Inicio de la instalación de FreeBSD Inicio de la instalación de FreeBSD Inicio de la instalación de FreeBSD

Inicio de la instalación de FreeBSD Inicio de la instalación de FreeBSD Inicio de la instalación de FreeBSD

Inicio de la instalación de FreeBSD Inicio de la instalación de FreeBSD Inicio de la instalación de FreeBSD

Inicio de la instalación de FreeBSD

Inicio de la instalación de FreeBSD

El siguiente paso es automático, consiste en la copia de los archivos base del sistema.

Copia de archivos base de FreeBSD Copia de archivos base de FreeBSD Copia de archivos base de FreeBSD

Copia de archivos base de FreeBSD Copia de archivos base de FreeBSD Copia de archivos base de FreeBSD

Copia de archivos base de FreeBSD Copia de archivos base de FreeBSD

Copia de archivos base de FreeBSD

A continuación se sigue con la configuración básica del sistema para la conectividad de red, usuarios, fecha y servicios demonio.

Configuración de FreeBSD Configuración de FreeBSD Configuración de FreeBSD

Configuración de FreeBSD Configuración de FreeBSD Configuración de FreeBSD

Configuración de FreeBSD Configuración de FreeBSD Configuración de FreeBSD

Configuración de FreeBSD Configuración de FreeBSD Configuración de FreeBSD

Configuración de FreeBSD

Configuración de FreeBSD

Se ha de establecer la contraseña del usuario root que otorga permisos de superusuario. También se da la oportunidad de crear los usuarios en el sistema.

Contraseña de superusuario en FreeBSD Creación de usuarios en FreeBSD Creación de usuarios en FreeBSD

Contraseña de superusuario y creación de usuarios en FreeBSD

Las últimas pantalla indican la finalización de la instalación.

Finalización de la instalación de FreeBSD Finalización de la instalación de FreeBSD Finalización de la instalación de FreeBSD

Finalización de la instalación de FreeBSD

Primer inicio en FreeBSD

Completada la instalación al reiniciar el sistema se presenta la pantalla del cargador de arranque y posteriormente la de inicio de sesión en modo texto a partir de la cual es posible instalar programas adicionales y un entorno de escritorio con interfaz gráfica.

Inicio de sesión en modo texto de FreeBSD Inicio de sesión en modo texto de FreeBSD Inicio de sesión en modo texto de FreeBSD

Instalación de entorno de escritorio

La instalación del entorno de escritorio requiere instalar el servidor gráfico y el entorno de escritorio deseado. Los entornos de escritorio disponibles son los mismos que están disponibles en GNU/Linux entre ellos GNOME, KDE y XFCE con lo que la experiencia de usuario es en gran medida la misma que en una distribución GNU/Linux, la mayor diferencia es que las versión del entorno de escritorio de FreeBSD disponible sea la versión anterior o tarde más tiempo en estar disponible desde su publicación.

A partir de la consola de inicio de sesión en modo texto hay que instalar los paquete del servidor gráfico Xorg, el paquete del entorno de escritorio deseado y cambiar un archivo de configuración si se desea iniciar el entorno de escritorio al inicio del sistema.

1
2
3
# pkg install xorg
# pw groupmod video -m freebsd || pw groupmod wheel -m freebsd
# pkg install gnome3
pkg-gnome.sh

Para iniciar el gestor de sesión GNOME en el inicio del sistema hay que cambiar la configuración en los archivos /etc/rc.conf y ~/.xinitrc.

1
2
3
4
dbus_enable="YES"
gdm_enable="YES"
gdm_lang="es_ES.UTF-8"
gnome_enable="YES"
rc-gnome.conf
1
2
exec /usr/local/bin/gnome-session

xinitrc.conf

Para establecer como idioma el español se requiere añadir la siguiente configuración en el archivo /usr/local/etc/gdm/locale.conf.

1
2
3
LANG="es_ES.UTF-8"
LC_CTYPE="es_ES.UTF-8"
LC_MESSAGES="es_ES.UTF-8"
locale.conf

GNOME en FreeBSD GNOME en FreeBSD GNOME en FreeBSD

GNOME en FreeBSD

Uso básico

FreeBSD proporciona una colección de programas básicos de línea de comandos incorporados en el sistema, al contrario que en GNU/Linux estos programas están desarrollados por los mismos desarrolladores del núcleo del sistema operativo y se actualizan como una unidad en cada versión en vez de individualmente.

Instalado el sistema dos tareas básicas son la instalación de programas adicionales y la actualización del sistema para obtener nuevas versiones de los programas, correcciones de errores y actualizaciones de seguridad.

Comando uname en FreeBSD Comando df en FreeBSD

Comandos uname y df en FreeBSD

Obtener permisos de superusuario root

Por seguridad algunas tareas administrativas y de edición de archivos de configuración requieren permisos de superusuario root. Esto es posible iniciando sesión en el sistema como el usuario root o obteniendo los privilegios de superusuario con el programa su o sudo.

Hay un único superusuario en el sistema cuyo nombre de usuario es root, este usuario tiene permisos para realizar cualquier acción en el sistema. La contraseña es necesaria para iniciar sesión, es la proporcionada en la instalación del sistema, y se solicita al obtener privilegios de superusuario en la línea de comandos con el comando su. El resto de usuarios distintos a root son usuarios regulares, para que un usuario regular obtenga privilegios de supersusaurio se ha de utilizar el comando su pertenecer al grupo wheel.

1
2
# pw groupmod whell -M freebsd

pw-add-user-to-wheel.sh
1
2
$ su -
#
su.sh

Obtener privilegios de superusuario

Obtener privilegios de superusuario

Instalación de paquetes

La finalidad de cualquier sistema operativo es permitir realizar tareas productivas en él a través de los programas. Para usar un programa es necesario instalarlo previamente en el sistema.

FreeBSD diferencia los programas de dos formas en como están distribuidos, los paquetes con binarios precompilados para su fácil y rápida instalación y los ports que requieren la compilación a partir del código fuente. En este sentido los paquetes de de FreeBSD son similares a los de los repositorios oficiales Arch Linux y los ports al repositorio AUR que requieren igualmente ser compilados a partir del código fuente.

La instalación de un paquete se realiza con el comando pkg para buscar su nombre e instalarlo.

1
2
3
4
5
6
# pkg search gnome
# pkg search firefox
# pkg search libreoffice
# pkg search gimp
# pkg search vlc
# pkg search vim
pkg-search.sh
1
2
# pkg install libreoffice

pkg-install.sh

Actualización del sistema

Una vez realizada la instalación en el futuro se publicarán nuevas versiones de los programas. Para mantener el sistema actualizado hay que ejecutar de forma periódica un comando de actualización.

La actualización de parches de seguridad de FreeBSD se realiza con los siguientes dos comandos. El sistema base del sistema operativo de FreeBSD se actualiza independientemente de los programas instalados como paquetes.

1
2
# freebsd-update fetch
# freebsd-update install
freebsd-update.sh

El siguiente comando permite revertir la actualización en caso de algún error.

1
2
# freebsd-update rollback

freebsd-update-rollback.sh

Para actualizar a versiones mayores se realiza con el siguiente comando en el que se indica la versión a la que actualizar.

1
2
# freebsd-update -r 13.0-RELEASE upgrade

freebsd-update-upgrade.sh

Los paquetes se actualizan independientemente del sistema base de FreeBSD con el siguiente comando.

1
2
# pkg upgrade

pkg-upgrade.sh

En caso de una actualización a una versión mayor de FreeBSD se requiere una reinstalación de todos los paquetes y ports con los siguientes comandos.

1
2
3
# pkg-static upgrade -f
# portmaster -af
# freebsd-update install
freebsd-pkg-upgrade.sh

Obtener más ayuda

La cuota de uso de GNU/Linux no es muy grande en el escritorio pero tiene un grupo de usuarios muy activo que comparte gran cantidad de información, es difícil no encontrar una respuesta a una duda o problema y es fácil obtener respuesta a una pregunta.

El grupo de usuario de FreeBSD es más reducido y por tanto encontrar respuestas a algo concreto no muy común es más difícil, aún siendo un grupo de usuarios más reducido se caracteriza por recibir calurosamente a los nuevos usuarios de FreeBSD. Una buena forma de obtener respuestas y soporte son los foros de usuario y las listas de distribución. Aunque no hay tantos canales de YouTube y artículos en blogs es posible encontrar información sobre FreeBSD a través de los buscadores.

Libros

También hay algunos libros dedicados en exclusiva a FreeBSD como Absolute Freebsd: The Complete Guide To FreeBSD, Design and Implementation of the FreeBSD Operating System, FreeBSD Device Drivers: A Guide for the Intrepid, FreeBSD Mastery: ZFS y FreeBSD Mastery: Advanced ZFS.

Eso es todo lo básico para empezar a usar FreeBSD, si alguién lee este artículo y usa FreeBSD u otra distribución BSD como sistema principal o en el trabajo me encantaría conocer más detalles así que si quieres puedes dejar un comentario, también si a alguien que acceda al artículo y lo lea seguro que le resulta interesante como forma de animarse a probar este sistemas operativo de la familia UNIX.

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

Picando Código

Siete días en el Picandoverso – Abril 4: No Control

abril 28, 2021 10:00

Es la primera vez desde que empecé esta serie de posts de “Siete días” en que no hay otros posts entre medio de uno y el siguiente. Pero esa era la idea original, que me forzara a escribir al menos un post a la semana con este resumen. Y este mes se cumplió con la edición número 14, ¡catorce semanas de repasos! Vengo con bastantes proyectos en el trabajo y de a poco volviendo a socializar más en el MundoReal™. De a poco van abriendo más cosas en Escocia y he vuelto a ver más amigos, así que por ese lado contento de poder ir volviendo a una vida social más normal. Pero igual tuve algo de tiempo para juntar algunos enlaces interesantes para comentar por acá. Van:

Siete días en el Picandoverso - Abril 4: No Control

Ruby

💎 Mañana jueves 29 de abril es el meetup online The Ruby Galaxy a las 19:00 UTC y se transmite a través de Twitch. La información completa de las charlas y oradores está en rubygalaxy.io. A nivel general, las charlas de este mes incluyen una sobre automatización con GitHub Actions, JSON Web Tokens y ViewComponents. Ahí estaremos.

💎 En este post escrito por Sylwia Vargas se hace un repaso de los clientes HTTP disponibles para Ruby en 2021. Muestra ejemplos de código para pedidos GET y POST de cada una de las herramientas y al final las compara en base a distintas medidas. Para los pedidos HTTP usa como ejemplo la API de Dad Jokes, lo que me hizo acordar a este alias que agregué hace poco en mi sistema, y que comparto y recomiendo:

alias dadjoke=’curl -H “Accept: text/plain” https://icanhazdadjoke.com/; echo’

Tecnología

🗜 Dejo esto acá para terminar de leerlo en algún momento, y creo que a más gente le puede interesar también. Shrink, Reduce, and Implode: The Legacy Zip Compression Methods describe e implementa los métodos de compresión. También enlaza a un artículo anterior con bastante detalle sobre la compresión Zip que también quiero leer… Zip Files: History, Explanation and Implementation

🐧 Una lista con 10 distribuciones Linux para principiantes en 2021. Hacía mucho que no leía un artículo de este tipo, pero más o menos encontramos a los mismos sospechosos de siempre.

🧪 Una de las cosas más mencionadas sobre Elixir es el Gen Server. En este post Alex Reichert explica de qué se trata con ejemplos de código del MundoReal™.

📬 El cliente de correo de código abierto para Android K9 está buscando financiamiento. Para esto están usando Liberapay, una plataforma de donaciones recurrentes software libre manejada por volntarios. Ya llevan 700 € por mes, con la meta de llegar a 1.000.

🏢 ¿Ha muerto UML? Ernesto Garbarino escribe sobre el Unified Modelling Language y quién fue responsable de su asesinato.

Criptomonedas y Bitcoin

💰 En éstos días leí al menos dos artículos interesantes sobre Bitcoin y Criptomonedas. El primero es Bitcoin – the future of money or speculative bubble?. El segundo artículo refleja bastante bien lo que pienso del tema. Se trata de Cryptocurrency is an abject disaster y describe bastante bien todos los problemas que ha traído. Algunas citas del artículo traducidas al español:

  • La integridad y confianza de toda la industria del software ha decaído drásticamente debido a las criptomonedas
  • Cualquier tecnología que no sea una (presunta)  moneda y que incorpora blockchain de cualquier manera siempre funcionaría mejor sin ella.
  • De eso se tratan las criptomonedas: no tecnología novedosa, no empoderamiento, sino hacer plata.
  • No, las criptomonedas no son una divisa para nada: es un vehículo de inversión. Una herramienta para hacer más ricos a los más ricos. Y eso es decirlo bien; en realidad tiene mucho más en común con una estafa que con una inversión genuina. ¿Qué “valor” provee resolver problemas matemáticos falsos? Es todo mierda.
  • Tal vez tu criptomoneda es diferente. Pero mira: estás en muy mala compañía. Cuando sos la única persona honesta en la habitación, tal vez deberías estar en una habitación diferente. Es imposible confiar en tí.
  • Las Criptomonedas son uno de los peores inventos del siglo 21. Estoy avergonzado de compartir una industria con esta estafa explotativa. Ha fallado en ser una divisa útil, inventó una nueva clase de abuso en internet, enriquecido más a los ricos, desperdiciado asombrosas cantidades de electricidad, apurado el cambio climático, arruinado cientos de proyectos de otra forma prometedores, provisto un clima para que florezcan cientos de estafas, creado escasez y aumentos de precios para el hardware, e inyectado incentivos perversos en la tecnología en todos lados. Al carajo con las criptomonedas.

Con suerte algún día se terminará toda esta pavada…

Comics

🐴 Dark Horse anunció un cómic precuela de la nueva serie He-Man en Netflix, Masters of the Universe: Revelation. Todavía no hemos visto ningún adelanto, pero supongo que los personajes al menos tendrán un estilo similar al de la tapa del cómic.

💬 Hoy es día de cómics nuevos y tengo para ponerme al día: BRZRK #2, Beta Ray Bill #2 (me encantó el primer número, excelente) y algunos títulos más de la semana pasada y ésta.

Videojuegos

💪 Ya está disponible por Limited Run Games la versión física de NEOGEO POCKET COLOR SELECTION Vol.1. No es una edición limitada -están haciendo sólo distribución- así que supongo que habrá más formas de adquirir la versión física eventualmente.

🥳 Después de 2 años sin actualizaciones, Mario Party para Nintendo Switch recibió una actualización. La novedad principal es que ahora se puede jugar online 🙄

Películas/TV

🦕 ¡Vuelven los Picapiedras! Fox anunció “Bedrock”, una comedia animada para adultos secuela a la serie The Flintstones. La serie vuelve a la familia 20 años después de la original, con Pedro Picapiedra a punto de retirarse y Pebbles en sus 20 y pico de años embarcándose en su carrera. La serie también va a documentar el pasaje de la Edad de Piedra a la Edad de Bronze, y las dificultades de los habitantes de en esta evolución.

😱 Salió trailer de la próxima película de The Conjuring, de las pocas sagas de terror que sigo:
YouTube Video

🎥 Liz se está quedando sin oxígeno y sin tiempo, para sobrevivir debe buscar la forma de acordarse quién es. Oxygen, una película de Alexandre Aja con Mélanie Laurent que se estrena en Netflix el 12 de mayo y me resultó bastante interesante:

YouTube Video

📺 Se terminó The Falcon and the Winter Soldier (Flacón y Gualtersoldier). Disfruté muchísimo ir viendo cada nuevo capítulo viernes a viernes. Es una serie bien a lo películas del Universo Cinematográfico de Marvel. No le pedía más que eso, y eso fue lo que me brindó. Espero con ansias las próximas aventuras de Sam y Bucky. Hasta junio que empieza Loki no hay nada más para ver en lo que respecta al UCM en TV, pero se viene The Bad Batch en el universo Star Wars mientras tanto.

💀 Estos días miré la película de Mortal Kombat, y también me gustó mucho. Otra que me dió lo que esperaba: peleas, magia y violencia. Hasta Fatalities hubo, ¡espero las secuelas!

Picando Código

Como comenté al principio, he estado bastante ocupado y el tiempo que venía usando para escribir posts lo estoy usando en otras cosas. Pero será cuestión de ir adaptando nuevamente el tiempo de escritura a los cambios en la rutina. Veremos cómo me ajusto en estos tiempos tan caóticos y raros.

Otros 7 días en el Picandoverso:

El post Siete días en el Picandoverso – Abril 4: No Control fue publicado originalmente en Picando Código.

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

Variable not found

Syncfusion Blazor UI components library: un primer vistazo

abril 27, 2021 06:05

SyncfusionEn el mundo de las suites profesionales de componentes, seguro que todos habéis oído hablar de Syncfusion. Esta compañía lleva desde 2001 ofreciendo componentes y marcos de trabajo para todo tipo de entornos, con el fin de hacer la vida más sencilla a los desarrolladores: ASP.NET Core, ASP.NET MVC, Web Forms, Angular, React, Vue, Xamarin, Flutter, WinForms o WPF son sólo algunas tecnologías en las que tenemos a disposición sus soluciones.

Y claro, no podía faltar Blazor :) La biblioteca Syncfusion Blazor UI ofrece más de setenta componentes para Blazor Server y WebAssembly que cubren sobradamente las necesidades más habituales en la construcción de aplicaciones profesionales.

Aunque se trata de una solución comercial y las licencias tienen coste, la buena noticia es que existe una generosa licencia community gratuita, mediante la cual podemos tener acceso a todos los componentes siempre que seamos desarrolladores independientes o una empresa con menos de seis trabajadores e ingresemos anualmente menos 1 millón de dólares brutos.

En este post vamos a dar un primer vistazo a esta biblioteca, para tener una idea de su alcance y forma de uso.

Componentes incluidos en Blazor UI components library

Como podemos ver a continuación, la lista de componentes incluidos en esta biblioteca es impresionante: potentes rejillas de datos, diagramas para visualización de datos, controles de edición de formularios, layouts, herramientas de navegación, agendas y calendarios, diagramas, visualizadores y editores WYSIWYG de documentos o utilidades para generación al vuelo de documentos ofimáticos.

Los componentes principales son los siguientes:

Grids
  • DataGrid
  • Pivot Table
  • Tree Grid
Data Visualization
  • Charts
  • Barcode Generator
  • BulletChart
  • Circular Gauge
  • Diagram
  • HeatMap Chart
  • Kanban
  • Linear Gauge
  • Maps
  • Range Selector
  • Smith Chart
  • Sparkline Charts
  • Stock Chart
  • TreeMap
Editors
  • InPlace Editor
  • Rich Text Editor
  • Word Processor
Calendars
  • Scheduler
  • Calendar
  • DatePicker
  • DateRangePicker
  • DateTime Picker
  • Gantt Chart
  • TimePicker
Buttons
  • Button
  • Button Group
  • Chips
  • Dropdown Menu
  • Progress Button
  • Split Button
Inputs
  • Checkbox
  • Color Picker
  • File Upload
  • Input Mask
  • Numeric Textbox
  • Radio Button
  • Range Slider
  • TextBox
  • Toggle Switch Button
DropDowns
  • AutoComplete
  • ComboBox
  • Dropdown List
  • ListBox
  • MultiSelect Dropdown
Notifications
  • Progress Bar
  • Toast
  • Spinner
Layout
  • Card
  • Dashboard Layout
  • Dialog
  • ListView
  • Splitter
  • Tooltip
Navigation
  • Accordion
  • Context Menu
  • File Manager
  • MenuBar
  • Sidebar
  • Tabs
  • Toolbar
  • TreeView
Forms
  • Query Builder
Viewer
  • PDF Viewer
File Formats
  • DocIO
  • PDF
  • Presentation
  • XlsIO

Según indican en la documentación oficial, todos los componentes están afinados para conseguir el mejor rendimiento posible y trabajar con grandes volúmenes de datos. En particular, el componente DataGrid está diseñado para ofrecer un alto rendimiento incluso con millones de filas, gracias al uso de virtualización de filas y columnas.

¿Cómo probar Syncfusion Blazor UI components library?

Si queréis averiguar si esta suite de componentes os vale para vuestros proyectos, lo mejor que podéis hacer es probarla :) Para ello, tenéis dos opciones:

  • Descargar la free trial, una evaluación totalmente funcional del producto durante 30 días, tiempo suficiente para que podáis probarlo todo a conciencia.

  • O bien, si sois desarrolladores individuales o empresas con 5 o menos empleados, e ingresáis menos de 1 millón de dólares al año, usar la versión community, mediante la cual tendréis acceso a todos los productos de forma ilimitada y sin restricciones de uso (es decir, podéis usarlos en proyectos comerciales, aunque si tenéis dudas os recomiendo que leáis las FAQs o contactéis con ellos).

Dado que encajo bien en este último grupo, he podido completar el proceso de solicitud de la licencia muy rápidamente. Lo único que tenemos que hacer es visitar el sitio web de Syncfusion, pulsar el botón "Claim Free License" y registrarnos usando nuestra cuenta de LinkedIn o Xing.

Por cierto, algo que llama bastante la atención es que la licencia community no está limitada a los componentes Blazor: en realidad se trata de la licencia community de Essential Studio, por lo que tendremos acceso a los componentes de cualquiera de las tecnologías soportadas (Blazor, ASP.NET Core, JavaScript, Angular, etc.): ¡más de 1.600 controles! También podremos usar las bibliotecas de generación de documentos Word, Excel, PowerPoint y PDF, y a herramientas de visualización de informes.

Plantilla de creación de proyectos con componentes SyncfusionUna vez completado el registro, tenemos acceso a un dashboard desde el que podemos descargar el software y obtener las claves de las licencias de los productos que deseemos utilizar. Podemos descargar la suite completa u obtener los productos de forma individualizada, para ocupar sólo el espacio que vayamos a necesitar, así como, si lo deseamos, instalar la extensión para Visual Studio que proporcionará plantillas para la creación sencilla de proyectos con las referencias a componentes Syncfusion que nos interesen (aunque en realidad no es estrictamente necesaria).

Un ejemplo simple, paso a paso: entrada de datos con autocompletado

Poner en marcha estos componentes es muy sencillo; si ya hemos descargado e instalado el producto, en muy pocos minutos podemos tener funcionando un proyecto Blazor Server o WebAssembly con controles Syncfusion. Veamos paso a paso cómo hacerlo.

Partiendo de un proyecto Blazor estándar ya creado (es decir, creado sin utilizar las plantillas propias de Syncfusion), lo primero que debemos hacer es instalar el "core" de los componentes, distribuido en el paquete NuGet Syncfusion.Blazor.Core.

Tras ello, debemos añadir una referencia al tema visual que queramos utilizar en el proyecto en el encabezado <head> de la página contenedora de la aplicación Blazor (puede ser el archivo _Host.cshtml o index.html, dependiendo de si usamos Blazor Server o Web Assembly).

<head>
...
<link href="_content/Syncfusion.Blazor.Themes/bootstrap4.css" rel="stylesheet" />
</head>

En este caso hemos elegido el tema bootstrap4, aunque la biblioteca proporciona cinco temas prediseñados, con versiones claras y oscuras, y permite creación de temas personalizados.

Además, antes de que se nos olvide, justo en el arranque de la aplicación hay que inicializar la biblioteca usando la clave de licencia obtenida desde el dashboard de Syncfusion. Por ejemplo, podríamos hacerlo en el archivo Program.cs:

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

Este paso es importante, porque de lo contrario los componentes visuales aparecerán en la página con un mensaje indicando que es necesario registrar la licencia.

Asimismo, como es habitual, tendremos que registrar los servicios de la biblioteca en el inyector de dependencias. En Blazor Server, desde el interior del método ConfigureServices() de la clase Startup; en Blazor WebAssembly, en el método Main() de Program.cs:

services.AddSyncfusionBlazor();

Lo que hemos hecho hasta el momento es común a todos los componentes, por lo que tendremos que seguir estos pasos siempre. A continuación, daremos pasos ya específicos para el componente que queremos utilizar, que en este caso es la entrada de datos con autocompletado.

Un detalle muy interesante es que los controles para Blazor se distribuyen agrupados según funcionalidad en distintos paquetes NuGet. Es decir, no existe un paquete único con todos los componentes, sino que hay que instalarlos en nuestro proyecto de forma independiente, de forma que el peso de la aplicación sólo se verá afectado por lo que utilicemos realmente.

En la web de Syncfusion podemos encontrar una extensa documentación de cada uno de los componentes para Blazor. Por ejemplo, como en nuestro caso queremos utilizar el componente de edición con autocompletado, nos centraremos en su apartado concreto en la documentación.

En este documento veremos que el paquete Nuget a instalar es Syncfusion.Blazor.DropDowns. También se recomienda añadir la siguiente directiva en el archivo _Imports.razor del proyecto, para que los controles estén disponibles desde cualquier componente:

@using Syncfusion.Blazor.DropDowns

Ya por último, lo que nos queda es añadir al componente que nos interese una instancia de SfAutoComplete, el componente editor con autocompletado, y configurarla apropiadamente para lograr nuestros objetivos. Por ejemplo, con el siguiente código mostraremos en la página de inicio de la aplicación un selector de colores por nombre, en el que aprovechamos las capacidades de este control para personalizar su visualización mediante plantillas y así poder mostrar una interfaz más colorida:

Selector de color con control SfAutocomplete

El código es el siguiente:

@* Index.razor *@
@page "/"

<p>Selected color:
<span class="color" style="background-color: @selected"></span>
@(selected ?? "None")
</p>

<SfAutoComplete TValue="string" TItem="string"
Placeholder="Select color" AllowCustom="false"
DataSource="colors" @bind-Value="selected">
<AutoCompleteTemplates TItem="string">
<ItemTemplate>
<span class="color" style="background-color: @context;"></span>
@context
</ItemTemplate>
</AutoCompleteTemplates>
</SfAutoComplete>

@code {
string selected { get; set; }
string[] colors = {
"White", "Black", "Blue", "Green", "Red", "Yellow"
};
}
/* Index.razor.css */
.color {
display: inline-block;
vertical-align: middle;
width: 16px;
height: 16px;
border: 1px solid #333;
}

Obviamente hay controles más complejos y potentes que requieren mayor esfuerzo en su configuración y puesta en marcha, pero nunca comparable con el requerido si nosotros tuviéramos que implementar a mano las funcionalidades para lograr los mismos resultados.

Recapitulando

Blazor UI components es una suite de componentes bastante completa, bien documentada, y, como habéis visto en el ejemplo anterior, de uso bastante sencillo.

Si tenéis ocasión y pensáis que os encaja en vuestros proyectos, os recomiendo que le echéis un vistazo, y más aún si sois elegibles para la licencia community, que os permitirá usarla sin coste :)

Nota: si os da pereza descargar nada, podéis ver una demo live de los componentes en la web de la compañía.

Publicado en Variable not found.

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

Variable not found

Enlaces interesantes 441

abril 26, 2021 06:05

Enlaces interesantes

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

Por si te lo perdiste...

.NET Core / .NET

ASP.NET Core / ASP.NET / Blazor

Azure / Cloud

Conceptos / Patrones / Buenas prácticas

Data

    Web / HTML / CSS / Javascript

    Visual Studio / Complementos / Herramientas

    Xamarin

    Otros

    Publicado en Variable not found.

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

    Blog Bitix

    Crear de forma sencilla un cliente de un servicio REST o HTTP con Retrofit

    abril 23, 2021 07:30

    La implementación de un servicio REST o HTTP es solo una parte, el otro lado es crear un cliente de ese u otro servicio que permita invocarlo, proporcionar parámetros y obtener las respuestas. Con la librería Retrofit implementar un cliente de un servicio en Java es una tarea bastante sencilla sencilla que utiliza una simple interfaz a la que se le añaden varias anotaciones que le indican a Retrofit cómo construir una implementación a partir de la interfaz. El código que hace uso de la clase que implementa la interfaz del servicio con Retrofit no es diferente de usar una clase que implementa una interfaz.

    Java

    En el lenguaje de programación Java hay varias librerías que permiten hacer peticiones a un servicio que utilice el protocolo HTTP. Varias de las librerías más conocidas son OkHttp, Apache HttpComponents e incluso en el JDK en la versión 11 se ha incorporado un cliente HTTP que soporta HTTP/2.

    Estas librerías cumplen su función y ofrecen total flexibilidad en su uso, sin embargo, requieren hacer las peticiones HTTP de forma explícita lo que supone un código repetitivo y tedioso incluyendo hacer las conversiones de objetos a JSON y de JSON a objetos Java en las peticiones y respuestas.

    Contenido del artículo

    La librería Retrofit para crear un cliente de un servicio REST o HTTP

    Retrofit es una librería que simplifica en gran medida el construir clientes HTTP de una API REST o realizar un cliente de un servicio REST. Con Retrofit basta con crear una interfaz Java que represente el servicio y decorarla con las anotaciones que proporciona Retrofit. También es posible utilizar Retrofit para servicios implementados con GraphQL que aunque no están basados en REST si utilizan el protocolo HTTP.

    Retrofit utiliza como librería para realizar las peticiones OkHttp y es compatible con varias librerías para realizar las conversiones de datos de JSON a objetos y de objetos a JSON, entre ellas Jackson, Gson y JSON-B. También soporta realizar las peticiones de forma síncrona o asíncrona.

    Esta es una interfaz de Java que representa un sencillo servicio REST de una petición GET. Las anotaciones instruyen a Retrofit como a partir de esta interfaz crear el cliente del servicio REST, al proporcionar esta interfaz Retrofit devuelve una instancia de la interfaz que al invocar a los métodos internamente realiza las peticiones HTTP.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    
    package io.github.picodotdev.blogbitix.javaretrofit;
    
    import retrofit2.Call;
    import retrofit2.http.GET;
    import retrofit2.http.Header;
    import retrofit2.http.Path;
    import retrofit2.http.Query;
    
    public interface Service {
    
        @GET("/message/{name}")
        Call<String> message(@Header("Accept-Language") String acceptLanguage, @Path("name") String name, @Query("random") String random);
    }
    
    Service.java

    Al proporcionar a Retrofit la interfaz este crea una instancia que implementa la interfaz pero que internamente implementa el cliente HTTP del servicio. Aparte de la interfaz para obtener la instancia del servicio se ha de proporcionar la URL base donde se ubica el servicio asi como otros objetos relacionados como interceptores.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    
    public class Main implements CommandLineRunner {
    
        @Autowired
        private MeterRegistry registry;
    
        ...
    
        private Service buildService() {
            OkHttpClient client = new OkHttpClient.Builder()
                    .addNetworkInterceptor(buildLoggingInterceptor())
                    .eventListener(OkHttpMetricsEventListener.builder(registry, "okhttp.requests").build())
                    .build();
    
            Retrofit retrofit = new Retrofit.Builder()
                    .client(client)
                    .addConverterFactory(ScalarsConverterFactory.create())
                    .baseUrl("http://localhost:8080/").build();
    
            return retrofit.create(Service.class);
        }
    
        ...
    }
    Main-buildService.java

    Anotaciones de Retrofit

    Las anotaciones de Retrofit en la interfaz de Java describen el servicio como variables en el path de la URL, parámetros, para realizar conversiones a JSON o el método HTTP a invocar o cabeceras HTTP.

    • HTTP, GET, POST, PUT, PATCH, DELETE, OPTIONS y HEAD: estas anotaciones indican el método HTTP que se realiza.
    • Path, Query: la anotación Path sustituye una variable en el path de la URL por el valor del argumento anotado. La anotación Query añade un argumento en la query de la URL.
    • Headers, Header: la anotación Headers permite especificar una colección de cabeceras HTTP a incluir en la petición. La anotación Header añade una cabecera a partir del valor de un argumento en la firma del método.
    • Body: la anotación Body transforma el argumento como los datos a incluir como JSON en cuerpo de la petición utilizando la librería que implementa la conversión de objetos a JSON.

    Aplicar funcionalidades transversales con interceptores

    Algunas funcionalidades comunes al crear un cliente de un servicio REST son obtener trazas de las peticiones que se están realizando, realizar autenticación, generar métricas o trazabilidad con Sleuth. Estas son funcionalidades transversales a todos los métodos de la interfaz del servicio REST que se implementan usando interceptores.

    Un interceptor es una clase que implementa una interfaz de la librería OkHttp que es invocada al realizarse una petición HTTP. OkHttp soporta métricas añadiendo un EventListener al construir la instancia del cliente de OkHttp.

    OkHttp proporciona una implementación de interceptor que emite trazas cuando se realiza una petición útil para observar en el log qué peticiones se están realizando y que códigos de estado se están devolviendo. Esta es una implementación propia de un interceptor para emitir las trazas que se realizan con el cliente.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    
    public class Main implements CommandLineRunner {
    
        ...
    
        private Interceptor buildLoggingInterceptor() {
            return chain -> {
                Request request = chain.request();
    
                long t1 = System.nanoTime();
                System.out.println(String.format("Sending request %s on %s%n%s", request.url(), chain.connection(), request.headers()));
    
                Response response = chain.proceed(request);
    
                long t2 = System.nanoTime();
                System.out.println(String.format("Received response for %s in %.1fms%n%s", response.request().url(), (t2 - t1) / 1e6d, response.headers()));
    
                return response;
            };
        }
    
        ...
    }
    Main-interceptor.java

    Servicio de ejemplo con Retrofit

    Un controlador como el siguiente de un servicio REST definido con Spring Framework sencillo que únicamente devuelve un mensaje en función de los parámetros recibidos a través de una en la petición, una variable en el path de la petición y un parámetro en la query.

     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
    
    package io.github.picodotdev.blogbitix.javaretrofit;
    
    ...
    
    @RestController
    public class RestService {
    
        private static final Map<String, String> MESSSAGES;
    
        static {
            MESSSAGES = new HashMap<>();
            MESSSAGES.put("es-ES;default", "¡Hola mundo!");
            MESSSAGES.put("es-ES;hello", "¡Hola %s!");
            MESSSAGES.put("en-GB;default", "Hello World!");
            MESSSAGES.put("en-GB;hello", "Hello %s");
        }
    
        @GetMapping(path = { "/message/", "/message/{name}" })
        public String message(@RequestHeader(value = "Accept-Language", defaultValue = "en-GB") String locale, @PathVariable(required = false) String name, @RequestParam(name = "random", required = false) String random) {
            System.out.printf("Random: %s%n", random);
            String message = "";
            if (name == null || name.isBlank()) {
                String key = String.format("%s;default", locale);
                message = MESSSAGES.getOrDefault(key, MESSSAGES.get("en-GB;default"));
            } else {
                String key = String.format("%s;hello", locale);
                String value = MESSSAGES.getOrDefault(key, MESSSAGES.get("en-GB;default"));
                message = String.format(value, name);
            }
            return message;
        }
    }
    
    RestService.java

    El cliente del servicio construido por Retrofit se realiza a partir de la definición de la interfaz, el cliente es un objeto que implementa esa interfaz y en código Java no de su uso es simplemente invocar sus métodos y proporcionar los parámetros. La implementación del cliente contiene el código necesario para transformar las invocaciones de los métodos de la interfaz en peticiones al servicio REST.

     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
    
    package io.github.picodotdev.blogbitix.javaretrofit;
    
    ...
    
    @SpringBootApplication
    public class Main implements CommandLineRunner {
    
        ...
    
        @Override
        public void run(String... args) throws Exception {
            Service service = buildService();
    
            String r1 = service.message("es-ES", "", UUID.randomUUID().toString()).execute().body();
            String r2 = service.message("es-ES", "Java", UUID.randomUUID().toString()).execute().body();
            String r3 = service.message("en-GB", "", UUID.randomUUID().toString()).execute().body();
            String r4 = service.message("en-GB", "Java", UUID.randomUUID().toString()).execute().body();
    
            System.out.printf("Result: %s%n", r1);
            System.out.printf("Result: %s%n", r2);
            System.out.printf("Result: %s%n", r3);
            System.out.printf("Result: %s%n", r4);
        }
    
        ...
    }
    
    Main.java

    Esta es la salida del programa en la consola donde se ven las trazas del interceptor de OkHttp con los datos de la petición y las respuesta del servicio junto con el mensaje de respuesta del servicio.

     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
    
    Sending request http://localhost:8080/message/?random=520983c7-79d9-4956-aceb-b0dad5c8902c on Connection{localhost:8080, proxy=DIRECT hostAddress=localhost/127.0.0.1:8080 cipherSuite=none protocol=http/1.1}
    Accept-Language: es-ES
    Host: localhost:8080
    Connection: Keep-Alive
    Accept-Encoding: gzip
    User-Agent: okhttp/3.14.9
    
    Random: 520983c7-79d9-4956-aceb-b0dad5c8902c
    Received response for http://localhost:8080/message/?random=520983c7-79d9-4956-aceb-b0dad5c8902c in 94,6ms
    Content-Type: text/plain;charset=UTF-8
    Content-Length: 13
    Date: Fri, 23 Apr 2021 17:46:41 GMT
    Keep-Alive: timeout=60
    Connection: keep-alive
    
    Sending request http://localhost:8080/message/Java?random=d4cca45d-4a45-40ca-9872-fc2c344f1572 on Connection{localhost:8080, proxy=DIRECT hostAddress=localhost/127.0.0.1:8080 cipherSuite=none protocol=http/1.1}
    Accept-Language: es-ES
    Host: localhost:8080
    Connection: Keep-Alive
    Accept-Encoding: gzip
    User-Agent: okhttp/3.14.9
    
    Random: d4cca45d-4a45-40ca-9872-fc2c344f1572
    Received response for http://localhost:8080/message/Java?random=d4cca45d-4a45-40ca-9872-fc2c344f1572 in 3,7ms
    Content-Type: text/plain;charset=UTF-8
    Content-Length: 12
    Date: Fri, 23 Apr 2021 17:46:41 GMT
    Keep-Alive: timeout=60
    Connection: keep-alive
    
    Sending request http://localhost:8080/message/?random=e802c2e7-9f5c-4908-8fe6-22b3c8069192 on Connection{localhost:8080, proxy=DIRECT hostAddress=localhost/127.0.0.1:8080 cipherSuite=none protocol=http/1.1}
    Accept-Language: en-GB
    Host: localhost:8080
    Connection: Keep-Alive
    Accept-Encoding: gzip
    User-Agent: okhttp/3.14.9
    
    Random: e802c2e7-9f5c-4908-8fe6-22b3c8069192
    Received response for http://localhost:8080/message/?random=e802c2e7-9f5c-4908-8fe6-22b3c8069192 in 2,2ms
    Content-Type: text/plain;charset=UTF-8
    Content-Length: 12
    Date: Fri, 23 Apr 2021 17:46:41 GMT
    Keep-Alive: timeout=60
    Connection: keep-alive
    
    Sending request http://localhost:8080/message/Java?random=16fc8a5f-b9ab-4b26-8049-81a4e7901820 on Connection{localhost:8080, proxy=DIRECT hostAddress=localhost/127.0.0.1:8080 cipherSuite=none protocol=http/1.1}
    Accept-Language: en-GB
    Host: localhost:8080
    Connection: Keep-Alive
    Accept-Encoding: gzip
    User-Agent: okhttp/3.14.9
    
    Random: 16fc8a5f-b9ab-4b26-8049-81a4e7901820
    Received response for http://localhost:8080/message/Java?random=16fc8a5f-b9ab-4b26-8049-81a4e7901820 in 2,7ms
    Content-Type: text/plain;charset=UTF-8
    Content-Length: 10
    Date: Fri, 23 Apr 2021 17:46:41 GMT
    Keep-Alive: timeout=60
    Connection: keep-alive
    
    Result: ¡Hola mundo!
    Result: ¡Hola Java!
    Result: Hello World!
    Result: Hello Java!
    System.out

    En el archivo de construcción hay que incluir la dependencia de Retrofit.

     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
    
    plugins {
        id 'application'
    }
    
    repositories {
        mavenCentral()
    }
    
    dependencies {
        implementation(platform('org.springframework.boot:spring-boot-dependencies:2.4.5'))
    
        implementation 'org.springframework.boot:spring-boot'
        implementation 'org.springframework.boot:spring-boot-starter-web'
        implementation 'org.springframework.boot:spring-boot-starter-actuator'
    
        implementation 'com.squareup.retrofit2:retrofit:2.9.0'
        implementation 'com.squareup.retrofit2:converter-scalars:2.9.0'
    
        implementation 'io.micrometer:micrometer-core:1.6.6'
    }
    
    
    application {
        mainClass = 'io.github.picodotdev.blogbitix.javaretrofit.Main'
    }
    
    build.gradle
    Terminal

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

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

    Picando Código

    Siete días en el P̸͖̣̞̍ί̵̨͙̮̞̪̹͇̪͎̋̒͘̕ƈ̵̢͈̰̲͇͍͍̬͙͇̂͊̓͒̽ᾷ̵͈͔̠ɳ̶̮͓͇̖̲͐̐̈́̔̌́ԃ̴̧̛̫̭͊̈́̋͂̕͘ͅσ̸̨̟̱̗̜̿́ͅʋ̶̨͓̑̈͊̌͠ҽ̶͔̙̙͂̃͂́͂͛̕̕͜͜ɾ̵̡̢̭̭̼̩̩̖̘͐͊̏͘͝͝ʂ̵̤̦̙̺̦̗̫̤̓̇̍͂̓̈̏̄̎̃͜ͅσ̴̯̦̞̠̯͉̟̮͂̑̂͆͊͛ͅ – Abril Revolutions

    abril 21, 2021 03:30

    En esta nueva edición de Siete días en el Picandoverso comparto unos videos interesantes sobre películas y series de artes marciales y robots, varios enlaces interesantes sobre el lenguaje de programación Ruby, algunas cosas sobre Firefox, Tecnología y más.

    Siete días en el P̸͖̣̞̍ί̵̨͙̮̞̪̹͇̪͎̋̒͘̕ƈ̵̢͈̰̲͇͍͍̬͙͇̂͊̓͒̽ᾷ̵͈͔̠ɳ̶̮͓͇̖̲͐̐̈́̔̌́ԃ̴̧̛̫̭͊̈́̋͂̕͘ͅσ̸̨̟̱̗̜̿́ͅʋ̶̨͓̑̈͊̌͠ҽ̶͔̙̙͂̃͂́͂͛̕̕͜͜ɾ̵̡̢̭̭̼̩̩̖̘͐͊̏͘͝͝ʂ̵̤̦̙̺̦̗̫̤̓̇̍͂̓̈̏̄̎̃͜ͅσ̴̯̦̞̠̯͉̟̮͂̑̂͆͊͛ͅ

    Ruby

    💎 Se publicó la versión 1.0 de Alba, biblioteca para parsear JSON en Ruby que dice ser la más rápida.

    💎 Publicado Rubocop 1.13 con bastantes mejoras, entre ellas un cop interesante Layout/RedundantLineBreak: hace que si una expresión entra en el largo de línea permitido, no lo separa en líneas nuevas.

    💎 La gente de Planet Ruby organizó una nueva semana temática sobre gemas Ruby. Se trata de The Ruby Pixel Art Week 2021, presentando una biblioteca gráfica Ruby por día todos los días desde el 19 al 25 de abril. Destaca bibliotecas gráficas para pixelart en Ruby. Todavía quedan algunos días disponibles si querés aportar escribiendo sobre una gema en particular.

    💎 Mike Perham, el desarrollador de Sidekiq – el popular programador de trabajos o “job scheduler” en Ruby- escribió un artículo muy completo sobre la API de Sidekiq. A Tour of the Sidekiq API.

    💎 Problemas comunes con CSV en Ruby y cómo solucionarlos en un artículo de Long Live Ruby. Me resultan muy familiares, ideales para quienes usamos Ruby para parsear Datos Abiertos.

    💎 Para celebrar su 2° aniversario, DragonRuby está ofreciendo licencias gratuitas del kit. La oferta dura hasta el lunes 26 de abril. DragonRuby Game Toolkit es un motor 2D para desarrollar videojuegos que pueden ser ejecutados en PC, Mac, Linux, Raspberry Pi y Web (también existe al menos un juego hecho en DragonRuby para Nintendo Switch). Tiene una licencia comercial y proveen licencias gratuitas para estudiantes, profesores y maestros, personas con bajos ingresos, menores de edad y más. Vengo atento a esta herramienta desde la charla de Amir Rajan en The Ruby Galaxy, y ya lo tengo descargado. ¡A ver si en breve sale algún proyecto de videojuego en Ruby!

    Programación / Tecnología

    🧪 La empresa Grafana Labs fue fundada en 2014 como negocio alrededor del proyecto de código abierto Grafana, para poder financiar esa tecnología y su comunidad. Inspirados en empresas como Elastic, Redis Labs y MongoDB -entre otras-, decidieron hacer un cambio en la licencia de su software. Las empresas mencionadas evoluciaron su régimen de licencias a licencias no aprobadas por la OSI, pero son un paso necesario para poder mantener el negocio que soporta el desarrollo de las respectivas tecnologías (particularmente para defenderse de prácticas de mega corporaciones monopólicas).

    Así que Grafana decidió cambiar la licencia de Grafana, Loki y Tempo de Apache 2 a AGPL3. Agregan que si bien AGPL no los protege de la misma manera que otras licencias (como la SSPL), creen que mantiene un balance correcto.

    🔥🦊 Firefox Nightly y Firefox Beta soportan HTTP/3 – Al visitar un sitio que ofrece soporte HTTP/3, el pedido en el panel de Red indicará que se usó el protocolo HTTP/3.

    🔥🦊 Se publicó Firefox 88 – el mejor navegador web y de los pocos que respetan tu privacidad. Entre las características destacadas están adiciones CSS: soporte para user-valid, :user-invalid y image-set(). Podemos aprender más de estas características en este post de Mozilla Hacks. ¡También se eliminó el soporte para el protocolo FTP! Personalmente cuando necesito usar FTP acudo a mi navegador de archivos, tanto Files en GNOME como Dolphin en KDE soportan ftp. Podemos leer las notas completas de esta version en este enlace.

    🕵️‍♂️ WordPress, sistema responsable de aproximadamente 40% de los sitios web, publicó una propuesta para tratar a FLoC como un problema de seguridad. Federated Learning of Cohorts (FLoC) es un nuevo proyecto de Google en Chrome para violar la privacidad de los usuarios y agruparlos basado en sus hábitos de navegación para proveer publicidad dirigida. Ahora WordPress propone tratarlo como un problema de seguridad y deshabilitarlo por defecto en el sistema.

    🖋 Siguiendo con WordPress, tras la versión 0.84.0 del plugin List Category Posts, Klemens publicó la versión 0.84.1 de List Category Posts que agrega hooks al plugin! Por mi parte publiqué una actualización de mi otro plugin de WordPress List Categories, más que nada confirmando su compatibilidad con las versiones más recientes de WordPress.

    📝 Otra semana de noticias de Emacs en el blog de Sacha Chua: Emacs News 2021-04-19

    🎮 Descubrí de casualidad de la existencia del Teenage Engineering Pocket Operator PO-128 viendo un cover chiptune 8-bits de Dammit de Blink 182. En el video se ve la edición limitada de Mega Man, pero existe también uno de Street Fighter. No sabía que existía este aparato, ¡pero ahora necesito uno! (de cada uno). Lástima que el precio es bastante elevado 😬

    YouTube Video

    Trabajo

    Recientemente vengo teniendo días bastante productivos en el trabajo. Así que los estoy aprovechando para sacar bastante trabajo adelante y mejorando cosas en el cliente Ruby Elasticsearch. También tengo que implementar algunas cosas interesantes que se van a publicar en la próxima versión del cliente de Elastic Enterprise Search.

    Estuvo bueno enterarse que proyectos de la empresa donde trabajo ¡ayudaron a la NASA a volar un helicóptero en Marte!

    Películas y Televisión

    Marvel publicó el primer trailer de una nueva entrega en su universo cinematográfico Shang-Chi and the Legend of the Ten Rings. Se ve muy bien, artes marciales con el toque Marvel, tiene que estar espectacular:
    YouTube Video

    Este viernes se estrena la película de Mortal Kombat, en cines y gratis para suscriptores de HBO Max. El servicio no está disponible en Escocia, y los cines todavía no han abierto por acá. Así que tendré que esperar… Mientras tanto, ya pude disfrutar de los primeros 7 minutos de la película publicados en YouTube por HBO Max. Con estos pocos minutos ya me gustó, muy buenas escenas de pelea con violencia y artes marciales:

    YouTube Video

    Netflix publicó un trailer del segundo volúmen de su serie Love death + Robots: La antología animada NSFW vuelve con una venganza. Gigantes desnudos, demonios de Navidad, y robots salvajes, nos alientan a consumirlo de manera irresponsable. Se estrena el 14 de mayo, y anunciaron un tercer volumen para 2022. Me sentí muy identificado con las palabras y expresión en la voz una de las protagonistas del video: “He estado viva 218 años, he visto demasiado”, creo que acompaña el sentimiento de esta pandemia… El trailer:

    YouTube Video

    Picando Código

    Tengo un par de borradores por terminar que espero poder publicar en breve, uno repasando un poco lo que ha sido este tiempo de pandemia en el blog. ¿Cómo les lleva la pandemia por su lado?

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

    Otros 7 días en el Picandoverso:

    El post Siete días en el P̸͖̣̞̍ί̵̨͙̮̞̪̹͇̪͎̋̒͘̕ƈ̵̢͈̰̲͇͍͍̬͙͇̂͊̓͒̽ᾷ̵͈͔̠ɳ̶̮͓͇̖̲͐̐̈́̔̌́ԃ̴̧̛̫̭͊̈́̋͂̕͘ͅσ̸̨̟̱̗̜̿́ͅʋ̶̨͓̑̈͊̌͠ҽ̶͔̙̙͂̃͂́͂͛̕̕͜͜ɾ̵̡̢̭̭̼̩̩̖̘͐͊̏͘͝͝ʂ̵̤̦̙̺̦̗̫̤̓̇̍͂̓̈̏̄̎̃͜ͅσ̴̯̦̞̠̯͉̟̮͂̑̂͆͊͛ͅ – Abril Revolutions fue publicado originalmente en Picando Código.

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

    Blog Bitix

    Historias de un streamer, «Un nuevo reto»

    abril 20, 2021 05:00

    Alex enciende la Xbox y conecta el disco duro externo más vendido del momento, que ha comprado en una tienda online con dos terabytes metidos en una caja verde con la que liberará espacio de la consola.

    Con la capturadora que compró y el micrófono tiene todo preparado y hoy es un día importante, se enfrenta a los mejores del instituto. Los cascos bien ajustados y listo, se deja caer en la parte más alta de la isla.

    Discos duros externos

    Sale a toda velocidad en busca de una fuente de armas. El disco externo está encendido y graba de manera automática sus avances y también sus emociones. Se relaja en el momento en que observa por la mirilla y ve a su oponente que está en el campanario, pero falla el disparo dejando una estela de humo que puede localizarle.

    Su perro Duty, se le ha subido a las piernas y le ladra, mete el hocico entre sus manos y tiene que dejar de jugar, no puede huir y le disparan, se salva por los pelos, se enfada, grita, «Mira lo que has hecho. Duty».

    El perro se aleja, deja de ladrar y comprende que no es el momento y aunque tiene muchas ganas y no aguanta más, se va al rincón de la habitación y allí deja una charco amarillento.

    ¡Ahora, vale! Vamos a la calle, Duty tiene la cabeza agachada le da vergüenza haber manchado la alfombra. «Luego la limpiaremos no pasa nada, ¡vamos Duty!».

    Los tres salen a casa de su amigo, ¿los tres? Sí los tres. Alex, su perro Duty y su nuevo disco duro externo en el bolsillo con la partida grabada. Ahora la verá y comentará con su amigo Tomás y a subirlo a su nuevo canal de Twitch.

    Ha nacido un nuevo streamer.

    Esta es una breve historia, una ficción para explicar lo práctico que sería disponer de este tipo de discos. Y ahora damos algunas características especiales de este disco duro externo recomendado tan vendido.

    Características del disco Seagate Game Drive - 2TB

    Tamaño del HDD 2.5", capacidad 2 TB (2000 GB), conector USB micro-USB B, versión USB 3.2 Gen 1 (3.1 Gen 1), tasa de transferencia de datos USB 480-5000 Mbit/s, color verde, alimentación USB, ancho 80 mm, profundidad 117 mm, altura 14.8 mm y peso 170 gr.

    Diseñado para Xbox

    El disco duro externo HDD portátil diseñado para Xbox One es una solución perfecta para liberar espacio de tu consola. Con 2 años de servicios rescue y 2 TB. Top ventas con miles de unidades vendidas. Es sin dudar una de las mejores opciones para el almacenamiento masivo de juegos y datos que se formatea automáticamente y sin problemas de compatibilidad.

    Disco duro Seagate Game Drive

    Disco duro Seagate Game Drive

    Comparte sin miedo con los discos duros externos para PS4 y para Xbox de Seagate que están recomendados para aquellos jugadores que no pueden desprenderse de su colección de juegos por muchos motivos, por la pasta que se han gastado en ellos, porque les une un vínculo mucho más fuerte de lo que imaginamos o porque simplemente es un aficionado dispuesto a coleccionar todo lo que pueda.

    Lo hemos probado y con diferencia, es un disco que soluciona muchas de estas necesidades de almacenamiento contado desde la ficción.

    Esperamos que os haya gustado este toque que mezcla lo técnico con la fantasía.

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

    Picando Código

    eBooks: Head First Programming por O’Reilly

    abril 20, 2021 12:30

    La serie de libros Head First de O’Reilly es excelente para aprender algo por primera vez. En su momento leí Head First Java, Head First Software Development y partes de Head First Design Patterns si recuerdo bien.

    Humble Bundle está ofreciendo un paquete de eBooks de la serie Head First para aprender Java, Python, Go, C, Ruby y más. El precio mínimo es USD 1/1 €, por un paquete con un costo total mayor a USD 700. Podemos elegir el precio y cómo se distribuye el dinero que aportamos entre la editora, la caridad Code For America o Humble Bundle.

    eBooks: Head First Programming por O’Reilly

    Pagando el mínimo de USD 1/1 € o más, obtenemos:

    • Head First Ruby
    • Head First C
    • Head First PMP – Cuarta Edición
    • Head First SQL
    • Head First Statistics

    Pagando USD 10 / 8.50 € o más, obtenemos los anteriores y:

    • Head First JavaScript Programming
    • Head First Learn to Code
    • Head First HTML and CSS – Segunda Edición
    • Head First C# – Tercera Edición
    • Head First Agile

    Pagando USD 18 / 15 € o más, obtenemos todos los libros anteriores y:

    • Head First Go
    • Head First Java – Segunda Edición
    • Head First Python – Segunda Edición
    • Head First Kotlin
    • Head First Android Development – Segunda Edición

    Comprar el paquete de ebooks

    El post eBooks: Head First Programming por O’Reilly fue publicado originalmente en Picando Código.

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

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

    Optimizaciones de .htaccess para tu web y también para WordPress

    abril 20, 2021 10:59

    Cuando me preparé para escribir Nulled WP-Rocket y cómo parchearlo necesariamente me tuve que familiarizar con el funcionamiento del plugin WP-Rocket. Me di cuenta que aunque es el más rápido del mercado, todavía lo podía ser aún más, puesto que había algunas optimizaciones elementales a nivel de .htaccess que no habían aplicado.

    Como forma de devolverles el favor decidí sugerírselas por lo que supongo que pronto las tendrán disponibles. De hecho también les apunté a optimizar estáticamente sus imágenes (PNG y SVG) que con FileOptimizer ahorrarían casi 64 KB., aunque en esto no me hicieron caso.



    Optimizaciones de .htaccess para tu web y también para WordPress

    A lo que íbamos, estos ajustes que menciono los puedes aplicar tu mismo, tanto si usas WP-Rocket como cualquier otro plugin de caché (WP Fastest Cache, Super Cache, W3 Total Cache), e incluso si no utilizas ninguno en absoluto.

    Se encargan de modificar algunas opciones del servidor web Apache para:
    – Aumentar la velocidad de carga estableciendo la fecha de expiración de los recursos (Leverage Browser Caching).
    – Reducir el tamaño de las páginas y por tanto aumentando su velocidad activando la compresión GZIP, Deflate y la nueva Brotli.
    – Mejorar la seguridad con algunos nuevos encabezados.
    – Mejorar el rendimiento gracias a Google Page Speed en el caso de que mod_pagespeed.so esté instalado.

    # Use UTF-8 encoding for anything served text/plain or text/html
    AddDefaultCharset UTF-8
    # Force UTF-8 for a number of file formats
    
    	AddCharset UTF-8 .atom .css .js .json .rss .vtt .xml
    
    # FileETag None is not enough for every server.
    
    	Header unset ETag
    
    # Since we’re sending far-future expires, we don’t need ETags for static content.
    # developer.yahoo.com/performance/rules.html#etags
    FileETag None
    
    	
    		
    			Header unset Pragma
    			Header append Cache-Control "public"
    			Header unset Last-Modified
    		
    	
    	
    		
    			Header unset Pragma
    			Header append Cache-Control "public"
    		
    	
    
    # Expires headers (for better cache control)
    
    	ExpiresActive on
    	ExpiresDefault                              "access plus 1 month"
    	# cache.appcache needs re-requests in FF 3.6 (thanks Remy ~Introducing HTML5)
    	ExpiresByType text/cache-manifest           "access plus 0 seconds"
    	# Your document html
    	ExpiresByType text/html                     "access plus 0 seconds"
    	# Data
    	ExpiresByType text/xml                      "access plus 0 seconds"
    	ExpiresByType application/xml               "access plus 0 seconds"
    	ExpiresByType application/json              "access plus 0 seconds"
    	# Feed
    	ExpiresByType application/rss+xml           "access plus 1 hour"
    	ExpiresByType application/atom+xml          "access plus 1 hour"
    	# Favicon (cannot be renamed)
    	ExpiresByType image/x-icon                  "access plus 1 week"
    	# Media: images, video, audio
    	ExpiresByType image/gif                     "access plus 4 months"
    	ExpiresByType image/png                     "access plus 4 months"
    	ExpiresByType image/jpeg                    "access plus 4 months"
    	ExpiresByType image/webp                    "access plus 4 months"
    	ExpiresByType video/ogg                     "access plus 4 months"
    	ExpiresByType audio/ogg                     "access plus 4 months"
    	ExpiresByType video/mp4                     "access plus 4 months"
    	ExpiresByType video/webm                    "access plus 4 months"
    	# HTC files  (css3pie)
    	ExpiresByType text/x-component              "access plus 1 month"
    	# Webfonts
    	ExpiresByType font/ttf                      "access plus 4 months"
    	ExpiresByType font/otf                      "access plus 4 months"
    	ExpiresByType font/woff                     "access plus 4 months"
    	ExpiresByType font/woff2                    "access plus 4 months"
    	ExpiresByType image/svg+xml                 "access plus 1 month"
    	ExpiresByType application/vnd.ms-fontobject "access plus 1 month"
    	# CSS and JavaScript
    	ExpiresByType text/css                      "access plus 1 year"
    	ExpiresByType application/javascript        "access plus 1 year"
    
    # Gzip compression
    
    	# Active compression
    	SetOutputFilter DEFLATE
    	# Force deflate for mangled headers
    	
    		
    			SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding
    			RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding
    			# Don’t compress images and other uncompressible content
    			SetEnvIfNoCase Request_URI \
    			\.(?:gif|jpe?g|png|rar|zip|exe|flv|mov|wma|mp3|avi|swf|mp?g|mp4|webm|webp|pdf)$ no-gzip dont-vary
    		
    	
    	# Compress all output labeled with one of the following MIME-types
    	
    		AddOutputFilterByType DEFLATE application/atom+xml \
                      application/javascript \
                      application/json \
                      application/rss+xml \
                      application/vnd.ms-fontobject \
                      application/x-font-ttf \
                      application/xhtml+xml \
                      application/xml \
                      font/opentype \
                      image/svg+xml \
                      image/x-icon \
                      text/css \
                      text/html \
                      text/plain \
                      text/x-component \
                      text/xml
    	
    	
    		Header append Vary: Accept-Encoding
    	
    
    
    	AddType text/html .html_gzip
    	AddEncoding gzip .html_gzip
    
    
    	SetEnvIfNoCase Request_URI \.html_gzip$ no-gzip
    
    
    	RewriteEngine On
    	RewriteBase /
    	RewriteCond %{HTTPS} on [OR]
    	RewriteCond %{SERVER_PORT} ^443$ [OR]
    	RewriteCond %{HTTP:X-Forwarded-Proto} https
    	RewriteRule .* - [E=WPR_SSL:-https]
    	RewriteCond %{HTTP_ACCEPT} image/webp
    	RewriteCond "%{DOCUMENT_ROOT}/wp-content/cache/wp-rocket/%{HTTP_HOST}%{REQUEST_URI}/.no-webp" !-f
    	RewriteRule .* - [E=WPR_WEBP:-webp]
    	RewriteCond %{HTTP:Accept-Encoding} gzip
    	RewriteRule .* - [E=WPR_ENC:_gzip]
    	RewriteCond %{REQUEST_METHOD} GET
    	RewriteCond %{QUERY_STRING} =""
    	RewriteCond %{HTTP:Cookie} !(wordpress_logged_in_.+|wp-postpass_|wptouch_switch_toggle|comment_author_|comment_author_email_) [NC]
    	RewriteCond %{REQUEST_URI} !^(/(.+/)?feed/?.+/?|/(?:.+/)?embed/|/(index\.php/)?wp\-json(/.*|$))$ [NC]
    	RewriteCond %{HTTP_USER_AGENT} !^(facebookexternalhit).* [NC]
    	RewriteCond "%{DOCUMENT_ROOT}/wp-content/cache/wp-rocket/%{HTTP_HOST}%{REQUEST_URI}/index%{ENV:WPR_SSL}%{ENV:WPR_WEBP}.html%{ENV:WPR_ENC}" -f
    	RewriteRule .* "/wp-content/cache/wp-rocket/%{HTTP_HOST}%{REQUEST_URI}/index%{ENV:WPR_SSL}%{ENV:WPR_WEBP}.html%{ENV:WPR_ENC}" [L]
    
    
    ServerSignature Off
    Options -Indexes
    
    	ModPagespeed on
    	ModPagespeedRewriteLevel OptimizeForBandwidth
    	ModPagespeedForceCaching on
    	ModPagespeedEnableCachePurge on
    	ModPagespeedEnableFilters collapse_whitespace,extend_cache,combine_heads,elide_atttributes,remove_quotes
    	ModPagespeedEnableFilters prioritize_critical_css,rewrite_css,fallback_rewrite_css_urls,move_css_to_head
    	ModPagespeedEnableFilters canonicalize_javascript_libraries,rewrite_javascript,defer_javascript,make_google_analytics_async
    	ModPagespeedEnableFilters recompress_images,sprite_images,recompress_webp,responsive_images,resize_images,lazyload_images,convert_jpeg_to_progressive
    	ModPagespeedEnableFilters convert_png_to_jpeg,convert_jpeg_to_webp
    
    
    	Header set Connection keep-alive
    
    
    	Header set X-XSS-Protection "1; mode=block"
    	Header always append X-Frame-Options SAMEORIGIN
    	Header set X-Content-Type-Options nosniff
    	Header always set Referrer-Policy "no-referrer, strict-origin-when-cross-origin"
    
    
    	mod_gzip_on Yes
    	mod_gzip_dechunk Yes
    	mod_gzip_item_include file \.(html?|txt|css|js|php|pl)$
    	mod_gzip_item_include handler ^cgi-script$
    	mod_gzip_item_include mime ^text/.*
    	mod_gzip_item_include mime ^application/x-javascript.*
    	mod_gzip_item_exclude mime ^image/.*
    	mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
    
    
    	#BrotliCompressionQuality 6
    	AddOutputFilterByType BROTLI_COMPRESS application/atom+xml \
    		                          application/javascript \
    		                          application/json \
    		                          application/rss+xml \
    		                          application/vnd.ms-fontobject \
    		                          application/x-font-ttf \
    		                          application/xhtml+xml \
    		                          application/xml \
    		                          font/opentype \
    		                          image/svg+xml \
    		                          image/x-icon \
    		                          text/css \
    		                          text/html \
    		                          text/plain \
    		                          text/x-component \
    		                          text/xml
    

    Lo mejor de todo es que no necesitas ningún plugin para aumentar el rendimiento de tu web, esté construida en la plataforma que esté construida, porque son añadidos que puedes agregar directamente a tu servidor web usando el .htaccess. Como ves, comprueban que la funcionalidad esté disponible en el entorno antes de usarse, así que no tienen riesgo de romper nada, eso sí, haz una copia de seguridad del archivo antes de tocarlo, no vaya a ser que se estropeé algo.

    Unas pocas opciones son de mi propia cosecha, es decir, las he evaluado yo sin haberlas visto mencionadas en demasiado sitios. Sin embargo la mayoría están sacadas de un sitio y de otro.



    Optimizaciones de .htaccess para tu web y también para WordPress

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

    Variable not found

    ¿Cuánto pesa realmente una aplicación Blazor WebAssembly recién creada?

    abril 20, 2021 06:05

    Blazor

    Cuando empezamos a estudiar Blazor WebAssembly e interiorizamos que para ejecutar .NET en el navegador es necesario llevar hasta éste el runtime y bibliotecas, tanto del propio framework como las de nuestra aplicación, una de las primeras dudas que nos asaltan es que cuánto peso tendrá eso. O dicho de otra forma, qué recursos tendrán que descargar los usuarios y qué tiempo tendrán que esperar hasta tener la aplicación en funcionamiento.

    En este post vamos a intentar dar respuesta a esta pregunta, aunque con matices. Obviamente, parte de ese peso dependerá de la aplicación; si se trata de un proyecto grande, con muchos ensamblados o que usen muchos componentes externos (p.e. paquetes NuGet), el número de archivos y el tamaño de la descarga crecerá inexorablemente. Por esa razón, no podremos ver aquí números absolutos, sino los mínimos, es decir, lo que pesará una aplicación Blazor WebAssembly recién creada, con los contenidos proporcionados por la plantilla por defecto usando .NET 5.

    Tampoco hablaremos de tiempos, pues son totalmente dependientes de las condiciones de red, la infraestructura en la que despleguemos la aplicación y las posibilidades del cliente. Simplemente tendremos en consideración que a más peso, mayor tiempo será necesario para llevarlo al navegador y ejecutarlo.

    Ojo: lo que vamos a ver son los datos aproximados obtenidos en mi máquina de desarrollo y con la versión actual de Blazor (5.0.4). Los números exactos variarán si hacéis pruebas en vuestro entorno, aunque seguro que el espíritu de las conclusiones seguirá siendo el mismo.

    Escenario 1: aplicación ejecutada en el entorno de desarrollo por primera vez

    Acabamos de crear una aplicación Blazor WebAssembly con Visual Studio y pulsamos F5.

    Peticiones realizadas204
    Contenido transferido (comprimido)9.2 MB
    Contenido cargado en la página (descomprimido)22.8 MB

    Panel de red en las herramientas de desarrollador, mostrando gran cantidad de recursos descargados¿De dónde salen estos números tan altos? Pues hay que tener en cuenta varios factores:

    • Estamos descargando, además de la página "raíz" que actúa como lanzadora de la aplicación y sus recursos relacionados (CSS, JS, iconos, fuentes), entre otros:
      • El runtime WebAssembly de .NET
      • Archivos de manifiesto y configuraciones
      • Los ensamblados (*.dll) de .NET 5
      • Los ensamblados de nuestra aplicación
      • Los datos de zonas horarias
    • El entorno de ejecución es Development, por lo que no se aplica ningún tipo de optimización.
    • No tenemos nada en caché, por lo que nuestro navegador deberá descargar todos los recursos.

    Aunque en nuestra máquina local o en redes internas la descarga de esos más de 9 MB no suponga ningún problema, en otro tipo de conexiones sí podría resultar un retraso importante para la carga. Sin embargo, recordad: estamos en el entorno de desarrollo y es la primera vez que ejecutamos.

    Escenario 2: aplicación ejecutada en el entorno de desarrollo por segunda vez o sucesivas

    Tras la primera ejecución, detenemos el proyecto y lo volvemos a lanzar desde Visual Studio pulsando la tecla F5.

    Peticiones realizadas11
    Contenido transferido (comprimido)5.6 kB
    Contenido cargado en la página (descomprimido)529 kB

    ¡Uau! ¡Pues sí que cambió la cosa! En la primera carga gran parte de los recursos (en particular, el runtime y bibliotecas de .NET) se almacenaron en la caché del navegador, por lo que no fue necesario volver a obtenerlos.

    Los contenidos cacheados son almacenados junto con un hash que permite detectar cuándo han cambiado. No se volverán a descargar salvo que eliminemos la caché o su contenido sea modificado.

    Nota: estos recursos son almacenados el cache storage, que es distinto al caché habitual del navegador, pues es gestionado desde el código JS de la página. Por esta razón, el comportamiento de opciones como "Disable caching" en la pestaña de red del navegador no tendrán efecto.

    Escenario 3: aplicación ejecutada en el entorno de desarrollo tras haber sido modificada

    Volvemos a lanzar con F5, aunque previamente modificamos ligeramente uno de los componentes Blazor, forzando así la generación de un nuevo ensamblado del proyecto.

    Peticiones realizadas12
    Contenido transferido (comprimido)51.2 kB
    Contenido cargado en la página (descomprimido)555 kB

    Como podemos observar, se trata de unos números muy parecidos a los anteriores. La diferencia principal está en el ensamblado del proyecto, que al haber sido modificado es necesario obtenerlo de nuevo. El resto de elementos previamente cacheados siguen siendo válidos.

    Escenario 4: aplicación publicada y ejecutada por primera vez

    Hasta ahora hemos visto los números siempre en el entorno de desarrollo, por lo que sólo nos afectarían mientras trabajamos en el proyecto. Pero pasemos a un escenario más definitivo: publicamos la aplicación (compilada en modo "Release") y la lanzamos, eliminando previamente la caché del navegador.

    Peticiones realizadas47
    Contenido transferido (comprimido)2.1 MB
    Contenido cargado en la página (descomprimido)7.0 MB

    ¡Hey! ¿Qué ha pasado aquí? Pues en primer lugar, fijaos en la reducción tan brutal del número de peticiones realizadas: hemos pasado de más de 200 a menos de 50. La magia aquí está en el IL trimming de la publicación, un mecanismo que permite eliminar de la salida el código IL que no utilizamos en la aplicación, incluidos los ensamblados del propio framework.

    También podemos observar una reducción importante en el tamaño (de 9 a 2MB). Aparte de que se han descargado menos recursos, esta reducción también se debe a que durante la publicación los archivos resultantes son comprimidos de forma estática.

    Como podemos ver, estos datos son bastante satisfactorios. Tanto el número de archivos a descargar como su peso total son más que razonables, teniendo en cuenta además que esta carga sólo ocurrirá la primera vez.

    Escenario 5: aplicación publicada en modo release y ejecutada por segunda vez (o siguientes)

    Accedemos de nuevo a la aplicación publicada anteriormente manteniendo la caché en el navegador, que al fin y al cabo será el comportamiento habitual de nuestros usuarios.

    Peticiones realizadas10
    Contenido transferido (comprimido)5.8 Kb
    Contenido cargado en la página (descomprimido)514 Kb

    Como podemos ver en este caso, una vez el contenido se encuentra en el navegador, queda poco por descargar, por lo que los resultados son similares a los que veíamos en tiempo de desarrollo. Números bastante bajos teniendo en cuenta que se trata de una recarga completa .

    Conclusión

    Como hemos visto, lo maravilloso que resulta poder utilizar C# en el navegador tiene su coste en cuanto a tiempo de la primera carga de la aplicación, aunque éste se reduce de forma drástica cuando nos encontramos en un entorno de producción y cuando se trata de las cargas sucesivas, gracias al uso de la caché del navegador.

    En muchos escenarios probablemente este retraso en el primer acceso es totalmente asumible. Si no es nuestro caso, probablemente deberíamos evaluar el uso de opciones que "maquillan" esos tiempos, como la prerenderización en servidor o el uso de animaciones o efectos interesantes para hacer más grata esa espera inicial a nuestros usuarios. Otras veces, cuando el tiempo inicial sea un factor absolutamente crítico, no tendremos más remedio que optar por tecnologías más ligeras en cliente (incluyendo Blazor Server, que es una buena opción en algunos escenarios).

    Publicado en Variable not found.

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

    Picando Código

    [Plugin WordPress] List Category Posts – 0.84

    abril 19, 2021 11:00

    Ayer publicamos una actualización del plugin de WordPress List Category Posts, la versión 0.84. Se trata de una versión bastante especial por varias razones.

    List Category PostsEn primer lugar, porque la publicación estuvo prácticamente 100% a cargo de Klemens Starybrat, uno de los colaboradores del plugin que más ha trabajado en el plugin en los últimos años. Klemens viene respondiendo preguntas en el foro de WordPress, resolviendo problemas en GitHub, actualizando el código, agregando funcionalidad y más. Ya es un colaborador oficial con permisos en GitHub y listado en la página del plugin como colaborador. También desarrolló un plugin que provee una interfaz gráfica para generar shortcodes de List Category Posts: GUI for List Category Posts.

    Es lo bueno de escribir código de código abierto, se terminó transformando en un proyecto comunitario y ya no depende exclusivamente de mí para recibir actualizaciones o nuevas versiones 😁

    Otro aspecto muy bueno de esta versión es que fue la primera vez que publicamos un release nuevo con GitHub Actions. Por alguna razón WordPress.org sigue usando Subversion para el control de versiones y publicación de sus plugins. Hasta ahora había sido la única razón por la cual tenía Subversion instalado en mi laptop, pero ya lo pude desinstalar sin problemas. Estamos usando esta acción: 10up/action-wordpress-plugin-deploy. Ahora al crear un tag en GitHub, que es como manejamos los releases, se publica automáticamente en WordPress.org.

    Como si fuera poco, esta versión trae un montón de cambios y mejoras después de un buen tiempo sin actualizaciones:

    • Nuevo: Elegir mostrar posts específicos por ID: ⦋catlist includeposts="2,97"⦌. ¡Gracias @hvianna!
    • Nuevo: Filtro avanzado de customfield con customfield_compare, ver la documentación por instrucciones.
    • Nuevo: Es posible darle estilo a category_description con category_description_tag ycategory_description_class.
    • Se cambió el tag por defecto que envuelve el contenido al usar content=yes a <div> para evitar generar HTML inválido (previamente era <p>).
    • Corregido excerpt_full que no pasaba los filtros the_excerpt (¡gracias a @StefanXRoos!). Los filtros se aplican igual que con excerpt_yes. Por favor revisa tu setup si estás usando excerpt_full.
    • Corregido bug en display_id, ¡gracias por reportarlo @Fiestoforo!
    • Corregidas advertencias de PHP en el admin de WordPress causadas por el widget, gracias por reportarlo @hiskingdomprophecy (#420).
    • Corregido filtro posts_where que no estaba siendo eliminado correctamente al usar starting_with.
    • Gran refactoreo de la generación de HTML haciéndolo más fácil de mantener.
    • Actualizado a PHP 7.4 en la máquina Vagrant.

    List Category Posts es un plugin para WordPress, es software libre publicado bajo la GPLv2. El código fuente está disponible en GitHub y en WordPress.org (SVN). Se puede descargar desde el sitio de plugins de WordPress.

    El post [Plugin WordPress] List Category Posts – 0.84 fue publicado originalmente en Picando Código.

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

    Variable not found

    Enlaces interesantes 440

    abril 19, 2021 06:05

    Enlaces interesantes

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

    Por si te lo perdiste...

    .NET Core / .NET

    ASP.NET Core / ASP.NET / Blazor

    Azure / Cloud

    Conceptos / Patrones / Buenas prácticas

    Data

    Machine learning / IA / Bots

    Web / HTML / CSS / Javascript

    Visual Studio / Complementos / Herramientas

    Xamarin

    Otros

    Publicado en Variable not found.

    Publicado en: www.variablenotfound.com.

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

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

    Nulled WP-Rocket y cómo parchearlo

    abril 17, 2021 04:51

    Hay una cosa que muchos no saben y que que el gestor de contenidos o CMS WordPress es código abierto con licencia GPL (GNU Lesser General Public License), lo cual exige que todos sus componentes también lo sean. Entre otras cosas significa que cualquiera es libre de hacer lo que quiera con él, incluso venderlo o modificarlo siempre y cuando el producto resultante también sea GPL.

    Hace unos años, en un afán de simplificar mi instalación quité el caché de WordPress. Sin embargo las cosas han ido cambiando y bien es cierto que después de estar con W3 Total Cache no probé los actuales líderes en cuanto a cacheo, todos ellos plugins de pago: WP-Rocket y WP Fastest Cache Premium. WP-Rocket se lanzó en 2013 y tiene un equipo de trabajo detrás, es decir no es la obra de un hombre solo como muchos otros.

    Hice unas pruebas y me di cuenta que con WP-Rocket y con WP Fastest Cache todo mejoraba mucho. Sin embargo eran plugins de pago, el primero desde 49$/año y el segundo desde 49$ de por vida. ¿Pero cómo pueden ser de pago siendo GPL? Bueno, porque GPL no impide cobrar por el software siempre y cuando se proporcione el código fuente del mismo y la libertad de estudiarlo y modificarlo entre otras.



    Nulled WP-Rocket y cómo parchearlo

    Según indican desde WP-Media el plugin WP-Rocket está instalado en cerca de 1,5 millones de webs, así que a 49$ por año podéis hacer números vosotros mismos…

    En efecto han surgido multitud de servicios que ofrecen plugins comerciales de WordPress a precio más ventajoso. El sistema que utilizan es sencillo, compran uno y cómo es GPL lo modifican y lo venden más barato, algo que es perfectamente legal.

    En el caso de WP-Rocket no es necesario llegar a tanto, porque sus autores WP-Media tienen el código disponible en Github. No tenemos más que descargarlo o clonarlo y nos haremos con él, por lo que se puede ofrecer gratuitamente sin problemas.

    Queda inicializarlo mediante composer, la parte más tediosa si no lo tenemos instalado y que con muchas dependencias de software nos instalará las dependencias que necesita:

    composer require wp-media/wp-rocket



    Nulled WP-Rocket y cómo parchearlo

    El primer paso para tenerlo nulled, nuleado o registrado es introducir nuestros datos de usuario. Es lo mismo que deben hacer aquellos que lo han comprado desde wp-rocket.me, sólo que nosotros nos los inventaremos.

    license-data.php

    // Your license KEY.
    if ( ! defined( 'WP_ROCKET_KEY' ) ) {
    	define( 'WP_ROCKET_KEY', '1234567');
    }
    
    // Your email, the one you used for the purchase.
    if ( ! defined( 'WP_ROCKET_EMAIL' ) ) {
    	define( 'WP_ROCKET_EMAIL', 'gmail@gmail.com' );

    También debemos introducir nuestra clave privada, que de nuevo es inventada:
    wp-rocket.php

    define( 'WP_ROCKET_PRIVATE_KEY'         , '365tredstq3gy5egftae45t4y5twegd');

    Ahora queda retornar que el software está licenciado y que su licencia es válida hasta el timestamp que queramos, en este caso 2030:

    inc/Engine/License/API/UserCLient.php

    public function get_user_data() {
    	return (object) [
    		'licence_account'    => '-1',
    		'licence_expiration' => 1893456000,
    	];
    }

    Y finalmente saltarnos las validaciones de claves que están en un par de sitios del mismo archivo:

    functions/options.php

    function rocket_valid_key() {
    	return true;
    }
    
    function rocket_check_key() {
    	Logger::info( 'LICENSE VALIDATION PROCESS STARTED.', [ 'license validation process' ] );
    
    	$rocket_options                   = [];
    	$rocket_options['consumer_key']   = 'activated';
    	$rocket_options['consumer_email'] = 'gmail@gmail.com';
    	$rocket_options['secret_key']     = 'activated';
    
    	if ( ! get_rocket_option( 'license' ) ) {
    		$rocket_options['license'] = '1';
    	}
    
    	Logger::info( 'License validation successful.', [ 'license validation process' ] );
    
    	set_transient( rocket_get_constant( 'WP_ROCKET_SLUG' ), $rocket_options );
    	delete_transient( 'rocket_check_key_errors' );
    	rocket_delete_licence_data_file();
    
    	return $rocket_options;
    }

    Para ahorrarte el trabajo puedes descargar tu mismo el archivo nulled_wp-rocket_3.8.8.zip (2,5 MB en formato ZIP), que además he aprovechado para optimizar con FileOptimizer, así que podríamos decir que es aún más rápido que el genuino.



    Nulled WP-Rocket y cómo parchearlo

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

    Header Files

    Huevos de Pascua

    abril 07, 2021 03:16

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

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

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

    warren_robinett

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

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

    textedit

    pc_icon

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

    os_x_mountain_lion

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

    mario_karts

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

    2dma

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

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

    Una sinfonía en C#

    Observables en Javascript RXjs ¿Qué es un Subject?

    marzo 22, 2021 12:00

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

    ¿Qué es un Subject?

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

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

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

    Hola
    

    Crear nuestros propios observables y controlarlos

    Entonces, podríamos tranquilamente hacer algo así:

    let subject = new Subject<number>();
    
    subject.subscribe({
        next: (value) => console.log(value),
        complete: () => console.log('complete'),
        error: (value) => console.log('Error ' + value)
    });
    
    let i = 0;
    let counter = 0;
    let interval = setInterval(()=>{
        i++;
        if(i === 10){
            counter++;
            i = 0;
            subject.next(counter);
        }
    }, 200);
    
    document.querySelector("#stopButton")?.addEventListener("click", ()=>{
        subject.complete();
        clearInterval(interval);
    });
    
    document.querySelector("#errorButton")?.addEventListener("click", ()=>{
        subject.error("Mi Error custom");
    });
    
    

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

    1 
    2 
    3 
    4 
    complete
    

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

    1 
    2 
    3 
    4 
    5 
    6 
    7 
    Error Mi Error custom
    

    Controlar otros observables

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

    let onStop = new Subject<void>();
    
    // creamos un observable del evento click de un botón
    // agregamos un operador TakeUntil para que deje de recibir eventos cuando onStop finalice.
    const observer = {
        next: (item : any) => console.log(` X:${item.clientX} Y:${item.clientY}`),
        complete: () => console.log("complete"),
        error: () => console.log("error")
    };
    
    let onStop = new Subject<boolean>();
    
    fromEvent(document, "click").pipe(takeUntil(onStop)).subscribe(observer);
    
    document.querySelector("#stopButton")?.addEventListener("click", ()=>{
        onStop.next(true);
    });
    
    

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

    Nada más por hoy, nos leemos.

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

    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