Martes 18 de diciembre de 2018

Asociación LiGNUx: El procesador de imágenes Raw RawTherapee alcanza su versión 5.5

Algoritmos genéticos: un caso práctico

Existen muchos tipos de algoritmos. Hoy vamos a hablar de un tipo de algoritmo no demasiado conocido, los algoritmos genéticos, que son de la familia de los algoritmos evolutivos. Además veremos su aplicación práctica en el vectorizado de imágenes con un programa que he realizado en Rust.

¿Qué es un algoritmo genético?

Un algoritmo genético es un algoritmo inspirado en el mecanismo de la naturaleza de la evolución biológica, descrita por Darwin allá por 1859 en el libro El Origen de las Especies. La idea es tener un conjunto de individuos (posibles soluciones). Estos individuos son evaluados para ver qué tan buenos son. Quedarnos con los mejores y proceder a la creación de nuevos individuos como resultados de la recombinación genética de dos individuos (como en la reproducción sexual). Posteriormente añadir alguna mutación genética para explorar nuevas posibilidades ligeramente diferentes. Proceder de nuevo a la selección natural hasta que tengamos individuos lo suficientemente buenos para nosotros.

Normalmente no son los algoritmos más eficientes ni tienen por qué dar un resultado óptimo, pero pueden servir para dar aproximaciones bastante buenas al resultado óptimo. Existen estrategias para mejorar los algoritmos genéticos como la gestión de la antigüedad de los individuos, para evitar máximos locales; la conservación de individuos con mal desempeño, para conservar mayor variedad genética; …

Como veremos más adelante, uno de los elementos más importante de estos algoritmos es la función de evaluación, que muchas veces es más complicada de programar de lo que parece.

Un caso práctico: vectorizado de imágenes

Para ver como estos conceptos teóricos funcionan en la práctica, vamos a hacer un programa que vectorice imágenes. ¿Esto qué es? Digamos que hay dos tipos de imágenes en informática. Por un lado tenemos las imágenes que almacenan los colores en píxeles (rasterizadas) y por otro lado aquellas que almacenan la imagen como fórmulas matemáticas, que se aplican cuando se quiere ver la imagen (vectoriales). Los formatos más comunes de imágenes rasterizadas son JPEG, PNG, GIF y WEBP. Los formatos más comunes de imágenes vectoriales son SVG y AI.

A las imágenes rasterizadas no se les puede hacer zoom hasta el infinito, se ven borrosas
A las imágenes vectoriales se les puede hacer zoom infinito, no pierden calidad

Pasar de una imagen vectorial a una rasterizada es trivial, pero el proceso inverso no lo es, y es justo donde vamos a aplicar el algoritmo genético.

En nuestro caso, vamos a tomar siluetas, negras sobre fondo blanco y tratar de vectorizarlas con curvas de Bézier.


Ejemplo de ejecución en la versión final de Mendel Vectorizer. La curva azul es la imagen vectorial generada.

Curvas de Bézier

En los años 60, Pierre Bézier, que trabajaba para Renault, diseñó un tipo de curva para el diseño asistido por ordenador (CAD). Estas son las conocidas como curvas de Bézier. Nuestro algoritmo tratará de encontrar la curva de Bézier más similar a la curva de la imagen rasterizada. Para ello necesitamos un punto de inicio, un punto final y dos puntos de control.

Curva cúbica de Bézier

En nuestro algoritmo, las curvas serán los individuos, y las coordenadas de los puntos de control serán los genes (habrá 4 genes por tanto).

Este es el código que he usado para definir las curvas de Bézier en Rust.

#[derive(Copy, Clone)]
pub struct Point {
    pub x: f64,
    pub y: f64,
}
impl Point {
    pub fn distance(&self, other: &Point) -> f64 {
        ((self.x - other.x).powf(2.0) + (self.y - other.y).powf(2.0)).sqrt()
    }

    pub fn middle(&self, other: &Point) -> Point {
        Point {
            x: (self.x + other.x) / 2.0,
            y: (self.y + other.y) / 2.0,
        }
    }
}

#[derive(Clone)]
/* Bezier */
pub struct Bezier {
    pub start: Point,
    pub control1: Point,
    pub control2: Point,
    pub end: Point,
}

impl<'a> Bezier {
    pub fn iter(&self) -> BezierIter {
        BezierIter {
            bezier: self,
            position: 0.0,
        }
    }
}

pub struct BezierIter<'a> {
    bezier: &'a Bezier,
    position: f64,
}

impl<'a> Iterator for BezierIter<'a> {
    type Item = Point;

    fn next(&mut self) -> Option<Point> {
        if self.position > 1.0 {
            return None;
        }
        let x = self.bezier.start.x * (1.0 - self.position).powf(3.0)
            + 3.0 * self.bezier.control1.x * self.position * (1.0 - self.position).powf(2.0)
            + 3.0 * self.bezier.control2.x * self.position.powf(2.0) * (1.0 - self.position)
            + self.bezier.end.x * self.position.powf(3.0);

        let y = self.bezier.start.y * (1.0 - self.position).powf(3.0)
            + 3.0 * self.bezier.control1.y * self.position * (1.0 - self.position).powf(2.0)
            + 3.0 * self.bezier.control2.y * self.position.powf(2.0) * (1.0 - self.position)
            + self.bezier.end.y * self.position.powf(3.0);
        self.position += 0.01;
        Some(Point { x, y })
    }
}

Encontrar puntos iniciales

El primer paso de nuestro algoritmo es buscar los puntos iniciales (y finales) de las curvas. En definitiva esto es un problema de búsqueda de esquinas.

Ejemplo de aplicación de FAST9 a una imagen

Existen varios algoritmos de búsqueda de esquinas: Harris, FAST9, FAST12, … No obstante, no tuve muy buenos resultados en las imágenes con las que trabajaba. Así que esta parte del algoritmo se la dejo al humano. El humano se encargará de poner los puntos, en orden, que tiene que tratar de unir el algoritmo con curvas de Bézier.

Función de evaluación

Muchas veces la función de evaluación es el punto más delicado de estos algoritmos. En este caso la idea fundamental es identificar si la curva de Bézier está encima de la curva original. Para ello tomamos 100 puntos equidistantes de la curva de Bézier (con la ecuación paramétrica de la curva es muy sencillo).

\(\mathbf{B}(t)=\mathbf{P}_0(1-t)^3+3\mathbf{P}_1t(1-t)^2+3\mathbf{P}_2t^2(1-t)+\mathbf{P}_3t^3 \mbox{ , } t \in [0,1].\)

Estos puntos se comparan con la imagen real, si ahí en la imagen original había una línea no pasa nada, si no, se resta 100. De este modo se penaliza gravemente salirse de la curva. Esto se hace así ya que la otra opción evidente (bonificar el estar sobre en la línea) podría dar lugar a resultados inesperados.

Ejemplificación de la función de evaluación. Los puntos amarillos están dentro de la línea. Los puntos verdes están fuera de la línea, penalizando a la curva en su “adaptación al medio”.

Pongamos como ejemplo una función de evaluación que bonifique por estar sobre la línea y no penalice por salirse de esta. Una línea bien adaptada a estas condiciones podría recorrerse toda la imagen, cruzando todas las líneas posibles, generando un garabato totalmente inútil pero muy bueno según esta función. Por ello, nuestra función de evaluación se basa en penalizar las salidas de la línea.

La función de evaluación presentada no es perfecta, ya que puede pasar de largo el punto final y dar la vuelta. Esta curva es más larga que la óptima, pero al estar completamente dentro de la línea negra original, la función de evaluación no la puede clasificar como peor que otras alternativas. Para solventar este problema una idea es que la longitud de la curva tenga una implicación en la función. No obstante, el cálculo de la longitud de una curva de Bezier es demasiado complejo y no lo he codificado. También podría aproximarse a través de segmentos rectos entre los 100 puntos calculados anteriormente.

Ejemplo de curva con puntuación máxima pero no óptima desde el punto de vista humano
pub fn evaluate(image: &amp;GrayImage, line: &amp;Bezier) -> f64 {
    let mut eval = 0.0;
    for point in line.iter() { // va generando los 100 puntos equidistantes
        let x = point.x as u32;
        let y = point.y as u32;
        if image.in_bounds(x, y) {
            let pixel = image.get_pixel(x, y);
            if pixel.data[0] > 200 {
                eval -= 100.0;
            }
        } else {
            eval -= 100.0;
        }
    }
    eval
}

Selección natural

La función de selección natural deja únicamente las 500 mejores curvas, de acuerdo a la función de evaluación, es decir, las mejor adaptadas de momento. Para la ordenación, Rust usa un algoritmo denominado Timsort, con coste O(nlogn). Sin embargo, en todo el algoritmo trabajamos con poblciones finitas, por lo que puede asimilarse a una constante, con coste O(1). 

pub fn natural_selection(image: &GrayImage, mut population: Vec<Bezier>) -> Vec<Bezier> {
    population.sort_by(|a, b| {
        let a = evaluate(&image, &a);
        let b = evaluate(&image, &b);
        b.partial_cmp(&a).unwrap()
    });

    population.into_iter().take(500).collect()
}

Población inicial

La población inicial se forma con 1000 curvas generadas con parámetros totalmente aleatorios. Los valores de cada coordenada, eso sí, están comprendidos entre -d y d siendo d la distancia en línea recta entre los puntos de inicio y final.

let mut population = Vec::new();
        let mut rng = thread_rng();
        let distancia = start.distance(&amp;end);
        for _ in 0..1000 {
            let xrand: f64 = rng.gen_range(-distancia, distancia);
            let yrand: f64 = rng.gen_range(-distancia, distancia);
            let mut control1 = start.middle(&amp;end);
            control1.x += xrand;
            control1.y += yrand;
            let mut control2 = start.middle(&amp;end);
            control2.x += xrand;
            control2.y += yrand;
            population.push(Bezier {
                start,
                end,
                control1,
                control2,
            });
        }

Recombinado

El proceso de recombinación permite mezclar los mejores especímenes tratando de conseguir uno mejor. Este algoritmo genético es de tipo RCGA (Real Coded Genetic Algorithm) ya que los genes son números reales, en contraposición a los típicos genes binarios.
Para estos algoritmos existen distintas variantes, aquí se usa el sistema de blend. El sistema de blend implica que de entre los dos padres se toman los valores mínimos y máximos para cada coordenada. Posteriormente se elige un nuevo valor de forma aleatoria con la condición de que esté dentro del rango de mínimo y máximo definido anteriormente.

// CROSSOVER
            
            let mut i: usize = 0;
            let mut babies = Vec::new();
            while i < GOOD_ONES {
                // 250 extra
                let line1 = &population[i];
                let line2 = &population[i + 1];

                let min_x = line1.control1.x.min(line2.control1.x);
                let max_x = line1.control1.x.max(line2.control1.x);
                let min_y = line1.control1.y.min(line2.control1.y);
                let max_y = line1.control1.y.max(line2.control1.y);
                let control1 = Point {
                    x: rng.gen_range(min_x, max_x),
                    y: rng.gen_range(min_y, max_y),
                };

                let min_x = line1.control2.x.min(line2.control2.x);
                let max_x = line1.control2.x.max(line2.control2.x);
                let min_y = line1.control2.y.min(line2.control2.y);
                let max_y = line1.control2.y.max(line2.control2.y);
                let control2 = Point {
                    x: rng.gen_range(min_x, max_x),
                    y: rng.gen_range(min_y, max_y),
                };

                babies.push(Bezier {
                    start,
                    end,
                    control1,
                    control2,
                });

                i += 2;
            }
            population.append(&mut babies);

Mutación

La fase de mutación permite generar pequeñas variaciones aleatorias respecto a la población. Afecta al 10% de la población aunque solo afecta a una coordenada a la vez.

Al ser un algoritmo RCGA, no vale simplemente con cambiar el valor de un bit. El enfoque utilizado en este algoritmo es el de una distribución normal de cambios de media 0. La distribución tiene la forma N(0,d/2). Esto implica que en la mayoría de las ocasiones la variación (tanto positiva como negativa) en la coordenada será bastante pequeña.

Distribución normal, aunque esta no es de media 0
// MUTATION
            // TASA DE MUTACION DEL 10%
            population = population
                .into_iter()
                .map(|mut line| {
                    if rng.gen::<f64>() < 0.10 {
                        let normal = Normal::new(0.0, distancia / 2.0);
                        let mutation_where: u32 = rng.gen_range(1, 5);
                        // Solo muta un gen, respecto a una Normal
                        match mutation_where {
                            1 => line.control1.x += rng.sample(normal),
                            2 => line.control1.y += rng.sample(normal),
                            3 => line.control2.x += rng.sample(normal),
                            4 => line.control2.y += rng.sample(normal),
                            _ => (),
                        }
                    }
                    line
                })
                .collect();

El programa: Mendel Vectorizer

El programa definitivo, Mendel Vectorizer, disponible en GitHub, tiene más detalles. La interfaz gráfica está hecha usando GTK, la interfaz de línea de comandos usa Clap y el algoritmo se ejecuta en paralelo usando paso de mensajes entre los hilos. El programa genera un fichero SVG resultado que puede ser abierto en programas como Inkscape o Adobe Illustrator.

El fichero generado por Mendel Vectorizer en Inkscape

Para usar Mendel Vectorizer en tu ordenador, sigue los siguientes pasos.

Descárgate una copia del código con Git. Compila con Rust (una edición que soporte la edición 2018, mínimo la 1.31) y ejecútalo.

git clone https://github.com/aarroyoc/mendel-vectorizer
cd mendel-vectorizer
cargo build
cargo run

También podéis descargaros la memoria en PDF del programa.

La entrada Algoritmos genéticos: un caso práctico se publicó primero en Adrianistán.

Lunes 17 de diciembre de 2018

Asociación LiGNUx: Tutorial para instalar la versión de mantenimiento del Kernel Linux 4.19.10
Gaspar Fernández

Gaspar Fernández
Poesía Binaria

Entorno de pruebas para nuestra web en función de una cookie

Hace unas semanas hablábamos de cómo hacer una redirección transparente en Apache en función de una cookie. Uno de los ejemplos que puse es el acceso a un entorno de test de nuestra aplicación. Un entorno de test al que podamos acceder nosotros como desarrolladores o incluso se lo podamos enseñar a un cliente final sin afectar al funcionamiento normal de la web (que por otro lado está funcionando).
A veces, podemos crear una dirección paralela tipo test.miweb.com, pero otras veces no es posible. Y decirle a todo el mundo que añada una dirección IP a su archivo hosts, y que nos haga caso, es complicado. Pensemos en aplicaciones que tienen una fuerte dependencia del host al que están vinculada. Un ejemplo sencillo es WordPress, muchas veces nos encontramos con plugins o temas que, tanto en su configuración como en otras tablas almacenan el host y se complicado estar todo el rato haciendo cambios en la base de datos. Pero no solo WordPress, esta necesidad nos puede surgir con multitud de aplicaciones.

Un poco de historia (personal)

Todo empezó buscando una manera de cambiar el DocumentRoot de un VirtualHost en función de una cookie. Aunque la propiedad DocumentRoot no soporta condiciones ni se puede cambiar tan fácilmente. Lo que debemos hacer es una redirección con proxy en función de una condición. Esta redirección puede ser a la misma máquina, o a otra diferente, incluso máquinas virtuales o contenedores docker, siempre que tengamos acceso por red. Estas máquinas también pueden ser privadas. Por lo que nuestro servidor principal puede tener un segundo interfaz de red que esté conectado a otro servidor y hacer el proxy hacia ese segundo servidor.

Así que, si en este momento tenemos suficiente con la máquina donde tenemos el servidor web principal podemos utilizar otro puerto en el que también levantaremos el servidor web. A mí me gusta el 180, por poner un puerto. Ese puerto debemos mantenerlo privado, para que el acceso sea solo dentro del host local y no esté expuesto a Internet (cosa que no queremos). Podemos elegir, si la página de pruebas está en otro host, perfecto. Si queremos que dicha web de pruebas esté en el mismo host, seguid leyendo.

Escuchando por el puerto 180

Lo primero es que Apache escuche en el puerto 180, aunque podríamos utilizar otro servidor web como Nginx, lighthttpd, etc. Aunque si lo que queremos es utilizarlo como entorno de test, es conveniente que utilicemos siempre el mismo servidor web (por lo que pueda pasar).

Aunque nuestra web la sirvamos por HTTPs. La redirección no hace falta hacerla también por HTTPs. Ya que la conexión segura se seguirá haciendo entre Apache y el usuario final que pide la web, y luego Apache hará una conexión no segura con él mismo para acceder a la web de pruebas. Puede que, según nuestros contratos con el cliente, o según lo paranoicos que seamos con la seguridad, nos interese también cifrar esta comunicación interna, pero eso ya es cuestión de gustos.

En Apache, la configuración puertos suele estar en /etc/apache2/httpd.conf, /etc/apache2/apache2.conf, /etc/apache2/ports.conf o incluso los archivos pueden estar situados en /etc/httpd/ . En mi caso, en la instalación en Ubuntu, suele estar en /etc/apache2/ports.conf, y finalmente lo podemos dejar así:

1
2
3
4
5
6
7
8
9
Listen 80
Listen 180
<IfModule ssl_module>
        Listen 443
</IfModule>

<IfModule mod_gnutls.c>
        Listen 443
</IfModule>

O incluso podríamos cercar más el acceso así, haciendo que solo escuchemos en el host local:

1
Listen 127.0.0.1:180

Ahora, nuestro Virtualhost de la web quedaría así (lo pongo completo, con SSL y todo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
<VirtualHost *:80>
     ServerName www.miweb.com
     ServerAlias miweb.com

     ServerAdmin administrador@miweb.com
     DocumentRoot /var/www/miweb.com/www

     RewriteEngine On
     RewriteCond %{HTTPS} off
     RewriteCond %{REQUEST_URI} "!/.well-known/acme-challenge/"
     RewriteRule (.*) https://www.%{HTTP_HOST}%{REQUEST_URI} [NE,L,R=301]

     ErrorLog ${APACHE_LOG_DIR}/error.log
     CustomLog ${APACHE_LOG_DIR}/access.log ombined

# Include conf-available/php7.0-fpm.conf

</VirtualHost>

<VirtualHost *:180>
     ServerName www.miweb.com

     ServerAlias miweb.com

     DocumentRoot /var/www/miweb.com_testing/www

     ErrorLog ${APACHE_LOG_DIR}/error.log
     CustomLog ${APACHE_LOG_DIR}/access.log combined
     Include conf-available/php7.0-fpm.conf
</VirtualHost>

<IfModule mod_ssl.c>
     <VirtualHost _default_:443>

          ServerName www.miweb.com
          ServerAlias miweb.com

          ServerAdmin administrador@miweb.com
          DocumentRoot /var/www/miweb.com/www

          ProxyPreserveHost On
          RewriteEngine On

          RewriteCond %{HTTP_COOKIE} cookie=([^;]+)
          RewriteCond %1 ^pruebas$
          RewriteRule ^/(.*) http://127.0.0.1:180/$1 [P,L]

          ErrorLog ${APACHE_LOG_DIR}/error.log
          CustomLog ${APACHE_LOG_DIR}/access.log combined

          Include conf-available/php7.0-fpm.conf

          SSLEngine on

          SSLCertificateFile /etc/letsencrypt/live/miweb.com/cert.pem
          SSLCertificateKeyFile /etc/letsencrypt/live/miweb.com/privkey.pem

          SSLCertificateChainFile /etc/letsencrypt/live/miweb.com/fullchain.pem

          <FilesMatch "\.(cgi|shtml|phtml|php)$">
               SSLOptions +StdEnvVars
          </FilesMatch>
          <Directory /usr/lib/cgi-bin>
               SSLOptions +StdEnvVars
          </Directory>
     </VirtualHost>
</IfModule>

Posibles cambios

Al estar utilizando otro VirtualHost, en este caso, el del puerto 180, podemos utilizar otra versión de PHP (En este caso, la web usa PHP), por supuesto otro DocumentRoot diferente, por lo que podríamos tener otra rama del repositorio de nuestra aplicación y la ésta podrá tener configuración de caché/logs/base de datos diferente a la aplicación principal.

Este sistema nos podría ayudar mucho a la hora de probar nuestra aplicación web en un entorno real o incluso con datos reales (si es posible), justo antes de desplegarla definitivamente.

Seguridad

Como dije antes, el puerto 180 no debe estar expuesto al exterior. No nos interesa que personas no autorizadas entren a nuestro sistema de pruebas. Podríamos tener contraseñas débiles, datos no reales o información de depuración activada que pueda dar pistas para atacar nuestra aplicación. Este puerto lo podemos bloquear desde nuestro proveedor de servicio, o desde la misma máquina, aplicando una restricción con UFW o desde iptables, así:

iptables -A INPUT -i eth0 -p tcp --dport 180 -j DROP

Ahora, debemos ser cuidadosos con las personas a las que les establecemos los valores de la cookie, porque podrán entrar a una zona privada de nuestro sistema. Sería conveniente no tener el acceso activado constantemente, sino activarlo solo cuando sea necesario, o poner también reglas por IP. Yo también, en los servicios donde utilizo esta técnica utilizo cookies como:
accesodepruebas=hn8JV9V1IfJylvQCmo+VUJb8ENgEIs/cbA8pWa7j1mE

La cadena aleatoria la podemos obtener así:

openssl rand -base64 32

De manera que sea muy muy difícil para alguien hallar el valor adecuado de la cookie.

Foto principal: unsplash-logoPietro De Grandi

The post Entorno de pruebas para nuestra web en función de una cookie appeared first on Poesía Binaria.

Lynx navega en la web sin salir de la consola de Linux

p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px 'Helvetica Neue'; color: #000000; -webkit-text-stroke: #000000} p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px 'Helvetica Neue'; color: #000000; -webkit-text-stroke: #000000; min-height: 12.0px} span.s1 {font-kerning: none} span.s2 {text-decoration: underline ; font-kerning: none} En el día a día, son muchos los que enfocan tanto
Ubuntizando.com

Ubuntizando.com
Ubuntizando.com

Hosting Java ¿Qué son y para qué sirven?

Cuando se habla de hosting muchas veces nos viene a la cabeza la idea de un alojamiento web que contratamos a un proveedor para poder tener nuestra página web, blog o tienda en linea. Esto es hasta cierto punto normal, pues la popularización de la Web a fomentado que esa idea pero hay más. Actualmente y gracias a las posibilidades que la nube nos ofrece es cada vez más frecuente recurrir a servidores de aplicaciones. Básicamente para no extenderme mucho podría decir que son máquinas destinadas a correr y ejecutar programas o servicios que son usados por nosotros con diferentes propósitos para el manejo de datos. Todos hemos visto en una oficina un viejo servidor que almacena el sistema de gestión o almacena datos importantes, imagina que desde ese servidor puedas correr programas y desde tu PC de escritorio acceder al resultado reduciendo considerablemente el tiempo necesario y el uso de recursos de tu sistema.

Extendiendo un poco más la explicación un servidor de aplicaciones es un programa de servidor en un equipo dentro de una red distribuida que proporciona la lógica de negocio para un programa de aplicación. Para entenderlo tenemos que pensar en el servidor de aplicaciones como parte de una aplicación de tres niveles, que consta de un servidor gráfico de interfaz de usuario (GUI), un servidor de aplicaciones (lógica empresarial) y un servidor de bases de datos y transacciones. De manera más descriptiva, se puede visualizar como la división de una aplicación en:

  1. Una interfaz gráfica de usuario de primer nivel, de front-end, basada en el navegador web.
  2. Una aplicación de lógica de negocio de nivel medio o conjunto de aplicaciones.
  3. Un servidor de back-end, que puede ser un servidor de base de datos.

Así un servidor de aplicaciones puede entenderse como un intermediario. Actualmente este tipo de servidores combina o funcionan dentro de un servidor web. Gracias a las opciones que nos permiten los navegadores actuales es posible acceder a programas complejos directamente desde estos sin necesidad de instalar software adicional. Esto es una gran ventaja sin duda. Mediante un “front-end” en HTML como un formulario, el usuario puede enviar una solicitud a un servidor de aplicaciones y este procesar la información para realizar la tarea encomendada o devolver un resultado a una página web nueva o modificada al usuario.

Este tipo de servidores suelen ser servidores dedicados, muy costosos, o Servidores Privados Virtuales (VPS). Sobre el papel funcionan muy bien como solución ya que nos liberan, como comentaba, de mucha carga de trabajo y recursos gestionando la mayor parte (o la totalidad) de las funciones de lógica de negociación y de acceso a los datos de las aplicaciones. Son soluciones “económicas” si los comparamos con las soluciones que teníamos disponibles hace 20 años.  ¿Quien no recuerda pelearse con CGI o un servidor Active Server de Microsoft?  Pero en la actualidad la cosa se ha simplificado un poco y podemos optar por hosting JAVA que tienen como principal ventaja el poder ser usados desde cualquier tipo de sistema operativo de escritorio o plataforma servidor con un coste muy inferior a las soluciones que antes comentaba.

JAVA es un lenguaje de programación muy extendido. Prácticamente el 80% de las empresas tienen algún tipo de software o aplicación desarrollado bajo este lenguaje o alguna de sus variables. Por eso no es difícil encontrar empresas que proporcionan servidores JAVA como soluciones o complemento a nuestro alojamiento web. Básicamente se tratan de planes compartidos o dedicados en donde podemos disponer de libertad absoluta para personalizar nuestro entorno servidor, acceder a sus recursos, etc.

Un ejemplo lo tenemos en la empresa ANW que ofrece a través de diferentes propuestas soluciones de hosting de aplicaciones JAVA adaptadas a todo tipo de usuarios.  De hecho es de las pocas que permiten desplegar nuestras aplicaciones con un simple click, ahorrando mucho tiempo y eligiendo la versión JDK que queramos.

 

 

Por otro lado sus paquetes incluyen SSL y BBDD MySQL además de un dominio .com o .es gratis. Por lo que son una buena alternativa para aquellas personas que arrancan con su Start-UP y quieren olvidarse los dolores de cabeza que todo “deploy” representa sin grandes diferencias con lo que viene siendo la administración de un hosting web convencional. Todo ventajas.

¿Pero qué diferencias tienen este tipo de hosting frente a un VPS? Costes a un lado la principal diferencia está en la cantidad de RAM disponible. En el caso de ANW y sus planes planes de hosting JAVA contamos con la friolera de 128GB de RAM que  es más que suficiente para resolver la mayoría de los picos de carga mediante un soft-limit correctamente configurado es virtualmente imposible que el servicio se vea comprometido. Todo esto a un precio muy por debajo de lo que un servidor VPS representa. Para entendernos. Si solo queremos lo importante de una naranja ¿para qué quedarnos con todo lo demás? 🙂

En resumen un servidor de aplicaciones puede ser una parte muy importante de tu proyecto. Si solo estás pensando en montar una web quizá no lo necesites pero si tienes en mente algo más complejo deberías tenerlo bastante presente. Del mismo modo los servidores dedicados pueden ser muy versatiles pero también son bastante costosos, y los VPS son geniales pero tienen el problema de que pagas por un paquete cerrado en donde los recursos del sistema pueden verse comprometidos por picos de memoria además de que como los servidores dedicados pueden ser difíciles de administrar. Un hosting JAVA puede quitarte mucho trabajo de encima y ayudar a centrar tus esfuerzos en lo importante y si además cuentas con un proveedor que te facilita el pliegue de tu aplicación con un clic, ya no se puede pedir más.

 

Domingo 16 de diciembre de 2018

Ubuntizando.com

Ubuntizando.com
Ubuntizando.com

Fotografía Libre, el libro que te ayuda a ser un poco más libre

Navegando en la red he encontrado información sobre “Fotografía Libre“, un proyecto que recopila en un tremendo eBook de 800 megas de peso un completo manual para, usando herramientas libres, liberar nuestra fotografía digital de todo software privativo para su tratamiento como puede ser PhotoShop por poner un ejemplo. Juan Luis Fernández Gallo, su autor,  ha creado una documento que creo muy valioso para la comunidad. Todo aquel que ha querido dar el salto al mundo del software libre se las ha visto con Gimp o Inkscape, que aún siendo muy prácticos como que cuentan con una curva de aprendizaje algo superior a otros programas de edición. Al final es cuestión de tiempo para lograr ponerse a hacer filigranas pero esto ahuyenta y mucho al usuario promedio. Y aquí lo valioso de este libro, porque ataja toda dificultad introduciendo al usuario de una manera sencilla.

Pero es que además es una completísima guía para aquellas personas que se inician en la fotografía. Algo así como la biblia de la fotografía digital en donde se explica prácticamente todo lo que necesitas saber y más. Qué es el patrón Bayer, cómo funciona el sensor de nuestra cámara, qué es el rango dinámico, qué son los distintos tipos de ruido que podemos encontrar en nuestras fotografías y cómo resolverlos, tipos de objetivos, lentes, apertura, etc. Simplemente impresionante. 🙂

El libro se encuentra disponible para descarga Torrent a partir de este enlace. Solo debemos descomprimir el .zip y abrir el torrent desde nuestra aplicación favorita, en mi caso Transmission.

Una vez descargado, si te ha gustado,

Fuente: https://colaboratorio.net

Asociación LiGNUx: BIOS UEFI – GRUB2 – BOOT – WINDOWS 10 y UBUNTU 18.04.01 LTS

Advent of Code 2018: segunda semana

Segunda semana del Advent of Code. En esta semana ya hemos tenido algunos problemas muy interesantes. Intentaré comentarlos de la mejor manera posible. Todo el código está aquí y en este otro post comenté mis soluciones de la primera semana.

Día 8

El día 8 se nos propone un problema de grafos también. Básicamente se nos define un árbol, donde cada nodo puede tener hijos y metadatos. En la primera parte nos piden sumar todos los metadatos.

Aquí al contrario que en el día 7, no voy a usar networkx. Era más difícil adaptar networkx al problema que hacer el árbol a mano. Uno de los puntos complicados de este problema es el parseo de la entrada, que hice de forma recursiva. Cada nodo es un diccionario con las propiedades tamaño, una lista de metadatos y una lista de nodos hijo.

En la segunda parte se define el concepto de valor de nodo y como calcularlo. También es bastante sencillo de implementar. Finalmente hacemos un recorrido por el árbol de tipo primero en anchura (BFS) con una deque de Python.

from collections import deque

def read_node(start,numbers):
    length = 2
    child_nodes = numbers[start]
    metadata_entries = numbers[start+1]
    children = list()
    while child_nodes > 0:
        child_node = read_node(start+length,numbers)
        children.append(child_node)
        length += child_node["length"]
        child_nodes -= 1
    metadata = list()
    while metadata_entries > 0:
        metadata.append(numbers[start+length])
        length += 1
        metadata_entries -= 1
    node = dict([("length",length),("metadata",metadata),("children",children)])
    return node
        


def read_file(file):
    with open(file) as f:
        line = f.readline()
    numbers = [int(x) for x in line.split()]
    G = read_node(0,numbers)
    return G

def node_value(N):
    if len(N["children"]) == 0:
        return sum(N["metadata"])
    else:
        s = 0
        for i in N["metadata"]:
            if i-1 &lt; len(N["children"]):
                s += node_value(N["children"][i-1])
        return s
        

def day8(file):
    G = read_file(file)

    to_visit = deque()
    to_visit.append(G)
    metadata_sum = 0
    while len(to_visit) > 0:
        N = to_visit.popleft()
        metadata_sum += sum(N["metadata"])
        to_visit.extend(N["children"])
    print("METADATA SUM: %d" % metadata_sum)
    print("NODE VALUE: %d" % node_value(G))

Día 9

Este día fue muy interesante. Se nos explica un juego, que consiste en ir añadiendo canicas en una circunferencia y cuando el número de canica que añadimos es múltiplo de 23, obtenemos puntos y quitamos una canica 7 puestos por detrás.

Aquí tuve una mala decisión de diseño ya que al principio quise hacer esto con una lista de Python (el equivalente a vector en otros lenguajes de programación). La idea era sencilla y funcionaba hasta que llegó la parte 2. La parte 2 te pedría calcular los puntos teniendo en cuenta 100 veces más canicas. Esto fue un grave problema para mi código. Calculo que tardaría 6 horas en calcularlo, pero antes optimicé. La optimización consistía en usar una lista circular doblemente enlazada. ¿Esto qué es? Se trata de una lista enlazada, doblemente, porque cada nodo tiene referencia al elemento siguiente y al anterior. Y es circular porque ambos extremos están unidos. Esto permite las inserciones y borrados en O(1). Además los movimientos relativos (en este problema todos son así) son extremadamente sencillos. La implementación de esta estructura de datos en Python es muy sencilla (en otros lenguajes es más complicado). No me molesté en hacer funciones que me hiciesen sencilla la vida y las conexiones/desconexiones las hago a mano directamente en el código del problema.

from collections import defaultdict

class Marble:
    def __init__(self,value,left=None,right=None):
        self.value = value
        self.left = left
        self.right = right
        if self.left == None:
            self.left = self
        if self.right == None:
            self.right = self

def day9(PLAYERS,LAST_MARBLE):
    SCORE = defaultdict(lambda: 0)
    player = 0
    marble = 0
    current_marble_pos = 0
    current_marble = None

    while marble &lt;= LAST_MARBLE:
        if marble > 0 and marble % 23 == 0:
            SCORE[player] += marble
            pivote = current_marble.left.left.left.left.left.left.left
            SCORE[player] += pivote.value
            pivote.left.right = pivote.right
            pivote.right.left = pivote.left
            current_marble = pivote.right

        else:
            if current_marble == None:
                current_marble = Marble(marble)
            else:
                current_marble = Marble(marble,current_marble.right,current_marble.right.right)
                current_marble.left.right = current_marble
                current_marble.right.left = current_marble
        player += 1
        player = player % PLAYERS
        marble += 1
    return max(SCORE.values())

Curiosamente, en la propia librería de Python deque tiene una operación llamada rotate que permite hacer este problema en poquísimas líneas y de forma muy eficiente. Pero desconocía la existencia de esa función (que lo que hace es mover la “cabeza” de la lista enlazada que es deque).

Día 10

Este problema es muy interesante. Se nos da una serie de puntos que van moviéndose por la pantalla. En un determinado momento estos puntos se juntan y forman un mensaje en pantalla.

Aquí lo interesante no es mover los puntos, eso es trivial, simplemente es sumar la velocidad cada vez las coordenadas. Lo interesante es saber cuando parar. Existen varias ideas:

  • Revisión humana de cada iteración
  • Comprobar que no haya puntos separados del resto (con grafos)
  • Comprobar que el área de concentración de puntos es mínima

Y alguna más. Para el ejemplo la primera idea servía. Pero en la prueba real, era más complicado. A mí se me ocurrió la tercera opción, la cuál es bastante eficiente. En cada iteración calculamos el área que contiene a todos los puntos, cuando ese área ya no se reduce más, hemos llegado al mensaje.

import re

def read_file(file):
    stars = list()
    p = re.compile("position=&lt;([ -][0-9]+), ([ -][0-9]+)> velocity=&lt;([ -][0-9]+), ([ -][0-9]+)>")
    with open(file) as f:
        lines = f.readlines()
    for line in lines:
        m = p.match(line.strip())
        try:
            pos_x = int(m.group(1))
        except:
            print(line)
        pos_y = int(m.group(2))
        vel_x = int(m.group(3))
        vel_y = int(m.group(4))
        stars.append([pos_x,pos_y,vel_x,vel_y])
    return stars
def print_stars(stars):
    stars = sorted(stars,key=lambda x: x[0],reverse=True)
    min_width = stars[-1][0]
    max_width = stars[0][0]
    min_height = min(stars,key=lambda x: x[1])[1]
    max_height = max(stars,key=lambda x: x[1])[1]
    s = str()
    for j in range(min_height,max_height+1):
        p = [star for star in stars if star[1] == j]
        for i in range(min_width,max_width+1):
            if len(p) == 0:
                s += "."
            else:
                if any(map(lambda star: star[0] == i and star[1] == j,p)):
                    s += "#"
                else:
                    s += "."
        s += "\n"

    return s

def step(stars):
    a = map(lambda x: [x[0]+x[2],x[1]+x[3],x[2],x[3]],stars)
    return list(a)

# LA RESPUESTA CORRECTA TIENE AREA MINIMA
def area(stars):
    stars = sorted(stars,key=lambda x: x[0], reverse=True)
    min_width = stars[-1][0]
    max_width = stars[0][0]
    min_height = min(stars,key=lambda x: x[1])[1]
    max_height = max(stars,key=lambda x: x[1])[1]
    area = (max_width-min_width)*(max_height-min_height)
    return area

def day10(file):
    stars = read_file(file)
    a = area(stars)
    steps = 0
    while area(step(stars)) &lt; a:
        stars = step(stars)
        steps += 1
        a = area(stars)
    print_stars(stars)
    print(steps)

La parte de dibujado me costó y ahí tuve un fallo que me costó media hora aproximadamente en resolver. Una mejor opción, pero que no se me ocurrió, hubiese sido usar Pillow y crear una imagen. Es mucho más fácil que dibujar sobre una terminal (y posiblemente más rápido).

Día 11

Para este problema hay 3 posibles algoritmos. En la primera parte nos piden que de una matriz extraigamos el cuadrado de 3×3 con mayor valor. La matriz hay que construirla pero es trivial. Yo decido usar un diccionario, con clave la tupla de coordenadas. Vamos recorriendo todas las posiciones y calculamos el valor. Ahora para buscar el cuadrado, simplemente vamos probando todos los posibles cuadrados.

En la segunda parte nos dicen que bsuquemos el cuadrado máximo pero el tamaño puede ser cualquiera. Aquí con la fuerza bruta ya tarda demasiado. Mi solución fue usar programación dinámica, para ello la clave pasa a tener un valor más, el tamaño del cuadrado. Cuando creamos la tabla estamos asignando valor al cuadrado 1×1 de posición X,Y. Representado es la tupla (x,y,1). Según vamos avanzando hasta 300×300 vamos guardando los resultados intermedios, de modo que podamos reutilizarlos. Por ejemplo, el valor de (x,y,4) solamente es la suma de (x,y,2), (x+2,y,2), (x,y+2,2) y (x+2,y+2,2). Evidentemente esto solo funciona en los tamaños pares. En los tamaños impares decidí coger el cuadrado de dimensión inmediatamente menor y calcular los laterales con los cuadrados de tamaño 1. Este sistema funciona mucho mejor que la fuerza bruta pero es lento. Los profesionales usaron el algoritmo Summed Area Table (del que desconocía su existencia). Este algoritmo es el óptimo para este problema.


def generate_fuel(x,y,idg):
    fuel = (((x+10)*y)+idg)*(x+10)
    fuel %= 1000
    fuel = (fuel // 100) - 5
    return fuel

def generate_table(idg):
    fuel = {(x,y,size):0 for x in range(1,301) for y in range(1,301) for size in range(1,301)} 
    for x in range(1,301):
        for y in range(1,301):
            fuel[(x,y,1)] = generate_fuel(x,y,idg)
    return fuel

def find_best(fuel):
    max_point = [-1,-1]
    max_score = -1
    for x in range(1,301):
        for y in range(1,301):
            if x+3 > 301 or y+3 > 301:
                continue
            score = fuel[(x,y,1)]+fuel[(x+1,y,1)]+fuel[(x+2,y,1)]+fuel[(x,y+1,1)]+fuel[(x+1,y+1,1)]+fuel[(x+2,y+1,1)]+fuel[(x,y+2,1)]+fuel[(x+1,y+2,1)]+fuel[(x+2,y+2,1)]
            if score > max_score:
                max_score = score
                max_point = [x,y]
    return max_point[0],max_point[1]

def find_best_any_size(fuel):
    max_score = -1
    max_point = [-1,-1,-1]
    for size in range(2,300+1):
        for x in range(1,301):
            for y in range(1,301):
                if x+size > 301 or y+size > 301:
                    continue
                if size % 2 == 0:
                    mid = size // 2
                    fuel[(x,y,size)] = fuel[(x+mid,y,mid)]+fuel[(x,y+mid,mid)]+fuel[(x+mid,y+mid,mid)]+fuel[(x,y,mid)]
                else:
                    fuel[(x,y,size)] = fuel[(x,y,size-1)]
                    for i in range(x,x+size-1):
                        fuel[(x,y,size)] += fuel[(i,y+size-1,1)]
                    for j in range(y,y+size-1):
                        fuel[(x,y,size)] += fuel[(x+size-1,j,1)]
                    fuel[(x,y,size)] += fuel[(x+size-1,y+size-1,1)]
                score = fuel[(x,y,size)]
                if score > max_score:
                    max_score = score
                    max_point = [x,y,size]
    return max_point[0],max_point[1],max_point[2]


def day11():
    fuel = generate_table(1133)
    x,y = find_best(fuel)
    print("BEST POINT: %d,%d" % (x,y))
    x,y,size = find_best_any_size(fuel)
    print("BEST POINT ANY SIZE: %d,%d,%d" % (x,y,size))

if __name__ == "__main__":
    day11()

Día 12

El día 12 me trajo recuerdos de un algoritmo con el que me peleé mucho, el denominado HashLife. El problema es un autómata celular unidimensional. Las reglas vienen dadas como patrones. La única diferencia es que hay que guardar su posición para luego calcular un número. La primera parte es bastante sencilla.

import re
from collections import defaultdict

def read_file(file):
    rules = defaultdict(lambda: ".")
    rule_prog = re.compile("([.#]+) => ([.#])")
    with open(file) as f:
        lines = f.readlines()
    state = lines[0].split(": ")[1].strip()
    for line in lines[2:]:
        m = rule_prog.match(line.strip())
        rules[m.group(1)] = m.group(2)
    return state,rules

def parse_state(pots):
    state = dict()
    for i,p in enumerate(pots):
        state[i] = p
    return state

def find(rules,current):
    if current in rules:
        return rules[current]
    else:
        size = len(current)
        mid = size // 2
        left = find(rules,current[0:mid])
        right = find(rules,current[mid:])
        rules[current] = left + right
        return rules[current]


def iter(state,rules):
    new_state = dict()
    xmin = min(state.keys())
    xmax = max(state.keys())
    for x in range(xmin-2,xmax+3):
        current = ("%c%c%c%c%c" % (
                    state.get(x-2,"."),
                    state.get(x-1,"."),
                    state.get(x,"."),
                    state.get(x+1,"."),
                    state.get(x+2,".")
                    ))
        new = rules[current]
        if new == "#" or xmin &lt;= x &lt;= xmax:
            new_state[x] = new
    return new_state

def sum_pots(state):
    n = 0
    for pot in state:
        if state[pot] == "#":
            n += pot
    return n

def print_state(state):
    xmin = min(state.keys())
    xmax = max(state.keys())
    s = str("XMIN %d : " % xmin)
    for x in range(xmin-2,xmax+3):
        s += state.get(x,".")
    print(s)


def day12(file):
    state,rules = read_file(file)
    state = parse_state(state)
    for i in range(20):
        print_state(state)
        state = iter(state,rules)
    print_state(state)
    n = sum_pots(state)
    print(n)

if __name__ == "__main__":
    day12("input.txt")

La segunda parte nos pedía lo mismo pero para el número ¡50000000000! Inmediatamente pensé en optimizarlo de forma similar a HashLife. La idea consiste en almacenar patrones mayores a los de las reglas (que son todos de tamaño 5), para poder evitar cálculos innecesarios.Además añadí un recolector de basura para ir eliminando por la izquierda las celdas inútiles.

No obstante, y aunque es muchísimo más eficiente, sigue sin ser capaz de procesar tal bestialidad de número en un tiempo razonable.

Y he aquí lo que me ha cabreado, porque no he podido sacarlo. A partir de cierto momento, el dibujo siempre es el mismo pero desplazándose a la derecha. De modo que el valor del siguiente paso siempre es la suma de una constante. Finalmente modifiqué el código para que buscase una situación en la que el número fuese resultado de una suma de una constante. Una vez hecho eso, calcula con una multiplicación lo que valdría cuando llegase a 50000000000.

import re
from collections import defaultdict

XMIN = -2

def find(rules,current):
    if len(current) &lt; 5:
        return ""
    if current in rules:
        return rules[current]
    elif len(current) == 5:
        return "."
    else:
        size = len(current)
        left=find(rules,current[0:size-1])
        right=find(rules,current[size-5:])
        rules[current] = left+right
        return rules[current]

def read_file(file):
    rules = defaultdict(lambda: ".")
    rule_prog = re.compile("([.#]+) => ([.#])")
    with open(file) as f:
        lines = f.readlines()
    state = lines[0].split(": ")[1].strip()
    for line in lines[2:]:
        m = rule_prog.match(line.strip())
        rules[m.group(1)] = m.group(2)
    return state,rules


def print_state(state):
    print(state)

def sum_pots(state):
    n = 0
    for i,c in enumerate(state):
        if c == "#":
            n += i + XMIN
    return n

if __name__ == "__main__":
    state,rules = read_file("input.txt")
    XMAX = len(state)+1
    state = "..%s.." % state
    sums = list()
    i = 0
    while len(sums) &lt; 3 or sums[-1]-sums[-2] != sums[-2]-sums[-3]:
        state = find(rules,"..%s.." % state)
        if state[0] == "." and state[1] == "." and state[2] == "." and state[3] == ".":
            state = state[2:]
            XMIN += 2
        if state[0] == "#" or state[1] == "#":
            state = "..%s" % state
            XMIN -= 2
        if state[-1] == "#" or state[-2] == "#":
            state = "%s.." % state
        sums.append(sum_pots(state))
        i += 1
    diff = sums[-1]-sums[-2]
    missing = 50000000000 - i
    n = missing*diff + sums[-1]

    print(n)

Y con esto pude finalmente calcular el resultado.

Día 13

El día 13 teníamos unas vías de tren. En estas vías había unos trenecitos que se desplazaban siguiendo unas normas. El objetivo en la primera parte era conocer el donde se producía el primer choque.

from Pillow import Image

XMAX = 0
YMAX = 0
STEP = 0

nextDirection = dict()
nextDirection["start"] = "left"
nextDirection["left"] = "center"
nextDirection["center"] = "right"
nextDirection["right"] = "left"

def relative_direction(original,movement):
    print("CROSS")
    if movement == "center":
        return original
    if original == "v":
        if movement == "left":
            return ">"
        else:
            return "&lt;"
    elif original == ">":
        if movement == "left":
            return "^"
        else:
            return "v"
    elif original == "^":
        if movement == "left":
            return "&lt;"
        else:
            return ">"
    else:
        if movement == "left":
            return "v"
        else:
            return "^"

def day13(file):
    global XMAX
    global YMAX
    global STEP
    plano = dict()
    carts = list()
    with open(file) as f:
        lines = f.readlines()
    YMAX = len(lines)
    XMAX = len(lines[0])
    for y,line in enumerate(lines):
        for x,char in enumerate(line):
            # SI HAY UN CARRITO, DEDUCIR TIPO DE VIA
            if char == "^" or char == "v" or char == "&lt;" or char == ">":
                if (x,y-1) in plano:
                    plano[(x,y)] = "|"
                else:
                    plano[(x,y)] = "-"
                carts.append([x,y,char,"left"])
            else:
                plano[(x,y)] = char
    
    end = False
    while not end:
        carts.sort(key=lambda x: x[1])
        carts.sort(key=lambda x: x[0])

        for cart in carts:
            # CHECK CRASH
            for crt in carts:
                if cart[0] == crt[0] and cart[1] == crt[1] and id(cart) != id(crt):
                    print("CRASH AT %d-%d" % (cart[0],cart[1]))
                    end = True
            try:
                x = cart[0]
                y = cart[1]
                print(cart)
                if cart[2] == ">":
                    if plano[(x+1,y)] == "/":
                        cart[2] = "^"
                    elif plano[(x+1,y)] == "\\":
                        cart[2] = "v"
                    elif plano[(x+1,y)] == "+":
                        cart[2] = relative_direction(cart[2],cart[3])
                        cart[3] = nextDirection[cart[3]]
                    cart[0] += 1
                elif cart[2] == "&lt;":
                    if plano[(x-1,y)] == "/":
                        cart[2] = "v"
                    elif plano[(x-1,y)] == "\\":
                        cart[2] = "^"
                    elif plano[(x-1,y)] == "+":
                        cart[2] = relative_direction(cart[2],cart[3])
                        cart[3] = nextDirection[cart[3]]
                    cart[0] -= 1
                elif cart[2] == "^":
                    if plano[(x,y-1)] == "/":
                        cart[2] = ">"
                    elif plano[(x,y-1)] == "\\":
                        cart[2] = "&lt;"
                    elif plano[(x,y-1)] == "+":
                        cart[2] = relative_direction(cart[2],cart[3])
                        cart[3] = nextDirection[cart[3]]
                    cart[1] -= 1
                elif cart[2] == "v":
                    print()
                    if plano[(x,y+1)] == "/":
                        cart[2] = "&lt;"
                    elif plano[(x,y+1)] == "\\":
                        cart[2] = ">"
                    elif plano[(x,y+1)] == "+":
                        cart[2] = relative_direction(cart[2],cart[3])
                        cart[3] = nextDirection[cart[3]]
                    cart[1] += 1
            except:
                breakpoint()
        STEP += 1
        print_train(plano,carts)

def print_train(plano,carts):
    im = Image.new("RGB",(XMAX,YMAX))
    for x,y in plano:
        if plano[(x,y)] != " ":
            im.putpixel((x,y),(255,255,255))
        if plano[(x,y)] == "+":
            im.putpixel((x,y),(120,120,120))
    for cart in carts:
        if cart[2] == ">":
            im.putpixel((cart[0],cart[1]),(255,0,0))
        elif cart[2] == "&lt;":
            im.putpixel((cart[0],cart[1]),(0,255,0))
        elif cart[2] == "^":
            im.putpixel((cart[0],cart[1]),(0,0,255))
        else:
            im.putpixel((cart[0],cart[1]),(0,120,120))

    im.save("train-%d.png" % STEP,"PNG")

if __name__ == "__main__":
    day13("input_net.txt")

Para esta parte ya decidí usar Pillow para mostrar la salida. Esto fue muy útil para la depuración. Por lo demás, volví a usar un diccionario para guardar coordenadas. De hecho, no se guardan las casillas que no son vías. Las vías se guardan en ese diccionario y los carritos en una lista. El problema define que los trenecito que se mueven antes son los que están más arriba y en caso de empate, los que están más a la izquierda. Esto es muy sencillo de hacer en Python ya que la ordenación del método sort es estable, lo que quiere decir, que en caso de empate, se respeta el orden original. En cada trenecito se guarda su coordenada, su dirección (hacia el sitio donde se va a mover en el siguiente turno) y su estado para la elección de dirección en los cruces.

La segunda parte pedía que ante una situación de muchos trenecitos, ¿en qué posición quedaba el último carrito? Esto es algo más complicado. Aquí fui bastante tonto y cometí un error al borrar los carritos de la lista, que hacía que todo se estropease. La manera correcta de hacerlo es anotar en una lista que trenecitos hay que quitar y una vez haya finalizado la iteración se eliminan los trenecitos.

from Pillow import Image

XMAX = 0
YMAX = 0
STEP = 0

nextDirection = dict()
nextDirection["start"] = "left"
nextDirection["left"] = "center"
nextDirection["center"] = "right"
nextDirection["right"] = "left"

def relative_direction(original,movement):
    if movement == "center":
        return original
    if original == "v":
        if movement == "left":
            return ">"
        else:
            return "&lt;"
    elif original == ">":
        if movement == "left":
            return "^"
        else:
            return "v"
    elif original == "^":
        if movement == "left":
            return "&lt;"
        else:
            return ">"
    else:
        if movement == "left":
            return "v"
        else:
            return "^"

def day13(file):
    global XMAX
    global YMAX
    global STEP
    plano = dict()
    carts = list()
    with open(file) as f:
        lines = f.readlines()
    YMAX = len(lines)
    XMAX = len(lines[0])
    for y,line in enumerate(lines):
        for x,char in enumerate(line):
            # SI HAY UN CARRITO, DEDUCIR TIPO DE VIA
            if char == "^" or char == "v" or char == "&lt;" or char == ">":
                if (x,y-1) in plano:
                    plano[(x,y)] = "|"
                else:
                    plano[(x,y)] = "-"
                carts.append([x,y,char,"left"])
            else:
                plano[(x,y)] = char
    
    end = False
    while len(carts) != 1:
        carts.sort(key=lambda x: x[1])
        carts.sort(key=lambda x: x[0])  
        print_train(plano,carts)
        remove = list()
        i = 0
        while i &lt; len(carts):
            cart = carts[i]
            x = cart[0]
            y = cart[1]
            if cart[2] == ">":
                if plano[(x+1,y)] == "/":
                    cart[2] = "^"
                elif plano[(x+1,y)] == "\\":
                    cart[2] = "v"
                elif plano[(x+1,y)] == "+":
                    cart[2] = relative_direction(cart[2],cart[3])
                    cart[3] = nextDirection[cart[3]]
                cart[0] += 1
            elif cart[2] == "&lt;":
                if plano[(x-1,y)] == "/":
                    cart[2] = "v"
                elif plano[(x-1,y)] == "\\":
                    cart[2] = "^"
                elif plano[(x-1,y)] == "+":
                    cart[2] = relative_direction(cart[2],cart[3])
                    cart[3] = nextDirection[cart[3]]
                cart[0] -= 1
            elif cart[2] == "^":
                if plano[(x,y-1)] == "/":
                    cart[2] = ">"
                elif plano[(x,y-1)] == "\\":
                    cart[2] = "&lt;"
                elif plano[(x,y-1)] == "+":
                    cart[2] = relative_direction(cart[2],cart[3])
                    cart[3] = nextDirection[cart[3]]
                cart[1] -= 1
            elif cart[2] == "v":
                if plano[(x,y+1)] == "/":
                    cart[2] = "&lt;"
                elif plano[(x,y+1)] == "\\":
                    cart[2] = ">"
                elif plano[(x,y+1)] == "+":
                    cart[2] = relative_direction(cart[2],cart[3])
                    cart[3] = nextDirection[cart[3]]
                cart[1] += 1

            for crt in carts:
                if cart[0] == crt[0] and cart[1] == crt[1] and id(cart) != id(crt):
                    remove.append(cart)
                    remove.append(crt)
            i += 1

        for i in remove:
            carts.remove(i)
        STEP += 1
    print("Remaining cart at %d-%d" % (carts[0][0],carts[0][1]))

def print_train(plano,carts):
    im = Image.new("RGB",(XMAX,YMAX))
    for x,y in plano:
        if plano[(x,y)] != " ":
            im.putpixel((x,y),(255,255,255))
        if plano[(x,y)] == "+":
            im.putpixel((x,y),(120,120,120))
    for cart in carts:
        if cart[2] == ">":
            im.putpixel((cart[0],cart[1]),(255,0,0))
        elif cart[2] == "&lt;":
            im.putpixel((cart[0],cart[1]),(0,255,0))
        elif cart[2] == "^":
            im.putpixel((cart[0],cart[1]),(0,0,255))
        else:
            im.putpixel((cart[0],cart[1]),(0,120,120))

    im.save("train-%05d.png" % STEP,"PNG")
    #BUILD VIDEO
    #ffmpeg -framerate 10 -i 'train-%05d.png' -c:v libx264 -vf scale=1000x1000:flags=neighbor -r 30 -pix_fmt yuv420p train.mp4


if __name__ == "__main__":
    day13("input.txt")

Aprovechando las imágenes decidí generar una visualización de este problema. ¡Disfrutad los 20 minutos de puntitos moverse!

Día 14

El enunciado del día 14 es algo enrevesado pero básicamente se va generando una cadena de números ad infinitum. Tenemos que buscar los 10 elementos después de N posición. La solución de la parte 1 es bastante sencilla cuando se entiende el problema y se pueden usar sin problema listas normales de Python. En la parte 2 se pide lo contrario. Dado un patrón, encontrar la posición en la que aparece.

Aquí decidí usar la función find de str, que está optimizada para esto. No obstante, la cantidad es tan grande que no debemos comprobar todo si queremos que el programa acabe en un tiempo razonable. Para ello uso el argumento start y pido que solo busque entre los 10 últimos caracteres de la cadena. Tarde mucho en darme cuenta de esto y me desesperé bastante ya que no veía forma de optimizarlo más.

def day14(inp):
    recipes = list()
    recipes.append(3)
    recipes.append(7)

    a = len(recipes)-2
    b = len(recipes)-1

    while len(recipes) &lt; inp:
        #print("A: %d B: %d" % (a,b))
        #print(recipes)
        recipe = recipes[a]+recipes[b]
        recipe_a = recipe // 10
        recipe_b = recipe % 10
        if recipe_a != 0:
            recipes.append(recipe_a)
        recipes.append(recipe_b)
        a += recipes[a] +1
        b += recipes[b] +1
        a %= len(recipes)
        b %= len(recipes)

    k = len(recipes) - (len(recipes) - inp)

    for i in range(10):
        #print("A: %d B: %d" % (a,b))
        #print(recipes)
        recipe = recipes[a]+recipes[b]
        recipe_a = recipe // 10
        recipe_b = recipe % 10
        if recipe_a != 0:
            recipes.append(recipe_a)
        recipes.append(recipe_b)
        a += recipes[a] +1
        b += recipes[b] +1
        a %= len(recipes)
        b %= len(recipes)
    print(recipes[k:k+10])

def day14_reverse(inp):
    inp = str(inp)
    recipes = str()
    recipes += str(3)
    recipes += str(7)

    a = len(recipes)-2
    b = len(recipes)-1

    while True:
        recipe = int(recipes[a])+int(recipes[b])
        recipe_a = recipe // 10
        recipe_b = recipe % 10
        if recipe_a != 0:
            recipes += str(recipe_a)
        recipes += str(recipe_b)
        a += int(recipes[a]) +1
        b += int(recipes[b]) +1

        a %= len(recipes)
        b %= len(recipes)
        if recipes.find(inp,len(recipes)-10) > -1:
            break
    pos = recipes.find(inp)
    print(pos)

if __name__ == "__main__":
    day14(846021)
    day14_reverse(846021)

Conclusiones

Y con esto acabamos la segunda semana del Advnt of Code 2018. Estos problemas ya me están llevando mucho más tiempo y me estoy desesperando más con ellos. Lo que más rabia me da es que muchas cosas se me podrían haber ocurrido antes, ya que salvo el día 11, podía haber sabido perfectamente desde el principio la solución óptima.

La próxima semana los problemas serán más complicados y no estoy seguro de poder ofrecer mis soluciones a todos.

La entrada Advent of Code 2018: segunda semana se publicó primero en Adrianistán.

Sábado 15 de diciembre de 2018

Las mejores librerías gratuitas para gráficas en PHP

“Los datos son el nuevo petróleo” es algo que dicen muchas personas y que parece confirmarse si se leen noticias tecnológicas. Y en efecto, actualmente podemos generar una cantidad de datos inmensa de los que podemos extraer una información muy valiosa. Y ahí esta la clave, en “extraer”. Los datos como tal no sirven para nada. Al igual que el petróleo, no lo queremos en bruto, sino refinado, tratado. Con los datos pasa lo mismo. Para representar esta información desde hace muchos años estadística ha ido diseñando métodos para representar datos y extraer información de ellos.

Antiguamente estas gráficas se realizaban a mano y su creación era muy costosa. Hoy en día, como seguro que sabrás si sigues las noticias tecnológicas actuales, podemos usar herramientas para generar estas gráficas de forma sencilla, directamente en un servidor. En este artículo vamos a ver las mejores librerías para generar gráficas en PHP.

phpChart

La primera librería de la lista es phpChart. Se trata de una librería de pago, pero con muchas opciones para las gráficas. Desafortunadamente, solo las versiones más caras soportan gráficos que no sean de barras, de líneas y de sectores. La librería funciona generando código JavaScript para el cliente que le permite dibujar la gráfica usando Canvas. Esta gráfica es interactiva, pudiendo el usuario hacer zoom, cambiar de modo de gráfico y permitiendonos hacer animaciones.

pChart

Otra opción es generar imágenes para las gráficas en el servidor. Esto es precisamente lo que hace pChart. Originalmente era un mero wrapper sobre la librería estándar de gráficos de PHP (GD) para añadir anti-alising, pero con el tiempo se enfocó a las gráficas estadísticas. Sus principales cualidades son una gran calidad en las visualizaciones y un rendimiento óptimo. pChart es gratuita si nuestra aplicación es software libre y de pago si no lo es. Requiere las extensiones GD y FreeType para funcionar correctamente. pChart soporta gran cantidad de gráficas y es usado por empresas como Intel o Airbus e instituciones como la NASA y el CERN. La librería tiene capacidades interactivas, aunque algo más reducidas que otras soluciones.

JpGraph

Otra librería que permite renderizar en el servidor es JpGraph. Esta librería, gratuita para usos no-comerciales, está diseñada con orientación a objetos. Tiene una gran variedad de gráficas disponibles, de buena calidad y como ellos promocionan: ligeros. Existe una versión PRO con todavía más tipos de gráficos, aunque son bastante específicos y normalmente no harán falta. La librería necesita que GD esté instalado y es compatible con PHP7.

D3.js

Para acabar, una de mis personalmente favoritas, D3.js. D3 no es una librería para generar gráficas y tampoco es PHP. Se trata de una librería JavaScript con utilidades para los documentos basados en datos, la idea es incluir esta librería y usarla donde quieras mostrar las gráficas. La ventaja de D3 es que te permite hacer lo que quieras y tiene una gran comunidad. Es open-source, y aunque es algo más difícil de usar, genera unos resultados excelentes, usando SVG de por medio. De hecho, D3 no generará código visual, sino que nos ayudará a hacerlo nosotros mismos. He ahí la dificultad y a su vez, su gran flexibilidad.

La entrada Las mejores librerías gratuitas para gráficas en PHP se publicó primero en Adrianistán.

Emiliano A. González Salgado

Emiliano A. González Salgado
El blog de Emi

Proceso de migración de LibreOffice Base HSLQDB a LibreOffice Base Firebird

Unas notas sobre encontrado en el proceso de migración de 3 bases de datos.

Hay varias diferencias esenciales entre los dos SGDB.

El documento que describe las mismas es:

Migrating HSQLDB Base files to Firebird Base files, que se encuentra en: https://wiki.documentfoundation.org/Documentation/FirebirdMigration

Para comenzar hay que asegurarse que LibreOffice Base esté en modo HSLQDB.
Herramientas – Opciones – Avanzado – Activar funcionalidades expermientales (desactivado).

– Primero realizar una copia de la base que vamos a convertir, para trabajar con la copia, y dejar el original resguardado. Se le puede dar un nombre que no nos confunda, por ejemplo master_firebird.odb (dónde “master” es el nombre original de la misma.

– Editar todas las tablas, comprobando si tenemos campos “numéricos” o “decimales”. Caso de existir habría que cambiarlos por otro tipo de datos: “DOUBLE PRECISION”. Hay un bug, (que no ha sido aún corregido ni se sabe si va a implementar), que da errores en la conversión automática. La conversión, normalmente, no se puede hacer directamente por diferentes motivos.

– En caso de existir Vistas de Tablas habría que comprobar que la sintaxis se adapta a las nuevas características.
Ello se puede ver en el documento al que hice mención al principio.
La concatenación de campos solo puede hacerse un modo (‘str1’‖’str2’‖’str3’), extraer de una fecha el día de la semana, el año, el mes, el trimestre… no se realiza de la misma manera que hasta ahora. Y mas.

Si hay campos con datos decimales o numéricos, y están involucrados en Vistas de Tablas, no se pueden cambiar a DOUBLE con una instrucción SQL.

Las Vistas, una vez convertida la Base a Firebird no se pueden editar.

En mi caso me planteé cambiar las Vistas por consultas y evitar problemas.

La Vistas de Tablas, en Firebird, según mi opinión, existen por compatibilidad con versiones anteriores.

En Firebird se pueden crear vistas, en el modo de edicción de consultas, pero no se pueden modificar. No se puede acceder a la edición SQL, en la edición normal sale un editor, igual que el de tablas, en el que no se puede realizar ninguna operación.

Por ello he prescindido de las Vistas y he realizado unas consultas idénticas a las mismas, y con los mismos nombres.

He creado unas consultas, idénticas a las Vistas, He rectificado el resto de consultas. cambiando las que tuvieran origen en las Vistas, por su respectiva consulta. Si por ejemplo, tengo una Vista vMovimientos, he creado la consulta vMovimientos.

He creado unas consultas copiando la intrucción SQL de las vistas, les he puesto un nombre cualquiera. Una vez creadas todas, he eliminado las vistas y he cambiado el normbre de las consultas al que tenían anteriormente las vistas.

– Hay que tener precaución con el número de caracteres que tiene el nombre de una tabla, una consulta o una vista, al igual que el de los campos. El máximo número de dígitos que permite Firebird son 30 caracteres. En HSLQDB creo que eran 50. El error salta al ejecutar la consulta.

– Los nombres de la tablas y de los campos, incluidas las consultas, no deben incluir ciertos caracteres. quienes hablamaos español no podemos usar la “Ñ”. Me pasó con un campo que era Año. Tuve que cambiarlo por Anualidad.

– Una forma rápida de cambiar los campos númericos o decimales a DOUBLE es con una instrucción SQL (siempre que el campo no esté involucrado en una Vista de Tabla)

La instrucción es la siguiente: ALTER TABLE “NombreTabla” ALTER COLUMN “NombreCampo” DOUBLE

Dónde NombreTabla es el nombre de la tabla, NombreCampo es el de la columna y DOUBLE es el tipo de datos que quiero ponerle.

Firebird es mas estricto en la comprobación de las consultas que HSQLDB. Puede que alguna no funciones después de la conversión, arrojando error. Ya sería menos laborioso modificar las que den error.

Precaución y suerte.

Un saludo,
Emiliano.

Manual/Guia: Como instalar archivos .obb para APK´s de smartphones

El manual más completo para aprender sobre cada tipo de archivo (apk y obb). También vamos a ver como activar y permitirlos en nuestro móvil android para poder tener juegos y aplicaciones gratis. ¿Para qué son los archivos APK? Estos archivos que tienen la extensión .apk son los que nos sirven para instalar un programa o app […]

La entrada Manual/Guia: Como instalar archivos .obb para APK´s de smartphones aparece primero en Blog de Informática ✏ Luisi.

Instalar OpenVPN en 5 minutos

Vamos a instalar esta VPN (Virtual Private Network). Que en español sería: Red Virtual Privada. Lo haremos en Ubuntu pero el procedimiento es el mismo para Debian. Incluso puedes instalarlo en una Raspberry Pi. Si no tenemos esos sistemas operativos, podemos instalar Linux en Windows 10 y seguir este tutorial. Será todo por terminal. Pero no necesitas […]

La entrada Instalar OpenVPN en 5 minutos aparece primero en Blog de Informática ✏ Luisi.

Viernes 14 de diciembre de 2018

Instalar Ubuntu, Debian, SUSE o Kali en Windows 10

Windows y Linux. Se suele decir que son las dos caras de una misma moneda. Tan diferentes entre ellos pero a la vez tienen la misma base y les damos el mismo uso. Ser nuestro sistema operativo. Hoy vamos a ver como instalar distintos sistemas operativos Linux, como son Ubuntu, Debian, Kali Linux o openSUSE en […]

La entrada Instalar Ubuntu, Debian, SUSE o Kali en Windows 10 aparece primero en Blog de Informática ✏ Luisi.

Jueves 13 de diciembre de 2018

Ubuntizando.com

Ubuntizando.com
Ubuntizando.com

Calamares busca traductores

Muchas veces no nos damos cuenta de todo el trabajo que hay detrás y lo mucho que tenemos que agradecer a los instaladores gráficos por hacernos la vida más fácil. Desde KDE en redes sociales acaban de hacer un llamamiento para buscar traductores para Calamares.

Aunque el nombre nos recuerda el veranito en la playa Calamares es un instalador gráfico universal que guía a los usuarios a través de la instalación de sistemas operativos como Manjaro, KDE neon, Netrunner y muchos más. Actualmente se encuentra localizado a 59 idiomas diferentes que necesitan voluntarios para su mantenimiento entre versión y versión. Como siempre suelo aconsejar si quieres colaborar en proyectos relacionados con el mundo del software libre y lo tuyo no es la programación una buena forma de comenzar es ayudando en materia de traducción, a fin de cuenta el lenguaje que usamos normalmente para comunicarnos es en realidad el lenguaje de programación más complejo 😉

Más info: https://calamares.io/calamares-seeking-translators/

Miércoles 12 de diciembre de 2018

Emiliano A. González Salgado

Emiliano A. González Salgado
El blog de Emi

Migración a LibreOffice Base Firebird.

Hace poco publiqué en el blog un artículo sobre la migración a LibreOffice 6.1 beta:
https://emilianoangel.wordpress.com/2018/06/05/migracion-a-libreoffice-6-1-base/

Tras hacer pruebas y demás tuve que dejar el cambio a la nueva versión de la base de datos, pues había algunos bug.

El problema mas importante que he encontrado ha sido por la conversión de campos numéricos y decimales de la versión de HSLQDB a Firebird.

Hay un bug que aún no ha sido resuelto.

Todo esto hacerlo con HSLQDB, antes de abrir la base a convertir con Firebird.

La solución es cambiar los campos “numéricos” o “decimales” a “DOUBLE PRECISION”.

Desde el editor de tablas, no se puede. Con instrucciones SQL, tampoco. Parece ser que en este tipo de campos no está permitida tal acción.

Solución, crear una nueva tabla, copiando la que se quiera modificar, pegar y en el proceso de pegado, cambiar los datos de los campos a DOUBLE PRECISION.

Siempre, en el pegado, aceptar la primera opción: “Definición y datos”.

Posteriormente hay que cambiar las posible vistas de tablas y las consultas, con los datos de la nueva tabla.

Una opción es en edición SQL, usando un editor de texto, con la opción de buscar y reemplazar.

Error que mostraba una consulta:

firebird_sdbc error:
*Dynamic SQL Error
*SQL error code = -104
*Invalid expression in the HAVING clause (neither an aggregate function nor a part of the GROUP BY clause)
caused by
‘isc_dsql_prepare’

Si la consulta se realiza tomando como criterio de agrupación el campo de una tabla, que sólo tiene una fila, muestra error. Es el ejemplo que sigue:

GROUP BY “Cuentas”.”cuenta” HAVING ( ( “Cuentas”.”cuenta” = “Parametros”.”cuenta” ) )

En cambio si pongo directamente el criterio no da errores.

GROUP BY “Cuentas”.”cuenta” HAVING ( ( “Cuentas”.”cuenta” = ‘DB Plus’ ) )

Para pedir los datos de los informes utilizo un formulario, que rellena la Tabla “Parametros”, sobrescribiendo los antiguos.

Solución. Relacionar “Cuentas.cuenta” con “Parametros.cuenta”. Solo en modo diseño de la consulta. En la columna problemática eliminar el criterio y activar, en Función: Agrupar por. En la SQL Sólo muestra el GROUP BY y desparece el HAVING. Por ahora vamos sorteando los obstaculos para usar Firebird.
Otro error era debido al nombre de una consulta. Tenía 40 caracteres. Se la ejecutaba directamente pues funcionaba como cualquier otra.
Pero si era origen de otra consulta ya mostraba un error. Decía que había un campo mas largo de la cuenta y no lo permitía.
Parece ser que HSQLDB permite hasta 50 caracteres como nombre de un campo o una tabla en la instrucción, pero Firebird lo máximo que permite son 30.
Se acortó el nombre, que era tan largo por un despiste, y arreglado el asunto.

Si hay formularios también habría que cambiar el origen de tablas de los mismos.

Si hay una columna tanto en tablas, como vistas o consultas con caracteres extraños, había de cambiarlas.

El problema se presentó con una que era “año”. La “Ñ” no la acepta, por ahora.

Si la base de datos no se compone de muchas tablas con datos problemáticos y muchas consultas que estén involucradas, pues es algo rápido, pero que hay que tener paciencia.

Enlaces interesantes:

https://wiki.documentfoundation.org/Documentation/FirebirdMigration

https://wiki.documentfoundation.org/Development/Base/FirebirdSQL

https://wiki.documentfoundation.org/Faq/Base

https://wastack.wordpress.com/

BlogDRAKE: AVISO:Firefox 64 requiere lib(64)atomic1

OpenSnitch, mantén tu Linux seguro con un Firewall

p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px 'Helvetica Neue'; color: #000000; -webkit-text-stroke: #000000} p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px 'Helvetica Neue'; color: #000000; -webkit-text-stroke: #000000; min-height: 12.0px} span.s1 {font-kerning: none} Cuando hablamos de seguridad informática, todos pensamos enseguida que estamos protegidos totalmente

Lunes 10 de diciembre de 2018

Gaspar Fernández

Gaspar Fernández
Poesía Binaria

Cómo actualizar /etc/hosts con todos los contenedores docker que hay en ejecución

Si tenemos varios contenedores docker arrancados en nuestro ordenador. Muchas veces, nos interesará conectar con servicios corriendo dentro de cada uno de ellos. Algunos estarán lanzados simplemente con docker, otros con docker-compose, cada uno trabajando en un sistema distinto, y necesitamos una forma más o menos sencilla de acceder a cada uno de ellos.

Con un pequeño script podemos recorrer todos los contenedores, pedir la dirección IP de cada uno de ellos y añadirlas al nuestro archivo /etc/hosts de forma que este archivo se actualice automáticamente cada vez que lanzamos el comando.

El script

Yo lo suelo llamar docker_update_hosts.sh, y suele estar en /usr/local/bin. En realidad, es un enlace el que está ahí:

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
#!/bin/bash

function panic()
{
    echo "$@" >&2
    exit 1
}

if [ "`whoami`" != "root" ]
then
    panic "This program must be ran as root"
fi

# Clear /etc/hosts file
HEADER="# Added automatically by docker_update_hosts"
sed -i '/docker\.local$/d' /etc/hosts
sed -i "/$HEADER\$/d" /etc/hosts
# Remove empty lines at the end of file
sed -i  -e :a -e '/^\n*$/{$d;N;ba' -e '}' /etc/hosts

echo -e "\n$HEADER" >> /etc/hosts

IFS=$'\n' && ALLHOSTS=($( docker ps --format '{{.ID}} {{.Names}}'))

for line in ${ALLHOSTS[*]}; do
    IFS=" " read  -r ID NAME <<< "$line"
    IP="$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' $ID)"
    if [ -n "$IP" ]; then
        echo -e "$IP\t$NAME.docker.local" >> /etc/hosts
    fi
done

El script debe ser ejecutado como root, porque tiene que tener permiso para escribir en /etc/hosts. Para ello, en muchas distribuciones lo podremos ejecutar así:

sudo docker_update_hosts

Hosts

El script creará varios hosts llamados [contenedor].docker.local donde contenedor es el nombre de cada uno de nuestros contenedores. Al final, nos podremos juntar con algo como:

172.17.0.8 myphp5.6-fpm.docker.local
172.17.0.7 mongodb-testing.docker.local
172.17.0.6 wp-plugin-test.docker.local
172.17.0.5 myphp7.2-fpm.docker.local
172.17.0.4 mariadb-proyectos.docker.local
172.17.0.3 mariadb-testing.docker.local
172.17.0.2 redis.docker.local

De esta forma, podremos utilizar el nombre que le hemos dado en docker junto con “.docker.local” para referirnos al contenedor y llamar a un servicio encerrado en el mismo. Por ejemplo, para conectar con la base de datos mariadb-proyectos.docker.local podemos, desde el mismo ordenador host:

mysql -u root -p -h mariadb-proyectos.docker.local

Precauciones

Ya que el script está editando el archivo /etc/hosts y ese mismo fichero puede ser editable por nosotros, el script escribe un comentario:

1
# Added automatically by docker_update_hosts

Y debajo se escriben todos los hosts e IPs de contenedores docker que encontremos. Automáticamente, nada más ejecutar el script se busca el comentario y se buscan todos los hosts que terminen en .docker.local, por lo que si tenemos otras cosas que terminen en .docker.local serán eliminadas cuando se ejecute el script.

No tenemos que tener especial cuidado cuando editemos el fichero /etc/hosts manualmente. Podremos meter hosts nuevos al final, o encima de los hosts introducidos por el script y se respetarán.

Ejecutar automáticamente

Dependiendo de nuestra forma de trabajar, podemos ejecutar el script a mano siempre que sea necesario, ejecutarlo dentro de un script para lanzar contenedores o podemos ejecutarlo en un cron cada 10 minutos, por ejemplo.

Foto principal: unsplash-logoSherzod Max

The post Cómo actualizar /etc/hosts con todos los contenedores docker que hay en ejecución appeared first on Poesía Binaria.

Lunes 03 de diciembre de 2018

Liher Sanchez

Liher Sanchez
El blog de Liher

Como saber o listar los Kernels que tengo en Ubuntu y cual estoy usando

Una de las cosas que mas me preocupa cuando estoy usando mi ordenador es tener el sistema bien limpio, tanto por fuera como por dentro. No me gusta tener la papelera llena de archivos, es una costumbre que tengo desde hace años, siempre vacío la papelera cuando voy a apagar el ordenador ya que así ahorro espacio en el disco duro. También me gusta eliminar los instalables de los programas ya que una vez instalado el programa el archivo instalador no me sirve para nada, aunque tengo algunos guardados que considero importantes, pero son muy pocos. Otra de las cosas que me gusta hacer es eliminar los Kernels que ya no uso por la sencilla razón de que no me sirven, con guardar el que esta en uso y el anterior pienso que es suficiente. Antes, para eliminar los Kernels que no usaba utilizaba una herramienta de un programa llamado Ubuntu Tweak, pero por desgracia es un proyecto descontinuado y ya no se puede instalar en mi Linux Mint 19. Ahora, para eliminar los Kernels en Ubuntu o Linux Mint sin uso lo hago de otra forma que ya os mostraré en otro artículo. En este lo que os voy a mostrar es como saber y listar los Kernels que tenéis en vuestro Ubuntu o derivadas y cual es el que estáis usando actualmente.

Quizás para las capacidades de almacenamiento que tienen hoy en día los discos duros este ahorro de espacio no sea muy grande pero el quitar cosas que ya no uso del ordenador es una costumbre que adquirí con mi primer ordenador ya que tenia unas prestaciones muy limitadas, en concreto tenia 43 MB de disco duro. Llegué incluso a comprimir todo el disco duro y eso lo convertía en un HD de 73 MB, que seguía sin ser suficiente pero ya era algo mas. Bueno vamos al lío. Si queremos saber y listar todos los Kernels que tenéis en vuestro ordenador lo que tenéis que hacer es abrir una Terminal y escribir el siguiente comando:

dpkg -l | grep linux-image

Al teclear este comando podréis ver algo similar a esto:

 

listar o saber los kernels de ubuntu

 

Como podéis ver en la imagen tengo 4 versiones del Kernel instalados en mi ordenador. Normalmente no suelo tener tantas pero no he borrado todavía los Kernels sin uso para tenerlos y mostrar como eliminarlos en otro artículo. En condiciones normales el Kernel que está en uso es el mas reciente como nos indican los números de versión, cuanto mas alto sea el numero, mas reciente será.

Ahora vamos con lo siguiente, como saber cual es el Kernel que estamos usando ahora mismo. Esto lo podemos saber de varias formas, yo os voy a mostrar dos bastante sencillas y que os darán la información que necesitáis. Para ello, en la Terminal, escribís este comando:

uname -a

O bien:

uname -r

Lo que veréis en la Terminal al introducir estos dos comandos es lo siguiente:

 

kernel en uso en Ubuntu

 

En la imagen podéis ver la información que obtenemos con cada uno de los comandos. Con el segundo comando la información es mas escueta, como podéis ver, aunque es suficiente. Y si queréis una información mas completa tenéis el primer comando.

Y ya está, eso es todo, con lo que os he mostrado ya poder saber y listar los Kernels que tenéis en vuestro Ubuntu o derivadas y también cual es la versión del Kernel que tenéis en uso. Un saludo a todos.

Liher Sanchez

Liher Sanchez
El blog de Liher

5 maneras fáciles y confiables de ganar dinero en línea

Gracias a Internet, ahora hay una gran variedad de formas de hacer dinero en línea. Ya sea que estés buscando maneras de ganar un poco de dinero extra, o crear un flujo de ingresos de tiempo completo, hay muchas oportunidades para hacerlo, todo en línea y desde la comodidad de tu hogar.

Aquí os dejo 5 de las mejores maneras de ganar dinero en línea que pueden definitivamente hacer que crees tu trabajo ideal, seas tu propio jefe y trabajes de manera independiente en tu propio horario y desde tu propio espacio.

1 – Podcasting

Una de las formas más creativas de ganar dinero en línea es alojar un podcast en línea. La clave para avanzar con el podcasting es encontrar tu nicho, hacer crecer una audiencia y luego encontrar formas de monetizar y conectarte con los patrocinadores. Esta no es, quizás, la forma más fácil de ganar dinero en línea, ya que requiere una gran cantidad de logística que debes escribir, grabar y editar para lograr un podcast de calidad, pero vale la pena considerarlo, especialmente si posees eres un comunicador nato.

2 – Venta de libros

Si bien la industria editorial solía tener una gran cantidad de documentos impresos, puedes completar todo el proceso de escribir, publicar y comercializar un libro en línea en estos días sin muchas complicaciones. Los sitios web como “Create Space” te permitirán cargar y llevar tu libro a impresión sin involucrar a un editor formal, e incluso puedes incluir tu libro en Amazon.com que, como sabes, es la plataforma ideal para vender un libro. Si crees que tienes las habilidades para escribir y que podrías escribir un libro que la gente quiera comprar, esta es una estrategia inteligente a considerar, ya que los costos iniciales pueden ser mínimos y probablemente ya tengas una computadora y un software de procesamiento de textos.

3 – Publicaciones patrocinadas

Si tienes un sitio web o un gran número de redes sociales, también puedes ganar dinero buscando publicaciones y anuncios patrocinados. ¿Pero, cómo funciona esto? Básicamente, las empresas están dispuestas a pagar a los bloggers y personas influyentes en las redes sociales por promover sus productos y servicios. Si tienes una plataforma, ya sea un blog o una gran cuenta de Instagram, puedes cobrar. Hay bloggers con reputación que obtienen hasta $ 20,000 dólares por una publicación patrocinada. Aunque creas que es exagerado, no lo es, y esto sirve para mostrar lo que es posible lograr con las publicaciones patrocinadas. Sin embargo, ten en cuenta que no necesitas un sitio web para hacer contenido patrocinado, ya que también puedes recibir un pago si tienes muchos seguidores en las redes sociales. Si tienes una gran cantidad de seguidores en Instagram, puedes obtener todo tipo de patrocinios. No solo puedes lograr pagos en efectivo, sino que también puedes recibir muchas cosas gratis.

4 – Seminarios web

¿Necesitas más ideas sobre cómo hacer dinero en línea? Otra estrategia es utilizar seminarios web para comercializar tu producto, servicio o curso. Con un seminario web, básicamente estás ofreciendo muchos consejos y sugerencias de forma gratuita, generalmente en un formato en vivo. Sin embargo, al final, estas lanzando tu producto o servicio pagado con el objetivo de asegurar algunas ofertas. El orador profesional Grant Baldwin, por ejemplo, utiliza seminarios web para promocionar sus cursos sobre oratoria pública. Si bien Baldwin ofrece muchos consejos gratuitos durante su seminario web, ofrece su curso al final para que las personas que quieran pagar obtengan más información. Y, definitivamente, este argumento de venta, funciona.

5 – YouTube

YouTube es otra plataforma que ha hecho posible que las personas ganen dinero en línea. Hay un montón de canales de YouTube por ahí sobre cualquier tema, y la mayoría de las personas con muchos seguidores están ganando algo de dinero a cambio de sus videos y tiempo. El año pasado, Forbes presentó a algunos de los youtubers más grandes en la escena de YouTube. Según el estudio, las diez estrellas de YouTube con mayor recaudación recolectaron $ 127 millones desde junio de 2016 hasta junio de 2017. El más popular, es un jugador llamado DanTDM, que ganó $ 16.5 millones en un año como youtuber. ¿Ganarás tanto? Probablemente no. Sin embargo, puede comenzar a ganar dinero a través de YouTube utilizando la propia red de anuncios de la plataforma u obteniendo publicaciones patrocinadas. Si te gusta hacer videos, comenzar un canal de YouTube puede ser una forma divertida de ganar algo de dinero de manera adicional.

Como ves, hay una gran cantidad de formas de hacer dinero en línea y las que te expongo aquí son solo la punta del iceberg. Si tienes tiempo, pasión por casi cualquier cosa, y al menos alguna habilidad creativa, puedes crear un flujo de ingresos en línea, o varios, si tienes suficiente tiempo. Pero, no solo tomes mi palabra, si miras en línea, encontrarás miles de historias exitosas que pueden inspirarte de gente que se atrevió a enfocarse en trabajar en línea y lograr la estabilidad económica soñada, además del trabajo ideal.

Gaspar Fernández

Gaspar Fernández
Poesía Binaria

Crear redirecciones en Apache en función de una cookie

Servidor de pruebas

En estos días que asusta leer la palabra cookie en cualquier sitio. Si nos remontamos al siglo pasado, los navegadores solían preguntarnos cada vez que iban a a definir una cookie para ver si aceptábamos o no. Cosa que se terminó volviendo insostenible ya que los sitios web definían varias cookies y empotraban contenido de otros sitios que querían definir cookies y terminábamos con unas diez ventanas emergentes cada vez que entrábamos en una web. Así que, bloqueabas todas, pero las webs no funcionaban bien, y terminabas resignándote y aceptando todo.

Aunque hoy vamos a tratar un tema diferente, vamos a darles a las cookies una utilidad extra. Aunque bien podemos conseguir el mismo efecto con un lenguaje de aplicación (Java, PHP, Python, etc), vamos a hacer que sea el mismo servidor web, en este caso Apache el que aplique una redirección en función del valor que tenga una cookie que nos manda el usuario y, un paso más, que sea transparente para él.

¿Para qué queremos esto?

Podemos utilizar esta técnica para tests A/B, para probar dos versiones de la web. Aunque vamonos a un caso extremo, pero real. Imaginemos que tenemos una versión antigua de la web, programada con versiones antiguas de un lenguaje de programación y también una versión nueva programada con versiones nuevas, bibliotecas nuevas, etc, de modo que esas dos versiones no pueden estar en la misma máquina (física o virtual), de modo que tendríamos que acceder a un punto de entrada nuevo y diferente.

También podemos hacer un acceso a un entorno de pruebas de la web, de modo que los desarrolladores puedan entrar a él, o incluso el cliente final, mientras no impedimos el acceso a los usuarios a la plataforma, haciendo que, el código sea diferente, las bases de datos sean diferentes, incluso las posibilidades de cargarnos algo también. Muchos desarrollos pueden estar pensadas para realizar pruebas, pero pensemos en plataformas como WordPress, que por unas cosas o por otras, en las que no voy a entrar, si cambiamos el host, con muchos plugins o temas podemos tener problemas.

Y, ¿qué tal el dar una seguridad extra a nuestras aplicaciones? De forma que solo alguien que tenga la cookie pueda entrar en un área privada en donde podrá trastear con muchas cosas peligrosas de su servidor adicionalmente a tener usuario y contraseña.

En muchos casos seguro que nos puede ser útil hacer una redirección en función de la dirección IP desde la que viene la petición, aunque en otros casos, tanto por el número de equipos que tienen que tener acceso como por el hecho de tener IPs dinámicas, no es posible.

Vamos a ver Apache

Para lograr esto, entramos en el VirtualHost de Apache y escribimos lo siguiente:

1
2
3
4
5
6
        ProxyPreserveHost On
        RewriteEngine On

        RewriteCond %{HTTP_COOKIE}     nombre_de_cookie=([^;]+)
        RewriteCond %1                 ^valor_de_cookie$
        RewriteRule         ^/(.*) http://otro_host/$1 [P,L]

En este caso, con la directiva P para conectar vía proxy y L para que no se procesen más reglas de reescritura tras esta. Es necesario también tener los módulos rewrite y mod_proxy_http instalados por lo que antes de nada no está de más ejecutar:

sudo a2enmod rewrite
sudo a2enmod proxy_http
sudo service apache2 restart

Veamos un ejemplo completo, podemos ver este archivo de VirtualHost (lo he puesto todo en HTTP, en el mundo real deberíamos utilizar todos HTTPs):

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
<VirtualHost *:80>
        ServerName miweb.com
        ServerAlias www.miweb.com

        ServerAdmin security@miweb.com
        DocumentRoot /var/www/miweb.com/www
        ProxyPreserveHost On
        RewriteEngine On

        RewriteCond %{HTTP_COOKIE}     magicCookie=([^;]+)
        RewriteCond %1                 ^123456$
        RewriteRule         ^/(.*) http://10.0.1.198/$1 [P,L]

       <Directory /var/www/miweb.com/www/ >
                Options -Indexes +FollowSymLinks +MultiViews
                AllowOverride All
                Require all granted
        </Directory>

        ErrorLog ${APACHE_LOG_DIR}/error.log

        LogLevel warn

        CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

En este caso, cuando entra un visitante normal, entrará directamente a la web alojada en este servidor. Web que está en /var/www/miweb.com/www, pero si viene un visitante que tenga la cookie magicCookie establecida y cuyo valor sea 123456, internamente la petición se redirigirá al 10.0.1.198, que es una IP privada que está en la misma red que el servidor y a la que normalmente los usuarios no tendrían acceso. Esta nueva dirección puede pertenecer a una máquina de la misma red, una máquina conectada a Internet, máquinas virtuales o incluso contenedores docker.

Vamos a probarlo

Para realizar pruebas, podemos crear un pequeño programa que defina la cookie en cuestión, por ejemplo, en PHP podríamos hacer algo así:

1
2
3
<?php

setcookie('magicCookie', '123456');

Solo tenemos que llamar a este archivo php desde el navegador y cuando volvamos a nuestro dominio se realizará la redirección interna.

También podemos utilizar una extensión de Chrome o Chromium llamada Cookie Inspector. Solo tenemos que activar las herramientas para desarrolladores y nos dejará establecer y modificar cookies.

Foto principal: unsplash-logoLouis Reed

The post Crear redirecciones en Apache en función de una cookie appeared first on Poesía Binaria.

Domingo 02 de diciembre de 2018

OrbitalApps, ejecutar aplicaciones en Linux sin instalarlas

p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px 'Helvetica Neue'; color: #000000; -webkit-text-stroke: #000000} p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px 'Helvetica Neue'; color: #000000; -webkit-text-stroke: #000000; min-height: 12.0px} span.s1 {font-kerning: none} span.s2 {text-decoration: underline ; font-kerning: none} Son muchas las ocaciones en las que

Martes 27 de noviembre de 2018

Ramón Miranda

Ramón Miranda
Ramón Miranda

A new dawn, alegory . The Making off


Hi all, today I am going to show you my latest painting done in Krita 4.0 while i was collaborating to provide resources like brushes, brushtips, and patterns.
I think Krita deserves a good promotional images (at least finished images) and this was also a good testing canvas for that. My 2 cents ;)
This image reflects the emotional state that makes me feel this new release. So here you have...
"A new dawn, alegory" i hope you like it.



The process. (click on the images to see big-res images)

Step 01. First i start with the background, the mood itself of the image. I focus my attention on color and overall emotion. You can see there is no texture but i define where the figure must be placed.

Step 02. Then i continue working with brushes and wet paint.Here i am testing how to get the Oil or at least the painterly effect on some brushtrokes and i remove some coldness on the background. I start to add a bit of glow, this is an easy way to get more corlors to play with. Also you can see some primitive structures on the BG.

Step 03. I feel i need more color, why not! and i start to define better the path of viewers eye. I use very often the contrast to catch the attention. You can see a lot of brushtrokes , some are from 3.3 brushes and others are testing brushes for 4.0. Not too much detail here but i feel i like the red color and movement on clothes

Step 04. After some crazyness, lot of fun and exploration, is time to define a bit the image, the message and planes. You can see now arcs, rocks and a more defined pose for the woman. But at the moment i have only big spots of color.

Step 05. Time for block stage defining more and more.  

Step 06. I sketch a better figure in paper with pen, I love strong characters and strong women so i decide to give her a powerful pose, dominant but a bit humble holding her clothes with bare hands.


Step 07. I change the scale of figure to emphasize the environment and movement on the folds. Now you can see the folds and better idea o what the final image is going to be.

Step 08. Is time to detail a bit more all the scene. Structures on background, the ruins in midplane, the ground, adding a bit of texture and the main arc in the foreground with the woman in focal point. The folds are well stablished and is time to see if everything works. I am not sure with the arm pose so i delete it for the moment.

Step 09. I redefine a bit the mood, to be not so pictoric but more actual looking. I focus my attention on bg and add glow to the gate, wich is the symbol of "how krita is seeing a new light and how reborns from the ruins. (you know the history) I block the main shapes of arm and detail lot of parts.

Step 10. So... what i miss oh yes! more details ;) . I left this image posted because you can see how i use temporary swatches (in this case for the folds) you can see also this for the hair and how the strands starts to appear more realistic.

Step 11. And now a dramatic light change because the lighting was not coherent. Final details in hair, texture, folds, folliage, and fx. All done with krita 4 brushes.

I  hope you enjoy this new release as I do. Remember Krita it can be amazing but you are the artist.
If you have qustions or want to know more about my work, check my social media.



Miércoles 21 de noviembre de 2018

BlogDRAKE: clipgrab, mixxx, telegram y selene en el Repositorio BlogDrake

Lunes 19 de noviembre de 2018

Esta de moda odiar a PHP

A ver PHP no es el mejor invento de la humanidad, pero tampoco lo ha inventado Microsoft.

Pero esta de moda odiar a PHP. Y que os voy a decir si yo le tengo un poco de cariño, es como ese viejo amigo que tiene sus cosas pero que os lleváis bien.

Os voy a contar mi historia con PHP y porque le tengo cariño y no sigo la moda de odiarlo.

Os cuento corría los 2000, creo que los 2002, en aquellos tiempos ya tenía alguna página (mi vieja linuxtopower) personal hecha con html, iframes y demás aparataje de esas épocas…hay gente que siente vergüenza por sus pintas 15 o 20 años atrás, pero al igual que contados casos de “fashion influencers” no se nos iba a ocurrir hacer una web limpia y clara rollo google en su inicio (porque cada vez es más Yahoo) y menos aún pensar en diseño para smart phones si aún ni existían.

Pero claro os recuerdo que aquellas páginas personales, eran estáticas cuál foto fija en el tiempo (con gigs molona), la única manera de actualizarlas era por medio de ftp, en el mejor de los casos si tenía el webhosting gratuito…éramos jóvenes sin dinero y en el peor un panel web ftp cutre muy cutre…pero que eso si, facilitaba mucho la vida cuando querías cambiar algo en un pc de un instituto, Universidad o cyber que tuviera los puertos capados…porque era un lujo tener Internet en casa.

Las webs eran tan estáticas que la única forma de interactuar con los visitantes era tener el típico contador de visitas gratuito (de otro lado y que solía venir con su correspondientes scripts para soltar banners y popups). Y el otro medio era el típico también libro de visitas que te lo ofrecía o el webhosting o enganchabas con un iframe de otro lado…con si correspondientes anuncios.

¡Y llegó PHP! Pero eran otros tiempos, ahora te dan contenedores y máquinas virtuales de un cupón en las cajas de los cereales. Recuerdo el primer webhosting que daba soporte para PHP gratuito era un tal H2O o algo así.

Y con el PHP llegó la locura de PHPnuke o PostNuke barrocos CMS (¿Seguirán los proyectos vivos?) que todo dios instalaba, instalando todo para al final aprender que la tecnología no soluciona los problemas, porque ponías un PHPnuke de la comunidad heavy de tu pueblo y pasado los meses eso seguía siendo un desierto. Si, ahí descubres lo difícil que es mantener una comunidad.

En aquellos tiempos, si querías hacer una web “dinámica” tenías pocas opciones:

  • Perl, la web de barrapunto está hecha con Perl. Yo he trabajado con Perl y es un horror de lenguaje, con sus sigil que te vuelves loco para desreferenciar una variable dentro de una función. Creo que en aquellos tiempos no había webhostings gratuitos que dieran soporte a Perl.
  • Java, lo tuve que aprender por obligación en la universidad, otro crimen. Primero que el aquellos tiempos todavía Java no era libre (y ahora no lo se) que para hacer algo sencillo tenías que montar un pifostio bien gordo con los servlets y compilarlo. Y otro que no me oli si existió algún webhosting gratuito.
  • PHP, que pienso yo, creo que la killer feature de el fue lo de poder limitar el tiempo de ejecución, la memoria RAM y alguna cosa más, y es lo que hizo que centenares de webhostings gratuitos florecieran porque no era peligroso ofrecer PHP.

Después curre muchos años con PHP, disfrute mucho, y el mundo siguió dando vueltas.

Y en esas estamos ahora está de moda odiar PHP porque:

  • Ha habido mucho manazas que ha hecho guarradas dignas de pasar por juez de la Audiencia Nazional. Si alguna vez joven informático/a te ofrecen un currito fácil y mal pagado de una web en PHP hecha por muchas manos…¡¡Huyeeee!!…porque te encontrarás un servidor con código vomitado de una persona que comió mierda de otro que a su vez era de otro y otro y otro así hasta la versión 2 PHP.
  • Tampoco es que PHP lo haya hecho bien, famoso es el artículo PHP: a fractal of bad design . En eso Python lo hace bastante mejor con su desarrollo basado en el debate sobre los documentos PEP. Y es que, que le vamos a decir al otro hermano deforme, nuestro querido javascript.
  • Porque un desarrollador puro y que irradia luz y modernidad ahora pica el código en javascript o python o Go.
  • Porque un desarrollador consciente de su fatal destino en el matadero y vendido el kilo de carne barato…reiros pero hay pobres desgraciaditos que quieren vivir así de sometidos, pues estos como empresa sería e inútil llena de burrocracia pican código en Java o Microsoft .Net.

Pero PHP tiene mucha vida, hay proyectos muy gordos (y libres…que es lo importante) picados en el: Mediawiki, WordPress, Prestashop…y dicen que Facebook estaba picado en PHP (con inventos como compilador y tal).

Sábado 03 de noviembre de 2018

Xavier Genestos

Xavier Genestos
SYSADMIT

Linux: grep mostrar lineas sin comentarios

Como ya sabemos, en sistemas GNU/Linux, la configuración de muchos servicios se guarda en ficheros de texto dentro del directorio: /etc Estos ficheros de texto, suelen estar acompañados de comentarios, explicando que hace cada parámetro y su opción por defecto. En ocasiones, nos puede interesar mostrar los parámetros de configuración del fichero sin mostrar los comentarios. También el

Domingo 28 de octubre de 2018

Xavier Genestos

Xavier Genestos
SYSADMIT

Linux: Verificar caducidad certificados

Verificar la caducidad de los certificados digitales es una de las tareas que los administradores de sistemas deben realizar de forma periódica. Para realizar la verificación desde Linux, podemos utilizar la herramienta openssl.  El comando sería el siguiente: <!-- HTML generated using hilite.me --> #Inicio SYSADMIT echo | openssl s_client -servername www.sysadmit.com -connect

Jueves 25 de octubre de 2018

Bruno Exposito

Bruno Exposito
Puro Linux

Buscar texto en ficheros recursivamente

El comando grep busca/muestra las ocurrencias encontradas en uno o varios ficheros de texto.

Usando el comando grep puedes realizar una búsqueda de forma recursiva en un directorio y mostrar que ficheros tiene la ocurrencia que buscas.

Esto es bastante útil si eres programador, tienes varios proyectos y tienes que buscar algo que no recuerdas donde está.

Por ejemplo, imagina que tienes un directorio con varios ficheros y subdirectorios con mas ficheros, y quieres buscar el texto “vertical-align” de forma recursiva e ignorando mayúsculas:

grep -Ri "vertical-align"

Buscar texto en ficheros recursivamente

 

Si lo único que quieres ver es el nombre del fichero puedes usar una tubería (pipe) y cortar usando como delimitador “:” y obtener tan solo la primera columna.

grep -Ri 'class' | cut -d ":" -f1

Buscar texto en ficheros recursivamente obteniendo solo el nombre del fichero

 

Si además quieres que no salgan repetidos aquellos ficheros que tienen mas de una ocurrencia puedes usar “uniq” para eliminar duplicados o “sort -u” para ordenar y además eliminar duplicados.

grep -Ri 'include' | cut -d ":" -f1 | sort -u
grep -Ri 'include' | cut -d ":" -f1 |uniq

Buscar texto recursivamente sin repetidos

Sábado 20 de octubre de 2018

Pedro L. Lucas

Pedro L. Lucas
Cartas de Linux

AppImage

AppImage es una forma de empaquetar aplicaciones de forma que se pueden ejecutar encualquier distribución de Linux que tenga pocos años de antigüedad. En el sitio web de AppImage se puede encontrar más información.

Sólo hay que descargar la aplicación, darle permisos de ejecución y ejecutarla. El detalle es que toda la aplicación va empaquetada en un solo archivo. No hay que descomprimir o instalar nada.

Como el movimiento se demuestra andando, vamos a ver un ejemplo. Se puede ir al siguiente enlace para instalar el editor Brackets:

https://github.com/brackets-userland/brackets-electron/releases

Y descargar el fichero con la extensión “AppImage”. Una vez descargado, se le dan permisos de ejecución (botón derecho, propiedades y hay que activar los permisos de ejecución en la pestaña “Permisos”). Ahora simplemente se ejecuta.

permisos

La cuando lo ejecutéis preguntará si lo deseáis integrar en el sistema (que aparezcan sus iconos en los lanzadores).

Pero no es oro todo lo que reluce. Algún fallo he encontrado. Por ejemplo, en el siguiente enlace está Spivak (es una aplicación de Karaoke). Si la descargamos y le damos permisos de ejecución, la aplicación a mi me falla con el siguiente error:

fallo

En la página https://appimage.github.io/apps/ hay aplicaciones preparadas para descargar y ejecutar.

¿Cuál es la diferencia con un paquete Snap? La diferencia está en la seguridad. El paquete Snap está construido de forma que la aplicación está dentro de un contenedor del cual no puede salir. La AppImage es un archivo que contienen a toda la aplicación y el usuario puede ejecutar sin necesidad de ser root para instalar dicha aplicación.

A mi me sigue gustando la ventaja de los sistemas de paquetes de las distribuciones que al instalar la aplicación, instala sus dependencias y estas pueden ser reutilizadas por varias aplicaciones, ahorrando espacio en disco. Pero no es malo tener otras alternativas.

Viernes 19 de octubre de 2018

BlogDRAKE: AVISO a usuarios de afirma

Lunes 08 de octubre de 2018

Ramón Miranda

Ramón Miranda
Ramón Miranda

Digital Atelier Streaming Youtube


Edit: the link of the streaming :https://www.youtube.com/watch?v=vYHZ5kPZ4DU

Hi all!,
Next friday i will be making my first streaming in Youtube (it will be in english.) There we will see what the Digital Atelier New bundle pack can give to your art in Krita.
So if you like brushes, patterns and these kind of things this is going to be really interesting for you. 
Share with your friends because this Friday 20:00 CEST you have a date with me and krita. 

At the end of the streaming i have surprises and goodies. Stay with me and enjoy it! We can have a lot of fun.


Martes 25 de septiembre de 2018

Ramón Miranda

Ramón Miranda
Ramón Miranda

Sunset garden


"El otoño está ya aquí. Con sonido de verano, pero ya la luz va siendo menos. El verano se aleja como una figura distante a la que no podemos tocar. ¿Volveremos a vernos dentro de un tiempo? ¿Hasta la próxima vez quizás? Los últimos rayos de sol adornan tu figura y yo te miro esperando volverte a ver aquí donde las rosas no son rojas sino amarillas, donde las sombras crean recovecos y se puede charlar mejor"

Así de romanticón despido el verano 2018 con una imagen estilo impresionista. El "jardín de la puesta de sol" con la figura de un típico pintor bohemio y a su vez protagonista de una obra impresionista como se presentaban aquellas obras.

Hecho con Krita en una tarde, había reservado esta imagen para un momento especial y este lo es. Veremos que nos depara el Otoño.

Domingo 23 de septiembre de 2018

Liher Sanchez

Liher Sanchez
El blog de Liher

Que es el dropshipping

Internet es genial y nos ofrece a todo el mundo un sinfín de posibilidades en muchos ámbitos. Internet contiene información sobre cualquier cosa, es una fuente de conocimiento tremendamente excepcional. Podemos encontrar páginas web sobre cualquier tema que podamos imaginar. Si te gusta la informática y tienes ganas podrás aprender a programar, hacer webs, crear y manejar bases de datos, gestionar sistemas operativos y un largo etcétera de posibilidades. También, sea cual sea vuestra profesión, podéis encontrar información y tutoriales tanto escritos como en vídeo sobre como hacer esto o lo otro y así poder conocer mejor vuestro oficio. Otra de las grandes cosas que tiene Internet es el mundo de los negocios, que es en lo que me quiero centrar en este artículo, mas concretamente en el dropshipping. Para aquellos que no sepáis lo que es os lo voy a explicar para que sepáis un poco de que va el tema y las posibilidades que ofrece.

Este blog no fue creado con la idea de ganar dinero, aunque reconozco que en algunas ocasiones se me ha presentado la oportunidad de ganar algunos euros y, no en todas, he aceptado. Aun a pesar de ser un “hobby” y de hacerlo muy a gusto tengo que reconocer que cuesta dinero mantenerlo online, tanto el VPS como los dominios y una ayuda nunca viene mal. En otras ocasiones os he hablado de como ganar algo de dinero en Internet y esta es una de ellas, el dropshipping. Es un modo de montar un negocio que tiene muchas y muy buenas ventajas y muy poco riesgo, lo cual os detallaré a continuación.

Creo que la mejor forma de explicar que es el dropshipping es con un ejemplo. Imaginad que queréis montar una tienda en Internet. Con el sistema tradicional habría que montar una web con una tienda online. Ademas habría que disponer de un almacén para los productos que queréis vender. También hay que preocuparse de ir renovando el stock de productos. Unos de los grandes riesgos de este sistema tradicional es el hecho de tener un producto que no lográis vender, lo cual supondría una pérdida económica. Hay mas factores a tener en cuenta con el sistema tradicional.

Ahora suponed que los productos que vendéis no los tenéis físicamente en un almacén. Para empezar supondría un ahorro el no tener que pagar un local para usarlo como almacén, es obvio, ¿no? Imaginad que cuando un cliente os compra un producto en vuestra tienda online, automáticamente, ese producto se pide a vuestro proveedor y es el mismo proveedor quien se encarga de mandar el producto al cliente que lo ha comprado en vuestra tienda. El precio de venta en vuestra tienda lo ponéis vosotros y la diferencia entre ese precio y el de vuestro proveedor es vuestra ganancia. En esto consiste a grandes rasgos el dropshipping, una nueva manera de tener una tienda online. Esto conlleva muchas ventajas, algunas ya las he comentado como el hecho de no necesitar un almacén y no tener que preocuparos por gestionar el envío de los productos.

Ademas de las ventajas ya mencionadas podemos tener muchas mas. Por poner un ejemplo, imaginaos hubiese una plataforma que nos ofreciese plantillas ya hechas para la tienda online, eso nos facilitaría el trabajo. Estaría muy bien que nos permitiese agregar productos de una manera sencilla e intuitiva, incluso que nos ofreciese productos según nuestras preferencias. Esto y muchas ventajas mas nos ofrece Oberlo, una página web en la cual tenéis todas las facilidades del mundo para convertiros en expertos del dropshipping y ganar un buen dinero. Incluso tienen un blog con artículos que os ayudaran mucho.

 

 

Oberlo

 

Así que ya sabéis, si queréis ganar algo de dinero en Internet tenéis muchas posibilidades, lo mas importante es tener realmente ganas y no pensar que todo os va a llover del cielo. Es algo que requiere mucho esfuerzo y dedicación y no podéis pensar que con abrir una tienda online os van a entrar los clientes en manada, cuesta llegar a tener un negocio prospero, precisamente por eso os comentaba lo de la web de Oberlo, con ellos es todo mucho mas fácil y podéis centraros mejor en promocionar los productos que vendáis, algo para lo que dispondréis de mas tiempo ya que no tendréis que preocuparos de cosas como el almacen o los envíos, entre otras cosas.

Un saludo a todos.

Xavier Genestos

Xavier Genestos
SYSADMIT

Linux: Como saber el gateway (puerta de enlace)

En este post veremos como saber el gateway (puerta de enlace) de un sistema Linux. Los administradores de sistemas Windows, ya saben que ejecutando el comando ipconfig, este nos mostrará la dirección ip, mascara de subred y gateway. En sistemas Linux, ejecutando el comando equivalente: ifconfig, no nos mostrará el gateway. Veamos a continuación las distintas formas de saber el gateway (

Miércoles 19 de septiembre de 2018

Bruno Exposito

Bruno Exposito
Puro Linux

ReactOS – Windows de código abierto

ReactOS es un sistema operativo de código abierto escrito en C/C++ y disponible para las arquitecturas x86, x86-64 y ARM.

El proyecto nació en el año 1995 como una clon de Windows 95 y está basado en el diseño de la arquitectura de Windows NT. Es compatible (lo intenta al menos) con las aplicaciones y controladores de Windows NT 5.X (Windows XP y posteriores).

Pese a estar construido basándose en Windows, ReactOS incluye ciertas mejoras que no están incluidas en el susodicho, como un gestor de paquetes, similar al que usa GNU/Linux.

reactos_desktop

 

Auditoría

Dado que Windows es un sistema operativo de código cerrado, los desarrolladores de ReactOS emplean ingeniería inversa para comprender el funcionamiento de Window.

En enero del 2016, uno de los desarrolladores encontró código desensamblado de Windows XP, algo completamente ilegal y que afectó a la credibilidad del proyecto, sin embargo en la actualidad ese código ha sido reescrito en C y el proyecto está auditado para que no existan dudas acerca del origen del código.

Este problema ocasionó la eliminación de los enlaces de descarga, una pérdida de credibilidad y la prohibición de colaborar con WINE.

 

Demostraciones a políticos rusos

ReactOS ha despertado cierto interés entre algunos políticos rusos, en 2007 Víktor Alksnis se reunió con Aleksey Bragin “coordinador” del proyecto, para realizar una demostración y en 2012 se realizó otra demostración a Vladimir Putin.

Estabilidad

En estos momentos, y pese a llevar tantos años en desarrollo, sigue en versión alpha, por lo que no se recomienda instalarlo en máquinas de producción.

 

Look and feel

En lo relativo a su aspecto visual, es muy similar a Windows 95/98/2000, con ligeras diferencias respecto al original.

El tema ha quedado tremendamente obsoleto y el menú de inicio es poco usable.

Personalmente considero que deberían modificar la interfaz para asemejarse a Windows 7 Basic (porque tiene pocas animaciones y transparencias) o Windows 10, porque es bastante “flat”.

 

Descarga

Puedes descargar la ISO de instalación como el live CD desde su página oficial: https://www.reactos.org/es/download

Viernes 17 de agosto de 2018

Bruno Exposito

Bruno Exposito
Puro Linux

Cambiar grupo de un fichero o directorio – Comando CHGRP

El comando chgrp sirve para modificar el grupo (group) de un fichero o directorio. Está instalado en todas las distribuciones GNU/Linux, dentro del paquete coreutils.

Puedes consultar los grupos usando el comando:

cat /etc/group | cut -d ‘:’ -f1/

Sintaxis de chgrp

sudo chgrp {{opciones}} {{grupo}} {{fichero_o_carpeta}}

La sintaxis de chgrp es sencilla, tras el comando chgrp se escriben los modificaciones (opcionales), a continuación el nombre del grupo y para finalizar el nombre del fichero o carpeta.

Opciones de chgrp

-c, –changes Igual que la opción “verbose” pero solo si hay cambios
-f, –silent, –quiet Omite la mayoría de los mensajes de error
-v, –verbose Muestra el resultado de cada fichero procesado
–dereference Afecta a la referencia del enlace simbólico, en lugar del enlace simbólico en si (opción por defecto).
-h, –no-dereference Afecta al enlace simbólico, en lugar de la referencia a la que apunta.
–no-preserve-root No trata “/” de manera espacil (por defecto)
–preserve-root Falla al intentar operar recursivamente sobre “/”
–reference=RFILE use RFILE’s group rather than specifying a GROUP value
-R, –recursive Se ejecuta sobre ficheros y directorios recursivamente
-H Si es un enlace simbólico a un directorio, entra en el
-L Atraviesa todos los enlaces simbólicos a directorios que encuentre
-P No atravesar enlaces simbólicos (por defecto)
–help Muestra la ayuda
–version Muestra la versión y licencia

Cambiar el grupo de un fichero

sudo chgrp {{grupo}} {{fichero}}

sudo chgrp comerciales ventas.odt

*El fichero ventas pertenece ahora el grupo comerciales

Cambiar el grupo recursivamente

sudo chgrp -R {{grupo}} {{carpeta}}

sudo chgrp -R soporte /mnt/shared/software

*Todo el contenido de la carpeta /mnt/shared/software pertece ahora al grupo soporte

Cambiar el grupo a un fichero

sudo chgrp sistemas foto.jpg

*Estando dentro de la carpeta donde se encuentra el fichero “foto.jpg“, cambia el grupo a sistemas.

sudo chgrp comerciales /home/paco/documento.odt

*Independientemente del directorio actual, cambia el dueño de “documento.odt” a comerciales.

sudo chgrp admins “/home/juan/Música/Barón Rojo – Tierra de nadie.ogg”

*Independientemente del directorio actual, cambia el dueño del audio (que contiene espacios en el nombre) a admins.

 

sudo chgrp consultores /home/juan/Documentos -Rv

 *Cambia el grupo de la carpeta y todo su contenido de forma recursiva (-R), mostrando los detalles de cada fichero procesado (-v)

sudo chgrp -RHc grupo carpeta/

 *Cambia el grupo recursivamente atravesando enlaces a carpetas y mostrando los cambios.

sudo find . -name “*.txt” -exec sh -c ‘chgrp -v aula3 “$0″‘ {} \;

*Busca todos los ficheros con extensión txt y les cambia el grupo a “aula3” mostrando los detalles de cada operación realizada

Jueves 09 de agosto de 2018

Gorka Urrutia

Gorka Urrutia
Nideaderedes

Actualización de seguridad Laravel 5.6.30

Ayer se publicó una actualización de seguridad para Laravel. Es una vulnerabilidad relacionada con la APP_KEY. Esta variable es un valor que se usa para encriptar algunos valores como las sesiones de usuarios.

¿Es grave? Sí, pero solo debes preocuparte si alguien se ha hecho con esta APP_KEY. Eso solo puede hacerlo alguien con acceso al servidor (por ejemplo algún antiguo proveedor o un empleado resentido).

Si crees que no es el caso no deberías preocuparte aunque siempre es preferible actualizar.

La APP_KEY se usa para cifrar las sesiones de usuario, no para las contraseñas. Así que si la cambias las contraseñas no se verán afectadas pero sí las sesiones de usuario (cosa que, bueno, no es tan grave).

Laravel - el framework de los artesanos

Laravel – el framework de los artesanos

Miércoles 18 de julio de 2018

Gorka Urrutia

Gorka Urrutia
Nideaderedes

Cómo indicarle al git la llave ssh que debe usar

Si tienes tantas llaves ssh como yo seguro que tarde o temprano tendrás problemas porque en algún sitio se quejará de “too many retries”. Si eso te pasa en git hay una forma de indicar cuál es la llave que quieres usar al conectarte vía ssh.

En mi caso yo tenía problemas al conectarme a BitBucket. Así que para solucionarlo hay que editar el fichero de configuración SSH de tu ordenador. En mi caso:

/home/gorka/.ssh/config

y añadir:

host bitbucket.org
    HostName bitbucket.org
    IdentityFile ~/.ssh/llave_publica_para_conectarme_a_bitbucket.pub
    User gorka

En tu caso deberás cambiar “gorka” por tu usuario en BitBucket y ~/.ssh/llave_publica_para_conectarme_a_bitbucket.pub por la ruta de tu llave pública (la que uses para conectarte a BitBucket).

Si el problema lo tuvieses con GitHub harías:

host github.com
    HostName github.com
    IdentityFile ~/.ssh/llave_publica_para_conectarme_a_github.pub
    User git

Domingo 15 de julio de 2018

Gorka Urrutia

Gorka Urrutia
Nideaderedes

Mi Libro de programación en C ahora es gratuito

A partir de hoy, 16 de Julio de 2018, mi libro de programación en C para principiantes estará disponible de manera gratuita. Hace ya tiempo que lo escribí y considero que ya he ganado lo suficiente con él. Así que he decidido regalarlo.

Por ahora estará disponible gratuitamente en Amazon. Como Amazon no me deja ponerlo a precio cero hasta septiembre lo voy a deshabilitar y crearé uno nuevo esta vez gratuito y sin drm (esa cosa que no te deja copiarlo ni nada).

Ahora voy a maquetarlo de nuevo en formato PDF y, posiblemente en epub o algo así. Cuando termine lo pondré disponible gratuitamente para descarga en el Rincón del C.

Si quieres me puedes echar una mano maquetando el libro. Voy a ir poniendo el código fuente del libro disponible en GitHub para que todo el mundo pueda colaborar.

Si lo ves a la venta en algún sitio avísame, que se trata de un timo.

Jueves 05 de julio de 2018

Mayúsculas iniciales en WordPress

Ciertamente si tenemos un sitio propio, con dominio propio y acceso como administrador a sus «entrañas» podremos crear nuestros propios estilos CSS y con ellos construir cualquier formato que queramos en nuestras páginas. Pero eso solo si «tenemos el poder» (y queremos utilizarlo). Ahora bien, esto no quiere decir que no podamos hacer «cosas extrañas» … Sigue leyendo Mayúsculas iniciales en WordPress

Jueves 28 de junio de 2018

“El paciente” a descompilar es un exe de msdos en formato MZ

Posts in this series
  1. Compilar C en m$dos en nuestros tiempos
  2. "El paciente" a descompilar es un exe de msdos en formato MZ

Aunque voy despacio, voy a ir poniendo mis avances, que supongo que es poquito, pero bueno por seguir la Método de depuración del patito de goma o el refrán oriental que dice “El que enseña aprende dos veces.” .

La verdad es que en los primeros palos de ciego y análisis creí que “el paciente” era un ejecutable de tipo COM o algo así, pero ahora volviendo a analizarlo he encontrado el famoso:

MZ

0x4D 0x5A

Eso ayuda un montón porque si queridos mios, los ejecutables también tienen formato y no es estándar, hay muchos muchos estándares (en m$-dos hablamos…en otros sistemas operativos…pues habrá los suyos).

Como dice en el foro de ubuntu: Learning how to disassemble dos binaries

If actual DOS executables disassembly is the thing you are searching for, then search for disassemblers, that can handle the MZ magic [$4D 5A] (the default DOS 16bit header) or elf, coff, xcoff, ecoff, mach and such …

Bueno pues ahora entender la estructura de fichero de el formato DOS MZ .

Si alguno tiene alguna pista, estaré agradecido.

KDE-Plasma: Agregar una plantilla al menú «Crear nuevo»

Cuando hacemos clic derecho en Dolphin, tenemos la opción «Crear nuevo» lo que nos permite crear una carpeta, un archivo de texto, enlace a aplicación, etcétera. Hoy veremos cómo agregar una nueva entrada a ese menú. Usaré como ejemplo el crear un documento Writer con una plantilla definida por nosotros. Primero, claramente, tenemos que crear … Sigue leyendo KDE-Plasma: Agregar una plantilla al menú «Crear nuevo»

Videojuegos libres que se han ido de github después de ser fagocitada por Microsoft

Después de la mala noticia (gracias capitalismo) de el canibalismo salvaje de Micro$oft comiendose a github. Ya hablamos por los tomates de eso en Github ha muerto…bueno lo han asesinado.

Muchos proyectos de software libre han migrado a otras forjas/repositorios de software, y de entre estos tenemos los videojuegos libres…junto con respirar, una de las cosas que mas me ocupa la cabeza…me gustaría algún día intentar conseguir vivir de hacer videojuegos libres…pero bueno…

Bueno pues conocidos por mi, he encontrado los siguientes videojuego libres que se han ido de github:

Solarus, un clon libre del Zelda de SNES/GBA/GB con editor de mapas y todo en plan RPGmaker. Solarus has moved to Gitlab

Y OpenMW que es un clon libre del videojuego de rol en 3D Morrowin. OpenMW code, bug tracker, and wiki are now on GitLab!

Y seguro que hay mas. Amable lector…¿Conoces algún otro videojuego libre que se haya pirado de github?

Jueves 21 de junio de 2018

DAE-18: El texto ya está en su lugar (mayormente)

Bueno, parece que después de todo es posible que la edición 2018 de «domando al escritor» no se convierta en la edición 2019… El texto está, mayormente, «en su lugar». De hecho el índice ya ha llegado a las siete páginas. No hay aún diagramas ni capturas de pantalla, solo texto y dos tablas. Hay … Sigue leyendo DAE-18: El texto ya está en su lugar (mayormente)

Martes 05 de junio de 2018

Emiliano A. González Salgado

Emiliano A. González Salgado
El blog de Emi

Migración a LibreOffice 6.1 Base

Hace unos días se ha publicado la beta1 de LibreOffice 6.1.
He descargado el paquete y lo he instalado en Fedora 28.
Al ser una versión de desarrollo, al ejecutarse, crea sus propios directorios de usuario, distintos de los de la versión estable.

El motor de base de datos que viene implementado por defecto es Firebird, aunque HSQLDB sigue funcionando normalmente.

Al abrir una base de datos realizada con HSQLDB, que puede ser cualquier base realizada con una versión menor (salvo que se hubiera activado Firebird anteriormente) siempre solicita convertirla a Firebird.

Esto se puede obviar presionando el botón “latest” en vez de “yes”.

Para convertirla a la versión de Firebird hay que tener presente varias cuestiones, pues el sistema de conversión aún tiene fallos:

Realizar un copia de seguridad de la base de datos que queremos abrir y trabajar con la copia.

Comprobar si tenemos alguna vista de tabla. Es decir en el menú “tablas” están las tablas propiamente dichas y la vistas, que no son mas que una consulta, que puede ser de tablas combinadas.

En caso de que existan vistas de tablas hay que abrirlas y comprobar que no haya campos calculados o campos concatenados que no estén realizados de manera que puedan ser correctamente interpretados por la nueva versión, pues en caso contrario la vista se elimina en la conversión.

Si hay campos calculados o campos concatenados en la vista lo mejor es crear una nueva consulta en modo SQL, copiar la instrucción SQL que nos muestra la vista y guardar la nueva consulta que hemos realizado con esta instrucción SQL copiada.

El error mostrado venía dado por un campo concatenado, que no se ajustaba a Firebird. En la consulta cambié la instrucción y conseguí que funcionara.
Usaba: “Prenom” + SPACE( 1 ) + “Nom”
Rectifiqué: “Prenom” || ‘ ‘ || .”Nom”

A continuación tendríamos que comprobar todos las consulta que tenemos. En la que figure la vista de tabla habría que cambiar todos los datos por los de la consulta.

Un método puede ser con un editor de texto y la edición SQL de consultas.

En mi caso la vista de tabla de llamaba vMovimientos y la consuta creada con la misma instrucción c_vMovimientos. Copiaba el resultado de la salida de la consulta en un editor de texto (kate) y con buscar y remplazar ya tenía la nueva sintaxis. Volvía a copiar y pegar. Guardaba la consulta y la base. Resuelto parcialmente.


La consultas con parámetros, si en criterio se hace referencia a un campo de una tabla, poniendo <= [tabla].[campo] muestra error.

Los campos numéricos y con decimales dan problemas.
Tengo en una tabla “Movimientos” que tiene, entre otros, tres campos “DECIMAL” con dos decimales.
Al importar los campos INTEGER, DATE, VARCHAR Y BOOLEAN no han dado problemas, pero los DECIMAL sí.

Había cantidades que no daban problemas, pero en otras el resultado era desastroso.
Números positivos los convertía en negativos que no tenía relación alguna, las cantidades con decimales terminados en 00 las dividía por 100. 9000,00 pasaba a ser 90,00, un 9xx,xx lo pasaba a -16xx,xx.

Para solucionarlo copio desde la base guardada y, abierta con una versión antigua, la tabla en Calc:
Crear tres nuevas columnas,
Multiplicar el resultado por 100.
Cambiar a formato numérico y sin decimales.
Transponer a sus antiguas columnas.

Con esto ya puedo realizar la exportación de datos a la tabla Movimientos de la nueva base convertida.

Parece un proceso muy engorroso, pero si se hace con tranquilidad, en poco tiempo se ha finalizado.

Por ahora, en la comprobación que he realizado, tanto los datos de fecha como los numéricos están correctos, sin que haya diferencia entre una y otra tabla.

NOTA.- En una comprobración posterior, y en un campo calculado, el resultado del mismo es el que he importado de la hoja de cálculo, no de lo que figura en la tabla.

Es decir, está multiplicado por 100 con respecto a lo que figura en la tabla.

El bug ha sido reportado por Xisco Fauli @x1sc0    https://bugs.documentfoundation.org/show_bug.cgi?id=118043 .

 

Jueves 31 de mayo de 2018

José María Morales Vázquez

José María Morales Vázquez
tecnología – Un lugar en el mundo…

WordPress. El misterioso caso del cuelgue diario a las 9 de la mañana

icono de wordpress Los blogs están muertos. Por fin. Bueno, no todos. Hay alguno que resiste hoy y siempre a la invasión de las redes sociales. A ratos me gusta pensar que este es uno de ellos… pero si soy sincero conmigo mismo ciertamente está un poco desnutrido. No le presto mucha antención, no… Hace meses, por ejemplo, que se cuelga durante aproximadamente media hora todas las mañanas y ni siquiera me he preocupado de ver que le pasa. Bueno, ya no. Ya está arreglado. Los malos hados subestiman el poder de esas tareas tediosas y desagradables que hacen que hasta te den ganas de ponerte a planchar o a limpiar los baños. Bueno, yo me he conformado con arreglar por fin este problemilla. Los baños otro día. 🙂

¿Síntomas mi querido Watson? Apenas nada: la indisponibilidad se producía por un elevado consumo de CPU y mirando con htop resulta que la responsable es mariadb (aunque en el pantallazo aparezca mysql ya sabéis que son compatibles a nivel binario).

htop - mysql se come todo el tiempo de proceso de ambos cores

Alguna pista mas: conéctandome a mariadb observo que lo que se están ejecutando son consultas aparentemente bastante simples sobre la tabla wp_options:

MariaDB [unlugar]> show processlist;
+-------+---------+-----------+---------+---------+------+--------------+------------------------------------------------------------------------------------------------------+----------+
| Id    | User    | Host      | db      | Command | Time | State        | Info                                                                                                 | Progress |
+-------+---------+-----------+---------+---------+------+--------------+------------------------------------------------------------------------------------------------------+----------+
| 29462 | unlugar | localhost | unlugar | Query   | 1043 | Sending data | DELETE a, b FROM wp_options a, wp_options b
			WHERE a.option_name LIKE '\\_transient\\_%'
			AND a. |    0.000 |
| 29552 | root    | localhost | unlugar | Query   |    0 | init         | show processlist                                                                                     |    0.000 |
| 29559 | unlugar | localhost | unlugar | Query   |   40 | update       | INSERT INTO `wp_options` (`option_name`, `option_value`, `autoload`) VALUES ('jetpack_nonce_15275779 |    0.000 |
| 29560 | unlugar | localhost | unlugar | Query   |   22 | updating     | UPDATE `wp_options` SET `option_value` = '1527578481.1030609607696533203125' WHERE `option_name` = ' |    0.000 |
| 29561 | unlugar | localhost | unlugar | Query   |    7 | updating     | UPDATE `wp_options` SET `option_value` = '1527578505', `autoload` = 'yes' WHERE `option_name` = 'jet |    0.000 |
| 29562 | unlugar | localhost | unlugar | Query   |    0 | updating     | UPDATE `wp_options` SET `option_value` = '1527578503.1177010536193847656250' WHERE `option_name` = ' |    0.000 |
+-------+---------+-----------+---------+---------+------+--------------+------------------------------------------------------------------------------------------------------+----------+

Así que le echamos un vistazo a esa tabla y resulta que tiene la friolera de más de 40.000 registros y consume cerca de 38 Megas de espacio ¿Qué tiene dentro?¿Los casos de corrupción del PP? Porque la estructura de la tabla también es bastante simplona:

MariaDB [unlugar]> describe wp_options;
+--------------+---------------------+------+-----+---------+----------------+
| Field        | Type                | Null | Key | Default | Extra          |
+--------------+---------------------+------+-----+---------+----------------+
| option_id    | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
| option_name  | varchar(191)        | NO   |     | NULL    |                |
| option_value | longtext            | NO   |     | NULL    |                |
| autoload     | varchar(20)         | NO   |     | yes     |                |
+--------------+---------------------+------+-----+---------+----------------+
4 rows in set (0.01 sec)

Un último dato: la exactitud en la periodicidad me escamaba también. Incluso uno de esos días de puentes con un tiempo maravilloso donde no queda ni el friki más irredento paseándose por algo donde no despachan cerveza el blog también se caía. Y a la misma hora, así que le eché un vistazo al cron del sistema y no había nada que se lanzara a esa hora. ¿Y? De repente recordé que wordpress viene con su propio planificador de tareas y que estas se pueden inspeccionar fácilmente. Por ejemplo a través del plugin WP Cron Cleaner. Bingo. Ahí la tengo: Justo a las 9.04 y todos los días hay una tarea que se llama delete_expired_transients. Y eso de “transient” ya era algo que habíamos visto por ahí arriba en la consulta que se estaba realizando en mariadb.

El proceso que se lanza diariamente alrededor de las 9 realiza una limpieza de transients

Tocaba googlear a ver que es eso de los transients pero ya teníamos datos suficientes para reunir en la biblioteca a todos los implicados y desvelar quien es el asesino.

Los transients, al parecer, son registros con información temporal que proviene de los plugins que tenemos instalados. ¿Sirven para algo? Pues una vez que caducan no, para nada. De hecho precisamente por eso está ahí esa tarea que elimina los caducados. ¿Qué es lo que ocurre entoces? Pues que es evidente que muy bien no funciona porque la mayoría de esos 40.000 registros son transients. Más de 35.000, de hecho. Y la búsqueda se realiza a través del campo wp_options que como vemos no está indexado. Fatal. La primera aproximación al problema pasa, pues, por crear un índice sobre esa columna:

MariaDB [unlugar]> alter table wp_options add index (option_name);
Query OK, 0 rows affected (3 min 47.86 sec)         
Records: 0  Duplicates: 0  Warnings: 0

Mano de santo, oigan. Al día siguiente a las 9.04 por primera vez en meses el blog no se colgó. ¿Lo dejo así?¿Con una tabla diez veces mas grande que el contenido de todo lo escrito en el blog?¿Hasta donde la dejo crecer entonces? Toca hacer otra búsqueda y por ahí me encuentro con mucha mas gente que ha tenido problemas similares y que asegura que se puede hacer tábula rasa y borrarlos todos. Así que hago un backup rápido, los elimino… y parece que todo va bien. Fantástico 🙂

¿Cómo eliminarlos? Pues a través de línea de comando es fácil:

MariaDB [unlugar]> DELETE FROM `wp_options` WHERE `option_name` LIKE ('%\_transient\_%')

Puestos a buscar una solución más cómoda y permanente para no llegar de nuevo aquí dentro de 10 años encontré otro plugin (Transient Cleaner) que te permite borrarlos puntualmente y/o programar una tarea para hacer una limpieza mas efectiva que la de wordpress de forma periódica.

Y listo. O eso parece. Mañana los baños. Sin falta 🙂

Artículo Original: .

Este artículo pertenece a Un lugar en el mundo... Si quieres ver actualizaciones y comentarios interesantes visita el texto original en: WordPress. El misterioso caso del cuelgue diario a las 9 de la mañana || Hospedado en un Cloud VPS de Gigas.

Martes 22 de mayo de 2018

Pedro L. Lucas

Pedro L. Lucas
Cartas de Linux

Cuenta oficial en Twitter de LXQt y LXQt 0.13.0

Con el nuevo lanzamiento de LXQt, ya van por la versión 0.13.0, el proyecto lanza su cuenta oficial en Twitter: https://twitter.com/LXQtOfficial Y luce así de bien:

¿Qué trae de nuevo LXQt? Pues según sus notas, muchas correcciones a errores: https://blog.lxqt.org/2018/05/release-lxqt-0-13-0/

Combinaciones de teclas útiles

Un par de combinaciones de teclas útiles que trae por defecto son:

  • Ctr + Alt + i  Abre el navegador web por defecto (¡utilísima!)
  • Ctr + Atl + e  Abre el explorador de ficheros
  • Ctr + Atl + t  Abre el terminal

Control de brillo y contraste

De entre la aplicaciones disponibles de LXQt, voy a hablaros de una que me ha hecho gracia, la posibilidad de controlar el brillo de pantalla.

¿Qué es lo que me gusta de esta aplicación? Permite cambiar el brillo de pantalla tanto por hardware como por software. En un portátil puedes cambiar el brillo de la pantalla modificando la intensidad luminosa de los LED que hay detrás de la pantalla. En un ordenador de sobremesa esto no se puede hacer, pero te permite cambiar el brillo de la pantalla por software y es algo muy agradable a la vista. ¡Sobre todo con pantallas excesivamente brillantes!

Aprovechando el espacio de la pantalla eliminando las barras de título

Otra curiosidad, si pulsáis sobre una barra de menús con el clic derecho del ratón y seleccionáis “Decorar”, se eliminan las barras de título. Muy útil para aprovechar todo el espacio disponible de la pantalla. Por ejemplo:

Es esta captura de pantalla, he puesto el panel a la izquierda y he eliminado la barra de título del terminal. Como se puede ver la pantalla se aprovecha mejor.

Para volver a decorar las ventanas, pulsamos Atl + espacio. Aunque, yo las gestiono pulsando con el botón derecho del ratón sobre su icono en el panel.

Y Wayland… ¿Para cuándo?

Los desarrolladores están teniendo ardientes debates sobre el tema: https://github.com/lxqt/lxqt/issues/1011

La postura que están adoptando es mantenerse independientes del gestor Wayland usado, de forma que se puedan usar las herramientas LXQt en cualquier gestor de composición Wayland. Parece que tienen claro que no van a reescribir otro compositor Wayland más habiendo opciones disponibles. Aunque hay voces que apuntan a que finalmente, por la estructura de Wayland, no va quedar más remedio.

Viernes 23 de marzo de 2018

José María Morales Vázquez

José María Morales Vázquez
tecnología – Un lugar en el mundo…

Bootstrap 4. Primeros pasos

icono de php Bootstrap es una colección de elementos, plantillas y componentes HTML, CSS y Javascript para crear rápidamente páginas web con un aspecto moderno y “responsivo” (¡menudo palabro!) al tamaño de pantalla de cualquier dispositivo. Su versión 4 se liberó hace un par de meses y aporta algunos cambios significativos como, por ejemplo, la inclusión de Popper como librería javascript para “tooltips” y otros elementos emergentes y la eliminación de las tipografías Glyphicons para introducir símbolos y pictogramas.

Podemos trabajar con Bootstrap bien descargandonosla en nuestro propio servidor web, o bien usando sus librerías directamente desde los CDN que nos ofrecen. Aquí usaremos este segundo método por sus evidentes ventajas de cara a montar una primera plantilla para pruebas. Necesitamos incluir simplemente el siguiente tag en :

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" />

Si vamos a usar los elementos javascript necesitamos incluir también las librerías correspondientes y, ademas, las de jquery y popper en nuestro proyecto las cuales también tienen disponible la posibilidad de enlazarlas directamente sin necesidad de descargarlas en local:

<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.1/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>

IMPORTANTE: los enlaces anteriores corresponden a las versiones estables más recientes en el momento de escribir esto. No suelen eliminar las versiones anteriores, pero conviene que te cerciores si llegas a este texto en un futuro lejano.

Con todo esto, la plantilla mínima de HTML para empezar a trabajar (incluyendo los enlaces correspondientes a las librerías javascript comentados) sería esta:

<!DOCTYPE html>
<html lang="es">
    <head>
    	<meta charset="utf-8" />
    	<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
    	<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" />
    	<title>Plantilla Bootstrap</title>
  	</head>
  	<body>
		<h1>Plantilla Bootstrap</h1>

    
		<!-- Javascript opcional -->
		<!-- <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
    	     <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.1/umd/popper.min.js"></script>
    	     <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script> -->
  	</body>
</html>

Sosa, verdad? Claro, aún no hemos empezado a trabajar… Si quieres ver algo más impactante, bootstrap dispone de plantillas con algo mas de chicha para tus diseños. Las tienes disponibles en este enlace. Si prefieres empezar desde cero, tienes disponible un montón de La documentación bastante fácil de seguir que incluye multitud de ejemplos prácticos para empezar a trabajar desde el primer minuto.

Artículo Original: .

Este artículo pertenece a Un lugar en el mundo... Si quieres ver actualizaciones y comentarios interesantes visita el texto original en: Bootstrap 4. Primeros pasos || Hospedado en un Cloud VPS de Gigas.

Lunes 19 de marzo de 2018

Baltasar Ortega

Baltasar Ortega
KDE Blog

Presenta tu charla para Akademy-es 2018 de Valencia

Hace tiempo que se anunció la sede y desde ese momento el blog va dando los detalles necesarios para ir abriendo boca.. Y es que en poco más de mes y medio se celebrará en Valencia la reunión anual en España de usuarios y desarrolladores de KDE, Akademy-es 2018. Concretamente se celebrará del 11 al 13 de mayo y es el momento de seguir preparando el programa. Como el evento es una celebración comunitaria se abrió en el momento del anuncio de la sede la posibilidad de que todo el mundo, además de acudir,  participara de forma activa. Así que presenta tu charla para Akademy-es 2018 de Valencia y muestra a toda el mundo tu proyecto personal o comunitario.

Presenta tu charla para Akademy-es 2018 de Valencia

Recordemos que en Akademy-es se realizarán las típicas charlas que presentan las novedades tanto de las aplicaciones como de las herramientas de programación, sin olvidar de los proyectos activos o de aquellos de los que se quieren lanzar en un futuro cercano.

En anteriores ediciones en estas charlas (extraído del programa de Akademy-es 2017 de Almería) descubrimos KDE,  nos pusimos a colaborar con KDE, conocimos la asociación KDE España, aprendimos más de Plasma 5, vimos pinceladas de un posible futuro de KDE, aprendimos como colaborar con KDE sin ser programador, conocimos mejor la relación de Slimbook co KDE, aprendimos a hacer aplicaciones para el móvil y recibimos las primeras leccions de Qt.

¿Y qué encontraremos en esta edición? Pues depende de ti, ya que si tienes algún tema que crees que interesará a la Comunidad KDE y sus simpatizantes, no lo dudes a y presenta tu charla para Akademy-es 2018. Estaremos encantados en escuchar tu propuesta.

Si quieres más información, basta con que leas el siguiente texto oficial o que visites la web oficial de Akademy-es 2018, no obstante aquí te lo puedo contar yo:
Para proponer actividades se deberá enviar un correo a akademy-es-org@kde-espana.es antes del 31 de marzo con un resumen breve de la presentación.

Presenta tu charla para Akademy-es 2018Es importante tener en cuenta las siguientes consideraciones:

  • Se puede elegir entre dos formatos de charlas:
    • Charlas de 30 minutos.
    • Lightning talk de 10 minutos.
  • Si la duración de las charlas propuestas no se ajusta a ninguno de estos dos esquemas (por ejemplo, si se necesita más tiempo), esto debe indicarse claramente en la comunicación.
  • Se permitirá a KDE España la distribución bajo una licencia libre de todo el material utilizado para la realización de la actividad, así como de la grabación de la misma.
  • La charla puede ser tanto a nivel de usuario como de nivel técnico.

Se trata de una gran oportunidad de darte a conocer en el mundo KDE y en el mundo del Software Libre en general.

Más información: Akademy-es 2018

¿Qué es Akademy-es?

Akademy-es (#akademyes, que es la etiqueta para las redes sociales) es evento más importante para los desarrolladores y simpatizantes de KDE, que se ha ido celebrando desde el 2006 con éxito creciente.

En general, las Akademy-es son el lugar adecuado para conocer a los desarrolladores, diseñadores, traductores, usuarios y empresas  que mueven este gran proyecto.

En ellas se realizan ponencias, se presentan programas, se hace un poco de caja para los proyectos libres (camisetas, chapas, etc) pero sobre todo se conoce a gente muy interesante y se cargan baterías para el futuro.

Podéis repasar las anteriores ediciones en estas entradas del blog:

Domingo 18 de marzo de 2018

Baltasar Ortega

Baltasar Ortega
KDE Blog

Noticias linux 02, tercer domingo de marzo de 2018

Esta semana sigue la sección que inicié de forma no oficial ya hace más de un mes y que se dedica a mostrar las novedades del mundo GNU/Linux que no aparecen en el blog por falta de tiempo y que deberían aparecer. Así que os doy la bienvenida a Noticias linux 02, correspondiente tercer domingo de marzo de 2018 con Firefox, Kubuntu, Plasma 5.12.3 y editores multimedia GNU/Linux

Noticias linux 02, tercer domingo de marzo de 2018

La semana de las mil actividades ha llegado a su fin, dejándome a las puertas de otra un poco más relajada en cuanto a obligaciones laborales, pero llena de tareas que hacer para poder sobrevivir a este tercer trimestre que llega.

Así que aprovecho la tranquilidad de este domingo para seguir con la nueva sección de Noticias Linux, que llega a su segunda edición, compartiendo noticias que han aparecido en otros blogs o webs y que hubiera estado genial que aparecieran en éste.

Firefox lanza su versión 59

Mientras esperamos que madure Falkon, los usuarios de la Comunidad KDE podemos seguir utilizando Firefox, el gran explorador web, que sigue mejorando y evolucionando.

Según podemos leer en Genbeta, el pasado 13 de marzo fue lanzado Firefox 59, una nueva versión del excelente explorador (disponible ya en las principales distribuciones GNU/Linux) que nos ofrece las siguientes novedades:

  • Tiempos de carga de página más rápidos.
  • Posibilidad de arrastrar y soltar nuestros “sitios favoritos en Firefox Home (la pantalla que aparece si creamos una nueva pestaña)
  • Posibilidad de desactivar la notificación que indica que una web está intentando acceder a la cámara.

Más información: Firefox

Plasma 5.12.3 ya disponible para Kubuntu 17.10

Noticias linux 02Los usuario de Kubuntu 17.10 están de enhorabuena. Según leemos en Ubunlog, ya está disponible la versión de Plasma 5.12.3 para sus escritorios.

Para hacerlo debéis activar los repositorios backports, abriendo una konsola y escribiendo los siguientes comandos:

sudo add-apt-repository ppa:kubuntu-ppa/backports -y
sudo apt update && sudo apt full-upgrade
Pero alerta, como dicen en el Ubunlog “Si tenemos una versión anterior a Kubuntu 17.10, no solo se actualizará el escritorio sino también la distribución
Más información: Kubuntu

Los 10 mejores editores Multimedia

Y finalizo esta entrada de Noticias Linux 02, con otra mención a un blog que se ha convertido en imprescindible para cualquier simpatizante del Software Libre: Maslinux.

En esta ocasión nos ha obsequiado con un recopilatorio de los 10 mejores editores multimedia GNU/Linux:  A modo de resumen, los mejores editores en orden de aparición son: Shotcut, VidCutter, FlowBlade, Kdenlive, Blender, Openshot, Cinelerra, Pitivi, Ardour y Rosegarden.
Y como siempre digo, son todos los que están, pero no están todos los que son. ¿Qué noticia os ha llamado la atención esta semana? Ponedlo en los comentarios y mejores esta entrada.

 

 

 

 

Sábado 17 de marzo de 2018

Baltasar Ortega

Baltasar Ortega
KDE Blog

Helium 8, un nuevo tema para Plasma

Volvemos a tema de diseño al blog con Helium 8, un nuevo tema para Plasma de tono grisáceo y ligero. Una gran creación de David Linares, conocido como @mcder3 que sigue ofreciéndonos diseños muy cuidados.

Helium 8, nuevo tema para Plasma

Los temas para el escritorio Plasma de la Comunidad KDE son sutiles pero importantes. La verdad es que todos se parecen mucho inicialmente, pero una vez instalados y tras un poco tiempo de uso ves las diferencias y decides si te gusta o no.

Y esto es así porque aunque los cambios son sutiles, abarcan a todo el sistema: iconos de la bandeja del sistema, pantalla de apagado, reinicio o cambio de usuario, animaciones al ejecutar aplicaciones, decoraciones de plasmoide, etc.

Es por ello, que me complace presentaros la nueva creación de David Linares (aka @mcder3) con la que tendremos un Plasma, como con todos sus diseños, elegante y ligero, con transparencias adecuadas y con un tono grisáceo.

Helium 8

 

También es de detacar su pantalla de salida y las animaciones con toques azulados cuando se ejecutan aplicaciones y se colocan en la barra de tareas. Todo muy sencillo pero visualmente muy atractivo.

 

Y como siempre digo, si os gusta el tema Helium 8 para Plasma podéis “pagarlo” de muchas formas, desde donaciones a mcder pasando por todo tipo de acciones en la página de KDE Store, que estoy seguro que el desarrollador lo agradecerá: puntúale positivamente, hazle un comentario en la página o realiza una donación. Ayudar al desarrollo del Software Libre también se hace simplemente dando las gracias, ayuda mucho más de lo que os podéis imaginar, recordad la campaña I love Free Software Day 2017 de la Free Software Foundation donde se nos recordaba esta forma tan secilla de colaborar con el gran proyecto del Software Libre y que en el blog dedicamos un artículo.

Más información: KDE Store

Martes 13 de marzo de 2018

TutorialesLinux.com: Herramientas de análisis de tráfico

Domingo 11 de marzo de 2018

José María Morales Vázquez

José María Morales Vázquez
tecnología – Un lugar en el mundo…

Laravel 5.6. Estructura y primeros pasos: Autenticación de usuarios

icono de php Ya yenemos Laravel 5.6 instalado en alguno de los dos entornos que hemos visto antes. ¿Qué sigue? Lo primero, entender un poquito la estructura de directorios que nos ha creado composer. Sólo lo imprescindible. El resto lo iremos viendo a medida que avanzamos.

josemaria@valeria /var/www/html/prueba $ ls -la
total 236
drwxr-xr-x 12 root www-data   4096 mar  9 19:31 .
drwxr-xr-x  3 root www-data   4096 mar  9 18:29 ..
drwxr-xrwx  6 root www-data   4096 ene  3 17:52 app
-rwxr-xrwx  1 root www-data   1686 ene  3 17:52 artisan
drwxr-xrwx  3 root www-data   4096 ene  3 17:52 bootstrap
-rw-r--rw-  1 root www-data   1413 ene  3 17:52 composer.json
-rw-r--rw-  1 root www-data 143565 mar  8 07:37 composer.lock
drwxr-xrwx  2 root www-data   4096 ene  3 17:52 config
drwxr-xrwx  5 root www-data   4096 ene  3 17:52 database
-rw-r--r--  1 root www-data    612 mar  9 19:31 .env
-rw-r--r--  1 root www-data    565 ene  3 17:52 .env.example
-rw-r--r--  1 root www-data    111 ene  3 17:52 .gitattributes
-rw-r--r--  1 root www-data    146 ene  3 17:52 .gitignore
-rw-r--rw-  1 root www-data   1125 ene  3 17:52 package.json
-rw-r--rw-  1 root www-data   1040 ene  3 17:52 phpunit.xml
drwxr-xrwx  4 root www-data   4096 ene  3 17:52 public
-rw-r--rw-  1 root www-data   3550 ene  3 17:52 readme.md
drwxr-xrwx  5 root www-data   4096 ene  3 17:52 resources
drwxr-xrwx  2 root www-data   4096 ene  3 17:52 routes
-rw-r--rw-  1 root www-data    563 ene  3 17:52 server.php
drwxrwxrwx  5 root www-data   4096 ene  3 17:52 storage
drwxr-xrwx  4 root www-data   4096 ene  3 17:52 tests
drwxr-xrwx 36 root www-data   4096 mar  8 07:38 vendor
-rw-r--rw-  1 root www-data    549 ene  3 17:52 webpack.mix.js

El directorio public ejerce de DocumentRoot. Allí encontraremos el index.php que da entrada a nuestra aplicación web así como las hojas de estilos, etc. El fichero .env que vemos aquí arriba en el directorio raiz de nuestra aplicación es el fichero de configuración principal. De hecho, puesto que vamos a empezar a trabajar con bases de datos en este momento podemos aprovechar para editar las siguientes directivas:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=laravel
DB_PASSWORD=secreto

Importante: aunque usemos mariadb la directiva DB_CONNECTION debe de ser mysql porque Laravel no entiende otra y, a fin de cuentas, ambas son compatibles a nivel binario. Para que Laravel sea capaz de hacer uso de esa base de datos debemos de crearla. A ella y al usuario que le hemos dicho que va a usar para manejarla. Entramos en nuestro gestor (mysql o mariadb) y ejecutamos lo siguiente:

CREATE DATABASE laravel;
CREATE USER laravel@localhost IDENTIFIED BY 'secreto';
GRANT ALL ON laravel.* TO laravel@localhost;

Vamos ahora a crear nuestro sistema de autenticación. Laravel viene ya con un módulo llamado User.php que reside en el directorio app. Para generar el resto de lo que necesitamos ejecutamos lo siguiente:

php artisan make:auth
php artisan migrate

La primera línea crea el código y rutas necesario para la gestión de usuarios. En particular, creará o modificará los siguientes ficheros:

routes/web.php
resources/views/auth/login.blade.php
resources/views/auth/register.blade.php
resources/views/auth/passwords/email.blade.php
resources/views/auth/passwords/reset.blade.php

La segunda instrucción crea la estructura de tablas necesaria en la base de datos que hemos configurado previamente. Si ahora volvemos a cargar la web de nuestro aplicación veremos que en la esquina superior derecha tenemos dos nuevos enlaces correspondientes a las funcionalidades de Login y Registro:

Laravel 5.6 con la funcionalidad de login y registro

Las pantallas de registro y login por defecto son estas:

Pantalla de registro en Laravel 5.6
Pantalla de login en Laravel 5.6

Y una vez hecho login vemos que en la barra de menú se nos identifica con nuestro nombre de usuario y tenemos la posibilidad de cerrar sesión:

Logout en Laravel 5.6

Si le echamos un vistazo a “las tripas” vemos que nos ha creado dos tablas una de las cuales, la de usuarios, es la que guardará la información relativa a los registros de usuarios.
Tablas creadas por Laravel 5.6 para la autenticación de usuarios

Además, tal y como está mandado, vemos que no almacena las contraseñas en claro sino un hash de las mismas:

hash de las passwords en Laravel 5.6

La castellanización de los recursos es tan sencilla como editar alguno de los ficheros php que hemos indicado anteriormente. Por ejemplo, el fichero login.blade.php es el que contiene la ventana de login y register.blade.php la de registro. Con muy poco esfuerzo tendremos las ventanas anteriores en perfecto castellano. Pero eso ya os lo dejo a vosotros 😉

Artículo Original: .

Este artículo pertenece a Un lugar en el mundo... Si quieres ver actualizaciones y comentarios interesantes visita el texto original en: Laravel 5.6. Estructura y primeros pasos: Autenticación de usuarios || Hospedado en un Cloud VPS de Gigas.

Jueves 01 de marzo de 2018

TutorialesLinux.com: Vulnerabilidad en Memcached (DDoS), cómo solucionarla.

Sábado 24 de febrero de 2018

Pedro L. Lucas

Pedro L. Lucas
Cartas de Linux

Viendo la degradación de la batería de un portátil

Las baterías de los portátiles, móviles y otros dispositivos van perdiendo capacidad con el tiempo. Esta pérdida de capacidad la podemos comprobar con diversas herramientas.

Por ejemplo, con la aplicación de gestión de la batería de LXQt se puede ver la siguiente captura:

En esta captura se puede comprobar que en el diseño original tenía una capacidad de 51.50Wh. Actualmente tiene 45.44Wh, por lo que su capacidad total se ha reducido, está al 88% de su capacidad inicial, es decir ha perdido un 12% en los 4 años que lleva en uso. Realmente si la batería estuviera totalmente vacía o totalmente llena se degradaría más rápido, por lo que la electrónica no debería dejar que la batería se llene o vacíe totalmente.

En siguiente parámetro es “Energy rate”. Muestra la energía que está entrando o saliendo de la batería en el momento actual. Según se ve, el portátil está consumiendo 10.22W en el momento de hacer la captura. Cuando el portátil está cargando, muestra la energía que está entrando en la batería y es fácil ver valores de 30W, aunque esta potencia que entra en la batería va bajando según se va llenando.

En la siguiente captura se puede ver que el “Energy rate” vale 0W:

En esta situación la batería está cargada y el portátil conectado a corriente eléctrica, por lo que no entra ni sale energía de la batería.

Consultar la degradación vía terminal

Usando el terminal del Linux es posible consultar la degradación de la batería y otras características visitando la carpeta /sys/class/power_supply/. Dentro de esta carpeta hay archivos que se pueden consultar para ver la capacidad, el voltaje o la intensidad eléctrica que está entrando o saliendo la batería.

Evolución de la degradación y tratando de evitarla

En teoría las baterías nuevas se degradan un poco, luego bajan linealmente para, finalmente, morir rápidamente. Más información se puede encontrar en el siguiente enlace:

http://batteryuniversity.com/learn/article/how_to_prolong_lithium_based_batteries

La primera conclusión que se obtiene del artículo anterior es: no se puede evitar la degradación de la batería. Lo que sí se puede hacer es que esta degradación vaya más despacio.

Dentro de la batería se producen multitud de reacciones químicas. La mayoría de ellas interesan, pero hay otras que no. Se suele recomendar no cargar la batería más allá del 80% y no dejar que su nivel baje del 20%. Si se llena o vacía la batería completamente, comienzan estas reacciones químicas que no interesan. Es mejor pequeñas cargas y descargas que llenarla y vaciarla completamente. Si el fabricante ha sido responsable, habrá dejado un margen de la batería que no podréis usar, este margen es para evitar la degradación.

La temperatura es también un factor importante. Las temperaturas muy altas, degradan las baterías a mayor velocidad. Por esta y otras causas, siempre vais a leer que no hay que dejar los dispositivos electrónicos al Sol o bajo otras fuentes de calor.

Cuando la temperatura de la batería es baja, su desempeño empeora. Pero esta situación en un portátil va a ser difícil que se dé.

Curiosidades

En Internet se puede encontrar información de portátiles o teléfonos que han explotado. Esto ha sido investigado y se debe a que se forman dendritas dentro de la batería que acaban formando cortocircuitos y provocando que se incendien:

https://computerhoy.com/noticias/hardware/esto-es-que-provoca-que-exploten-baterias-metal-litio-52834

Otra curiosidad son las baterías de Ni-Fe que no sufren ningún tipo de degradación. Pueden llegar a durar más de 20 años y no sufrir ni el 2% de degradación. Y como extra su reciclaje es muy simple:

https://en.wikipedia.org/wiki/Nickel%E2%80%93iron_battery

Su punto débil, su peso y volumen. Pero se pueden usar para otros usos como instalaciones solares en los que los paneles recargan las baterías cuando hay Sol y se obtiene la electricidad cuando es de noche:

http://www.zappworks.com/battery_prices.htm

Como veis en el anterior enlace los precios son prohibitivos.

Ya se comienzan a escuchar otras tecnologías novedosas como las baterías de ánodo de grafeno, de electrolito sólido, Litio-azufre,…

Habrá que esperar para ver cuál de ellas acaba desarrollándose de forma definitiva.

Martes 20 de febrero de 2018

Lenin Hernandez

Lenin Hernandez
Leninmhs

Como enviar correos desde Perl usando Gmail

En esta entrada tendremos realizaremos el envió de correo desde el SMTP de Gmail usando el lenguaje de programación Perl para realizar esta tarea, específicamente usando el modulo Email::Sender. Perl es un lenguaje muy común para escribir scripts, por lo cual, es muy útil poder enviar de correos electrónico desde el. En Perl existen varias … Sigue leyendo Como enviar correos desde Perl usando Gmail

Jueves 01 de febrero de 2018

Curso: Gestión de proyectos Software con Git y GitHub

Independiente si te mueves por el mundo del desarrollo, la administración de servidores o simplemente eres una mente inquieta en...

La entrada Curso: Gestión de proyectos Software con Git y GitHub aparece primero en Nosinmiubuntu | Ubuntu en concreto, GNU/Linux en general.

Miércoles 31 de enero de 2018

Curso: Desarrollo en HTML5, CSS y Javascript de Apps Web, Android e IOS (8ª edición)

Retomamos las publicaciones en la web para hablaros de la próxima edición del curso gratuito Desarrollo en HTML5, CSS y...

La entrada Curso: Desarrollo en HTML5, CSS y Javascript de Apps Web, Android e IOS (8ª edición) aparece primero en Nosinmiubuntu | Ubuntu en concreto, GNU/Linux en general.

Lunes 22 de enero de 2018

TutorialesLinux.com: Borrar un volumegroup y extender el principal