Martes 28 de marzo de 2017

Baltasar Ortega

Baltasar Ortega
KDE Blog

Se inician las votaciones de los Open Awards 2017

Hace un tiempo hablamos de OpenExpo 2017 hoy quiero comentar que una de las novedades más destacadas de la edición anterior ya ha pasado a su segunda fase. En otras palabras, ya se inician las votaciones de los Open Awards 2017, los premios que nacieron con la intención de consolidarse en el mundo del Software Libre como un referente anual y van en camino a conseguirlo.

Se inician las votaciones de los Open Awards 2017

En 2016 nacieron los Open Awards 2016, unos premios que tienen la intención de reconocer a las empresas y administraciones que crean y fomentan grandes soluciones con tecnologías Open Source en España. Tiene por objetivo fomentar, apoyar, reconocer y premiar los proyectos de código abierto y conocer las iniciativas Open Source más destacados del año

  • Reconocer y premiar los proyectos que más han destacado durante el último año.
  • Impulsar la comunicación y la notoriedad pública de las empresas, medios y administraciones participantes en los premios.
  • Valorar el trabajo realizado por muchas empresas, medios y administraciones públicas.

Se inician las votaciones de los Open Awards 2017

En su primera edición este blog se llevó el primer puesto en la categoría de mejor medio de los Open Awards 2016, gracias a todos por vuestro apoyo, pero este año, por diversas razones, no se ha inscrito. Y eso que han insistido incluso vía telefónica, aprovecho estas líneas para agradecer este detalle.

Este año siguen con su segunda edición de los Open Awards 2017, cuya nota de prensa es la siguiente:

“La convocatoria de los premios Open Awards – el mayor reconocimiento del sector Open Source & Software Libre – organizados por la Feria y Congreso OpenExpo, ha superado con creces todas las expectativas.
Los galardones más codiciados del mundo de las tecnologías abiertas, reconocen y premian los proyectos e iniciativas de código abierto más destacados, impulsan la notoriedad pública de las empresas, proyectos y administraciones participantes en los premios y valoran el trabajo realizado por todos ellos.
El próximo 3 de mayo se darán a conocer los nombres de los finalistas de los Open Awards, que en su segunda edición ha contado con la participación de 132 empresas y proyectos del sector. Esta cifra supone un incremento del 97% de la participación con respecto al año anterior.
Empresas de renombre como Liberty Seguros, Arsys, Toyota, Petronor, Eroski, Red Hat, Agencia Tributaria, Ediciones SM, BQ, gigas y lastminute.com, han presentado su candidatura a los premios y junto al resto de participantes, están esperando tu voto.
Conoce a todos los nominados y vota por tus empresas y proyectos favoritos para conseguir que se coloquen entre los 5 primeros de su categoría convirtiéndose así automáticamente en finalistas.
El acto de entrega de los Open Awards tendrá lugar el jueves 1 de junio dentro del marco de OpenExpo 2017 en La N@ve (Madrid), evento al que ya han confirmado su participación empresas como Microsoft, Arsys, OVH, Exevi, OTRS, Carto, Magnolia, Hopla! Software, Docker, WhiteBearSolutions, Bacula Systems, ackstorm, Google Cloud y mdtel, entre muchas otras.

Anímate y vota, tienes hasta el 30 de abril para hacerlo.

 

Lunes 27 de marzo de 2017

Miguel Parada

Miguel Parada
Ubuntizando.com

No sin mi permiso. La importancia del opt in en tus comunicaciones comerciales

Hoy quiero hacer un pequeño paréntesis y hablar de algo que creo que es importante tener en cuenta. Con esto La entrada No sin mi permiso. La importancia del opt in en tus comunicaciones comerciales aparece primero en Ubuntizando.com.

Para leer completa esta publicación haz click sobre el título
Gaspar Fernández

Gaspar Fernández
Poesía Binaria

Aplicaciones web sin servidor, o casi (arquitecturas serverless)


¿Cómo es esto posible? Si tenemos una cosa clara en el mundo de Internet es que si queremos tener en pie un servicio, éste debe estar alojado en una máquina que esté conectada a Internet, con energía y que nos asegure en cierta forma que está levantada. Estos servidores pueden ser de diversos tipos según las necesidades de la aplicación: web, base de datos, autentificación, tareas, logs, notificaciones, etc. Así que, ¿qué es esto de aplicaciones sin servidor? ¿o serverless?

¿Sin servidor? Serverless?

En realidad, este término no tiene que ver con que exista físicamente un servidor o no, sino con el hecho de delegar su administración a un tercero. Al mismo tiempo, nosotros no pedimos un servidor, pedimos un servicio Por lo que este término se aplica siempre que no tengamos que administrar el servidor que ejecuta un servicio, es más, en muchos casos, no sabemos sus características ni tenemos acceso a él más allá del servicio que ejecuta. Es más, el proveedor nos da un punto de entrada para poder llamar al servicio, y lo que haya por detrás será todo un misterio. Ellos nos garantizan el servicio encargándose de todo.

Esto pueden ser aplicaciones en la nube (ay la nube, ese gran desconocido, literalmente), como bases de datos, servidores de autentificación, incluso APIs para nuestras aplicaciones. Esto se utiliza sobre todo para aplicaciones móviles, en las que disponemos de un frontend y por detrás se hacen llamadas a servicios web que a su vez pueden hacer llamadas a otros servicios, todos remotos. Esto se suele llamar BaaS (Backend as a Service).

Por otro lado, algo que está muy de moda últimamente es la ejecución de funciones como servicio o FaaS (Functions as a Service), de hecho casi siempre que escuchemos algo sobre Serverless se referirán a esto y no es más que el alojamiento y ejecución de código por un tercero en contenedores de cómputo descentralizados y administrados por un tercero. Estos terceros suelen ser IBM, Google, Microsoft, Amazon, etc En definitiva, nuestro código no sabemos dónde se aloja ni dónde se ejecuta, sólo sabemos cómo llamarlo y cómo ver la respuesta de la ejecución. Es más, dependiendo del uso que hagamos de esta tecnología puede que haya muchas máquinas ejecutando nuestro código a la vez, sirviendo respuestas para nuestras aplicaciones… y todo sin tener que montar ni contratar un servidor.

Como hemos podido ver, estas soluciones son administradas, es decir, tampoco necesitamos que nadie se tome molestas para encargarse de la seguridad del servidor, balanceo de carga, actualizaciones de software, direccionamiento, almacenamiento, ni nada. Sólo debemos encargarnos de subir nuestro código y listo. Pero claro, eso de Serverless, seguro que se le ocurrió a uno de marketing porque suena muy bien. Está claro que servidor sí que hay, pero bueno, no tenemos que prestarle mucha atención.

¿Para qué quiero yo esto?

El objetivo, además de que es algo muy moderno, por un lado es que se reducen costes. Aunque hay que mirarlo con lupa y estudiar casos concretos. Es decir, para una empresa, el tiempo de un empleado supone dinero y el tiempo que el empleado invierte en tareas de mantenimiento de un servidor, significa una inversión económica. Además, tener una máquina contratada para realizar un servicio determinado es también una inversión económica, generalmente en forma de alquiler mensual y esto cubre momentos en los que se está utilizando el servicio y momentos en los que no hay nada utilizándose. Y normalmente, las empresas que facilitan este tipo de servicios cobran por el tiempo de uso de los servicios.

Por otro lado, nos garantiza la escalabilidad de los servicios (escalabilidad? Introducción a la escalabilidad de aplicaciones web. Técnicas, opciones, seguridad y consejos.). Ya que, en el caso de FaaS, sólo ejecutamos funciones, estas funciones podrán conectar con bases de datos y utilizar servicios externos, pero gozan de independencia de la máquina donde se ejecutan por lo que podremos llamar al servicio las veces que necesitemos, simultáneamente y no debemos tener ningún problema en la disponibilidad (no es plan de hacermos un DDOS tampoco). En el caso de BaaS también estamos llamando a servicios independientes por lo que el escalado no es un problema.
El caso es que el tema del escalado, que bien nos puede suponer un quebradero de cabeza de esta forma es transparente a nosotros y lo harán los servicios de manera natural.

Paranoico de mí

Pero claro, estamos dependiendo de un tercero, o de varios terceros, no tenemos control sobre la infraestructura, en muchos casos ni podemos visitarla, internamente no sabemos cómo funciona (más allá de lo que nos cuentan), puede que hasta desconozcamos la versión exacta del software que ejecutan estos contenedores. Aunque es verdad que las empresas muestran gran transparencia en sus operaciones no es lo mismo que si lo hicieras tú.
Siguiendo con la dependencia, la supervivencia de nuestras aplicaciones depende por completo de los servicios del tercero que contratamos. Eso quiere decir que si la empresa cambia sus condiciones (empeorándolas) tenemos un problema, si hacen una actualización de software y nuestro código no es compatible, tenemos otro problema gordo, si la empresa cierra (recordemos que todos los imperios han caído tarde o temprano), tenemos un problema más gordo aún y cambiar de empresa puede ser otro problema si no lo abordamos desde el principio.

No es lo mismo contratar un VPS con un sistema operativo donde podemos copiar los archivos de nuestra aplicación y desplegar (más o menos) que si tenemos que realizar cambios en nuestra aplicación para hacer llamadas a los servicios que hemos cambiado de empresa. Normalmente cada una tiene sus APIs para garantizar los accesos a sus servicios, autentificación de las llamadas, disparadores, etc. Aunque todos suelen tener partes comunes, también tienen sus particularidades.

¿Para qué lo podemos usar?

Lo primero, para tener todos los bloques de nuestra aplicación de Internet separados y bien diferenciados, lo que nos ayudará a crecer más rápidamente y como dijimos antes, la escalabilidad será algo natural.

Aunque ahora me voy a centrar un poco más en FaaS. Es decir, lo que haremos con este tipo de servicio es simplemente la ejecución de código. Una función, por ejemplo hecha en Python que tiene que ejecutarse en alguna ocasión. ¿Cuándo? Generalmente estas funciones se ejecutarán cuando se dispare un evento del tipo: petición web, entrada de datos en base de datos, inserción de mensaje en un log, creación de una notificación, entrada de un usuario determinado, nuevos archivos en servidores de almacenamiento y mucho más.

Normalmente nuestra aplicación tendrá un servidor web de entrada, que sí lo gestionamos nosotros (ese es nuestro VPS, o nuestros servidores balanceados), pero ahí vamos a incluir el código más básico posible: generación de páginas a partir de las plantillas, obtención sencilla de datos, control de sesiones, y poco más.

Por ejemplo, si tenemos en base de datos toda la información de ventas anual y queremos crear una gráfica resumen con todo y algunos datos estadísticos, seguramente si hemos vendido mucho debemos hacer cientos de cálculos y podemos encargárselos a otro liberando algo de carga en nuestro servidor, aunque el la entrada/salida de nuestra base de datos va a tener impacto igual, pero los cálculos y el trabajo de memoria y CPU para extraer medias, periodos, tendencias y demás se lo lleva otro. Todo esto lo podemos extender a todas aquellas tareas que sean un poco más pesadas de la cuenta. A lo mejor no tardan mucho tiempo, pero involucran sobre todo CPU y memoria y puede perjudicar el rendimiento global de nuestra aplicación. Estas tareas pueden ser: grandes importaciones/exportaciones de datos, generación de imágenes o miniaturas, generación de vídeos, etc.

En el lado del programador

El número de lenguajes es limitado y lo pone el proveedor del servicio. Contamos con lenguajes más o menos famosos y útiles como Python o NodeJs, en algunos sistemas podremos ejecutar Java o C#. Es normal que todos los lenguajes no estén soportados, porque hay que preparar los entornos de ejecución para que sea seguro utilizarlos y, supongo que con el tiempo se podrá ampliar el número de lenguajes soportados. Esto también puede causar dependencias, ya que puede que un proveedor soporte un lenguaje y otro no.

Por el lado de los desarrolladores, tenemos que contar con herramientas que nos permitan desarrollar el código de estos servicios de forma sencilla. Como la forma más común y sencilla de disparar los eventos es con peticiones HTTP. Actualmente hay sistemas que nos permiten crear un pequeño servidor local que atiende estos tipos de peticiones y ejecuta el código seleccionado. Luego, cuando pasemos el código a nuestro servidor sólo tendremos que cambiar el punto de acceso al servicio (que no será local, será el que nos dé nuestro proveedor). Y todo porque desarrollar desplegando todo el rato es muy feo.

Es conveniente también automatizar los despliegues. Y tenemos herramientas para ello, pero dependen del proveedor que cojamos. Sólo tendremos que crear un script o un archivo de instrucciones de despliegue y ya podremos usarlo para desplegar. Lo bueno es que esta tecnología nos permite crear tantos eventos como queramos, y tenemos la posibilidad de tener varios entornos, testing y producción por ejemplo, y sólo tenemos que cambiar el punto de entrada.

Tenemos que tener en cuenta que las funciones que ejecutamos deben estar lo más optimizadas posible, porque nos cobrarán por tiempo de ejecución, por lo tanto, las funciones deben estar bien definidas, tener un único objetivo y evitar entrar en bucles infinitos o esperas innecesarias. Eso sí, estas funciones podrán disparar eventos que ejecuten otras funciones en el futuro, así que tendremos que tener un poco de cuidado para que nuestras funciones no se pisen las unas a las otras…

Resumiendo

Para no agobiarnos mucho, con esta tecnología, definiremos una serie de eventos que, cuando se disparen, ejecutarán un fragmento de código en un ambiente de ejecución o contenedor controlado. Este código se ejecutará y el contenedor se destruirá. Si la función tiene que ejecutarse muchas veces, incluso simultáneamente, el proveedor se encarga del escalado/encolado/etc.

Estas funciones pueden conectar con otros servicios de base de datos, almacenamiento u otros tipos de servidores, incluso disparar la ejecución de otras funciones.

En próximos posts voy a contaros mi experiencia trabajando con Amazon Lambda

Referencias

No te pierdas estos sitios con interesantes lecturas sobre arquitectura Serverless:

The post Aplicaciones web sin servidor, o casi (arquitecturas serverless) appeared first on Poesía Binaria.

Asociación LiGNUx: Tutorial para instalar la versión de mantenimiento del kernel Linux 4.10.6
Baltasar Ortega

Baltasar Ortega
KDE Blog

Las herramientas de Okular, optimizando tu trabajo con el visor

Hace mucho tiempo, el blog tenía una sección llamada “A fondo…” donde se analizaba en profundidad una aplicación. Lamentablemente, por falta de tiempo, esa sección quedó aparcada y de ella solo quedan retazos como el siguiente artículo llamado “Las herramientas de Okular” donde se quiero analizar un aspecto de la aplicación.

Las herramientas de Okular

Las herramientas de OkularHace poco comenté la magnífica funcionalidad de Okular a la hora de trabajar con tablas. Al realizarlo me di cuenta que el menú de herramientas había crecido un poco desde que hablé de él hace unos años, o al menos esa sensación me quedó.
Hoy me gustaría comentar con más detenimiento todo lo que nos ofrece el menú de herramientas de esta magnífica aplicación de la Comunidad KDE.

  • Herramienta de navegación: Con este modo nuestro puntero se convierte en una mano con la que podemos ir moviendo el documento arriba/abajo – izquierda/derecha según nuestras necesidades con el botón izquierdo del ratón. El atajo de teclado es Crtl + 1.
  • Herramienta de zoom: Si pulsamos Crtl+2 o seleccionamos este modo, nuestro cursor se convierte en una lupa con la que podemos seleccionar una área determinada del documento y ésta se amplía al máximo. Con el botón derecho nos alejamos del documento.
  • Herramienta de selección: Esta es la funcionalidad que suelo utilizar con más frecuencia. En este modo podemos seleccionar un trozo del documento y Okular nos mostrará varias opciones. La primera es coger lo seleccionado como texto para copiarlo o buscarlo en la web. La segunda es que la selección se quede como una captura de imágen. Se accede a ella con Crtl + 3.
  • Herramienta de texto: Con este modo solo seleccionamos el texto línea a línea. Se activa con Crtl + 4 y es la más recomendada para extraer el texto del documento.
  • Herramienta de selección de tabla: Esta es la funcionalidad con la que podemos seleccionar tablas y que Okular las reconozca como tal. Se activa con Crtl + 5 y si os interesa os aconsejo leer este artículo.
  • Herramienta de ampliación: Con este modo, el trozo del documento bajo del cursor se ampliará el factor que configuremos cuando pulsemos el botón izquierdo del ratón. Ideal para destacar algo de nuestro documento. Se activa con Crtl + 5.

Las herramientas de Okular

En fin, 6 modos diferentes del comportamiento para las acciones con el ratón sobre el documento.

Miguel Parada

Miguel Parada
Ubuntizando.com

Horbito: SO en la nube

¡Hola a todos! Hoy vengo a hablaros de una propuesta que me parece interesante dentro de los famosos sistemas operativos La entrada Horbito: SO en la nube aparece primero en Ubuntizando.com.

Para leer completa esta publicación haz click sobre el título
Miguel Parada

Miguel Parada
Ubuntizando.com

Cómo comprimir y descomprimir archivos en Linux usando el terminal

Ya no es muy habitual usar el terminal para gestionar archivos. No para el usuario medio de escritorio pero alguna La entrada Cómo comprimir y descomprimir archivos en Linux usando el terminal aparece primero en Ubuntizando.com.

Para leer completa esta publicación haz click sobre el título

Domingo 26 de marzo de 2017

Asociación LiGNUx: Otro año más participamos en el concurso Open Awards organizado en la Open Expo
Baltasar Ortega

Baltasar Ortega
KDE Blog

6 distribuciones GNU/Linux con Plasma 5, 6 vídeos llenos de diversidad

Finalmente, y como no podía ser de otra forma por el gran trabajo de la Comunidad KDE, el escritorio Plasma 5 ha conquistado la gran mayoría de escritorios de distribuciones GNU/Linux. Así que ha llegado el momento de realizar un breve compendio en forma de vídeo de diferentes 6 distribuciones GNU/Linux con Plasma 5. Una forma de ver la variedad de formas que puede adquirir el entorno de trabajo más versátil y potente del Software Libre.

6 distribuciones GNU/Linux con Plasma 5

6 distribuciones GNU/Linux con Plasma 5

En Kaos

De la mano de Jorge Dangelo nos llega un pequeño vídeo de Plasma 5.9 corriendo sobre KaOS, la famosa distribución GNU/Linux que destaca por su amor por Qt y KDE.

En KDE Neon

En esta ocasión el vídeo nos lo ofrece sunny khatri, el cual nos muestra en casi 6 minutos algunas de las virtudes de Plasma 5.9 en el proyecto KDE Neon.

 

En openSUSE Tumbleweed

No podía faltar en esta lista una visión de Plasma 5.9 en la distribución GNU/Linux Rolling de openSUSE de la mano de DeltaSonic en un vídeo un poco más largo que los anteriores.

En Kubuntu

Si queréis pasar un rato largo viendo Plasma 5.9 funcionando sobre Kubuntu 17.04 no os podéis perder el siguiente vídeo de Md Imam Hossain, donde a lo largo de más de 40 minutos nos repasa el entorno Plasma de principio a fin: Preferencias del sistema, Discover, plasmoides, Dolphin, Krunner, etc.

En Manjaro

No podía faltar Manjaro, una distribución GNU/Linux que está muy de moda y que recibe muy buenas críticas. En esta ocasión nos llega de la mano de FC2 Linux y tiene una duración de poco más de 11 minutos, donde se puede apreciar el buen gusto visual que desprende esta distribución.

En ArchLinux

Y para finalizar, el vídeo más corto de la lista donde vemos una sesión de alireza amirsamimi mostrando su Plasma 5.9 sobre ArchLinux, otra rolling release que sigue en plena forma.

 

Sábado 25 de marzo de 2017

Asociación LiGNUx: La beta final de Ubuntu 17.04 Zesty Zapus ya esta disponible
David González

David González
Blog Bitix

Ejemplo de JNI, usar código en C desde Java

Para tareas muy específicas que requieran alto rendimiento, baja latencia, tiempo real o haya restricciones de tiempo el lenguaje Java y la JVM pueden mostrar algunas limitaciones obligando a escribir alguna sección crítica de un programa en un lenguaje nativo como C o C++. Para hacer posible la integración entre Java y C existe en Java la API JNI. En este artículo mostraré como realizar un programa Java que emite el mensaje Hola Mundo desde una biblioteca compartida en C y usando JNI.

Java
SVG
Linux

Nunca hasta ahora había tenido necesidad de crear un programa que no estuviese completamente escrito en el lenguaje Java. La API de Java ofrece multitud de clases para cualquier funcionalidad que necesitemos desde estructuras de datos hasta algoritmos de búsqueda o criptografía. También porque el rendimiento de un programa en Java es suficiente y similar a un programa equivalente escrito en C o C++ gracias a las optimizaciones que implementa la máquina virtual de Java o JVM aún siendo los programas Java compilados a una representación intermedia de bytecode independiente de la arquitectura de procesador y sistema operativo en archivos de extensión class y posteriormente interpretados y traducidos a la arquitectura de ejecución, lo que le proporciona a Java la conocida frase “Write once, run anywhere”.

Sin embargo, en casos que se necesita un alto rendimiento para tareas muy específicas o evitar las imposiciones de la máquina virtual como las paradas que realiza para el recolector de basura una solución es escribir esa funcionalidad crítica en lenguaje C, C++ e incluso en Go. El caso de necesidad que me he encontrado es acceder a un sensor de temperatura DHT11 del kit de iniciación a la electrónica para la Raspberry Pi para leer de él la temperatura y humedad. La forma que tiene el sensor DHT11 de proporcionar los datos tiene restricciones de tiempo, cuando se le requieren los valores envía 80 bits de datos donde un pulso de 27μs significa un 0 y un pulso de más de ese tiempo hasta 70μs significa un 1. Estas restricciones de tiempo del sensor y el hecho de que es en una modesta en potencia Raspberry Pi 1 donde lo usaré hace que Java no sea capaz de leer correctamente los valores del sensor.

Acceder desde Java a código nativo en C requiere usar Java Native Interface o por sus siglas JNI. Lo primero que hay que realizar es crear una clase que declare los métodos que serán implementados de forma nativa declarando estos métodos usando la palabra reservada native y que serán enlazados por la JVM cargando una librería compartida con System.loadLibrary(). Creada la clase Java se ha de generar el archivo de cabecera .h propia del lenguaje C con el programa de utilidad del JDK javah. Con el archivo de cabecera se implementa la función y se crea una librería compartida en GNU/Linux usando el compilador gcc. Con la librería compartida se puede iniciar el programa Java. Si la biblioteca compartida no se encuentra se lanzará una excepción del tipo UnsatisfiedLinkError.

Excepción UnsatisfiedLinkError cuando no se encuentra la librería de código nativo

Algunas otras necesidades para hacer uso de JNI son:

  • Acceder a características dependientes de la plataforma necesitadas por la aplicación que no están soportadas en la librería estándar de Java.
  • Ya hay una librería escrita en otro lenguaje y se quiere hacer accesible a código Java a través de JNI.
  • Se quiere implementar una pequeña parte de código crítico en un lenguaje de bajo nivel como ensamblador.

Desde los métodos de código nativo se puede:

  • Crear, inspeccionar y actualizar objetos Java (incluyendo arrays y strings).
  • Llamar a métodos Java.
  • Capturar y lanzar excepciones.
  • Cargar y obtener información de clases.
  • Realizar validación de tipos en tiempo de ejecución.

Los comandos para generar el archivo de cabecera de C y compilarlo con el código nativo en una librería compartida con gcc son:

La cabecera usa varias definiciones de tipos definidas en los archivos jni.h y el archivo que variará según el sistema operativo jni_md.h. En la estructura JNIEnv con múltiples funciones de integración en C y Java, también varias definiciones de los tipos Java para usarlos en C como jobject, jstring, jint, jboolean, jlong, jdouble, jchar, etc.

El programa que emite el mensaje Hello World! desde código nativo en C debe cargar y enlazar la librería de código nativo con el código de la clase Java. Esto se muestra en el bloque de inicialización static de la clase, en este caso usándo el método System.load(), la librería de código nativo de extensión .so en GNU/Linux como en este caso al construirse el proyecto se incluye en el archivo .jar del artefacto resultante se extráe al directorio temporal y se carga desde esa ubicación temporal. En el programa se llama al método print implementado en código nativo y en el código C se usa la función printf de la librería stdio para emitir el mensaje:

La librería compartida para un sistema amd64 la he compilado en mi equipo de escritorio y para la versión arm en la Raspberry Pi e incluido en el directorio src/main/resources de código fuente del ejemplo.

Mensaje en la terminal emitido desde código nativo en un sistema amd64 y ARM

Ente ejemplo usa Java 8 y requiere instalar el compilador gcc para compilar la librería con código nativo. Gradle ofrece soporte para compilar código nativo con su plugin, sin embargo, he preferido usar y conocer los comandos javah y gcc sin usar Gradle. En el siguiente artículo mostraré el ejemplo del sensor DHT11 usando JNI y código nativo en C llamando a métodos de un objeto Java desde código C.

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

Jueves 23 de marzo de 2017

Lingua Franca: una nueva versión de Heuristica

Este artículo es parte de la serie Recomendando fuentes tipográficas Hoy toca a una nueva versión de la fuente Heuristica que si bien ha sido pensada para lingüistas puede utilizarse en otros ámbitos: Lingua Franca Esta fuente, desarrollada por Andreas Nolda, es muy parecida a otra de la que hablamos en estas páginas hace ya […]

Webminal, aprende a manejar la consola de Linux sin esfuerzo

¿Eres de los que piensa en Linux y sólo ve la consola?, ¿te da miedo dar el paso porque no sabes dónde aprender los comandos más básicos?, ¿te aburren los manuales de quinientas páginas?. Si has respondido a cualquiera de estas preguntas que si, este artículo es para ti, no dejes de leer. Y es que hoy os traemos una nueva forma de aprender los comandos de linux, pero mucho más

Miércoles 22 de marzo de 2017

BlogDRAKE: La magia sigue viva

Lunes 20 de marzo de 2017

Pedro L. Lucas

Pedro L. Lucas
Cartas de Linux

Off-topic: El cambio climático y lo que no hacemos por evitarlo

Me gustaría enseñaros un vídeo que muestra la evolución del CO2 en la atmósfera durante un año. Evidentemente es una simulación por ordenador, pero tiene algunas cuestiones interesantes:

  • Durante los meses de primavera y verano, la fotosíntesis se ve favorecida, se puede ver muy claramente la absorción del CO2 por parte de los árboles (el efecto es espectacular).
  • La mayoría de los países desarrollados parece que estén ardiendo del CO2 que emiten.
  • El modelo también muestra la evolución del CO (no CO2), un gas altamente perjudicial.

El vídeo está en inglés, pero se viendo las leyendas de la parte inferior se puede entender la evolución del CO2:

Todos sabemos que el CO2 es uno de los responsables del efecto invernadero, pero no el único:

Basado en el vídeo anterior, hay otro que ofrece más información:

Vamos hacer unos números. He buscado por Internet la cantidad de CO2 que absorbe un árbol en un año y obtengo que es del orden de 10 kg de CO2 al año por término medio. Aunque esta cifra varía mucho en función del tamaño del árbol y su etapa de crecimiento.

Supongamos que un ordenador gaste al año del orden de 200 kWh. En la producción de esos 200 kWh se emiten 130 kg de CO2. Por lo tanto, se necesitan 13 árboles para compensar el CO2 que emite un ordenador.

¿Y un coche que haga 20000 km al año? Según este enlace, emite unas 3 toneladas de CO2, aunque según otros sitios las emisiones podrían ser de 2’5 toneladas anuales. Serían necesarios de 250 a 300 árboles para compensar sus emisiones anuales.

En hacer esos 20000 km un tren emite del orden 250 kg de CO2 por pasajero. Por lo que se necesitarían 25 árboles para neutralizar sus emisiones.

¿Y en la fabricación? En fabricar un teléfono móvil se generan gran cantidad de contaminantes. Se estima, por ejemplo, que en la fabricación de cada unidad de iPhone 6 se generan 80kg de CO2, en el transporte hasta la tienda unos 3kg y en su reciclaje 1kg. El usuario se estima que sólo emitirá del orden de 10kg de CO2 por usarlo. En general en los aparatos electrónicos, se contamina más al fabricarlos que lo que el usuario contaminará debido a su uso.

¿Cuántos árboles hay en el mundo? Se estima que hay del orden de 3 billones de árboles. 15 mil millones de ellos son talados cada año.

¿Cuántos coches hay en el mundo? Se estiman que unos mil millones.

Y ahora hago la siguiente cuenta si cada coche hiciera 20000km anuales, emitiendo 3000kg de CO2 al año, emitirán 3.000.000.000.000kg de CO2 al año, los árboles absorben 30.000.000.000.000kg de CO2 al año. Es decir que sólo con los coches estamos contrarrestando la absorción de un décimo del CO2 por parte de los árboles. La cosa preocupa un poco pues a parte de los coches CO2 producen las fábricas, las centrales térmicas, la mayoría de las calefacciones, los seres vivos,…

En esta guerra coches vs árboles, van ganando los coches claramente, como muestra el siguiente vídeo de la evolución del CO2 en la serie temporal:

Está claro que algo estamos haciendo mal, pero… ¿qué hacemos por evitarlo? Yo prácticamente nada. Tengo muchos buenos propósitos, pero si he de hacer un trayecto por ocio, en el cual el tiempo que tarde me da igual, cogeré el coche. Tengo las tres bolsitas de basura para reciclar, pero en mi entono soy de los únicos. A veces por pequeños gestos, como el de guardar un plástico en el bolsillo para tirarlo en su contenedor correspondiente, hacen que me tilden de friki (sí, me ha sucedido).

Tal vez habría que decir basta y cambiar ciertas costumbres: Limitar el uso del coche y no usarlo si hay una alternativa menos contaminante. Usar los aparatos electrónicos hasta que literalmente revienten y no dejarse guiar por modas absurdas que intentan obligarnos a cambiar de móvil cada dos años (por ejemplo). Reusar todo lo que se pueda reusar, como los envases. Reciclar cuando algo llegue al final de su vida útil. Ahorrar energía (apagar la luz y otros dispositivos cuando  no se usen)…

Me temo que sólo tengo buenas intenciones y volveré a coger el coche, comprar el móvil de última generación, o tirar el papelito al suelo mientras digo: ¡Qué sucias están las calles y este ayuntamiento no limpia!

Termino con unas palabras que se atribuyen a los Indios Cris del Canadá: “Cuando hayáis talado el último árbol, matado el último animal y contaminado el último río os daréis cuenta de que el dinero no se come… “


BlogDRAKE: 3 de mis imagenes estaran en Mageia 6

Domingo 19 de marzo de 2017

David González

David González
Blog Bitix

Introducción y ejemplo de cluster de contenedores con Docker Swarm

Las funcionalidades de Docker Swarm están incorporadas en Docker para gestionar clusters de nodos con contenedores de los servicios que deseemos. En artículo comentaré algunas de las propiedades de networkning distribuido incorporado en Docker, como crear un cluster de nodos Docker usando VirtualBox con máquinas virtuales para simular múltiples máquinas junto con como lanzar un servicio en el cluster que en este caso consistirá en un servidor web nginx.

Docker

En artículos anteriores de la serie sobre Docker comentaba varias de las herramientas de Docker como Docker Compose, Dockerfile o Docker Machine con ejemplos de como usarlo en local. Una de las herramientas que me quedaba por investigar era Docker Swarm para crear clusters de nodos para contenedores Docker en un entorno de producción. A partir de la versión 1.12 de Docker se han incorporado varias características a Docker para usaar contenedores de forma distribuida y que a pesar de la complejidad subjacente que debe haber es realmente simple usarlo.

Una de las características es el networking que hace trasnparente la comunicación en red distribuida que se hace entre los nodos y los contenedores de esos nodos. Además permite crear redes por software para que los contenedores conectados a esas redes se comuniquen de forma privada. Otra característica interesante de Docker Swarm es que se encarga de monitorizar el estado de los servicios recreando contendores si alguno deja de funcionar. También a través del denominado routing mesh da igual al nodo del cluster por el que se acceda y da igual en que nodo esté el contenedor que Docker Swarm con esta propiedad se encargará de hacer llegar la petición al contenedor. Además, a lo que en Docker Swarm se denomina servicio se realiza balanceo de carga entre la instancias del mismo que haya en el cluster y al servicio se le asigna un DNS y dirección IP por el que puede ser accedido por otros servicios.

En el siguiente ejemplo para crear el cluster de nodos Docker usaré Docker Machine para crear las máquinas de los nodos en máquinas virtuales de VirtualBox aunque su funcionamiento es similar si usásemos la nube de Amazon EC2, Digital Ocean u otros.

El siguiente script crea primeramente varios nodos cada uno en una máquina virtual, luego establece el nodo 01 como manager y los nodos 02 y 03 como workers usando un token para unirlos al cluster según su rol. Los nodos manager se encargan de mantener el estado del cluster y los que a través de ellos los comandos de los servicios deben ser lanzados, en un entorno de producción posiblemente tendríamos 3 nodos manager para soportar tolerancia a fallos. Finalmente, se obtiene lista los nodos del cluster. El comando docker-machine env node-01 permite establecer el entorno contra el que el comando docker lanzará las operaciones como si de la máquina local se tratase.

Una vez creado los nodos es cuando podemos empezar a crear servicios en el cluster. Los servicios son una definición de los contenedores de Docker que queremos que el cluster ejecute. En el ejemplo definiré el servicio de un servidor web nginx, primeramente crearé una red por software en el cluster a la que los servicios pueden conectarse que en el ejemplo (aunque para este no es necesario) utilizaré para hacer una consulta DNS con la herramienta drill para ver el nombre de dominio y dirección IP que asigna Docker Swarm al servicio del servidor web. Con docker service create se crean los servicios, algunos de los parámetros del comando son el nombre del servicio que queremos asignarle, los puertos que expone en este caso el 80 y 443 en el host para que sea accesible desde fuera del cluster, la redes a las que está conectado y finalmente la imagen del contenedor del servicio que en este caso será la versión de nginx con Alpine para Docker. Se pueden listar los servicios que contiene el cluster con docker service ls y los procesos de cada nodo donde podemos ver en que nodos se está ejecutando los contenedores con docker ps.

Una de las propiedades interesantes del networking de Docker Swarm es que ofrece incorporado balanceo de carga, esto es, si el servicio de nginx del ejemplo estuviese formado por dos instancias las peticiones se distribuirían entre las instancias usando el método round-robin. Otra característica interesante si se observa el ejemplo con detalle es que da igual el nodo al que hagamos la petición que la respuesta se obtendrá igualmente, esto es, aunque la petición se haga al nodo 01 y realmente el contenedor del servidor nginx se esté ejecutando en el nodo 02 la petición se realizará correctamente gracias al routing mesh del neworking de Docker Swarm, esto es gracias a que cada servicio tiene asignada una dirección IP, como se ha visto anteriormente en la salida del comando drill.

En este vídeo de asciinema se ve en funcionamiento todos los anteriores comandos. Y en la aplicación de VirtualBox estarán las máquinas virtuales de cada uno de los nodos que crea el ejemplo. En el vídeo se aprecia que el servicio de nginx se está ejecutando en el nodo 02 cuando se listan los procesos de Docker de cada nodo con docker ps, nótese sin embargo que al hacer un petición HTTP a cualquiera de los nodos se devuelve la página de inicio de nginx ya que gracias al routing mesh de Docker Swarm la petición se redirige de forma transparente para el cliente y el servicio al nodo donde realmente se está ejecutando el contenedor de nginx.

<noscript><a href="https://asciinema.org/a/107868" target="_blank"><img src="https://asciinema.org/a/107868.png" width="734" /></a></noscript> Introducción y ejemplo de cluster de contenedores con Docker Swarm
Máquinas virtuales de los nodos del cluster de Docker Swarm

Los comandos para eliminar un servicio del cluster y eliminar completamente el cluster son los siguientes.

Un libro que me ha gustado mucho y que recomiendo leer sobre Docker Swarm es The Devops 2.1 Toolkit que lo explica detalladamente y todo el libro está orientado a como usarlo en un entorno de producción. Un libro más introductorio que también he leído y que está bastante bien es Docker in Action.

Finalmente, quizás si estás usando GNU/Linux y VirtualBox como yo al crear los nodos con el comando docker-machine te produzca el siguiente error (quizá se corrija en futuras versiones de Docker o VirtualBox).

La solución que he encontrado para que funcione es asignar una dirección IP al adaptador puente solo-anfitrión y levantar la interfaz que usa Docker para comunicarse con las máquinas virtuales previamente a crear el nodo. En Arch Linux con los siguientes comandos.

Se puede definir un conjunto de servicios como una unidad en un archivo en stacks de forma similar a como es posible hacer con Docker Compose cosa que mostraré en otro artículo.

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

David González

David González
Blog Bitix

Controlar un display LCD 1602 para mostrar texto con la Raspberry Pi y Java

Raspberry Pi
Java

Uno de los motivos por los que compré el kit de iniciación a la electrónica para la Raspberry Pi, además de cacharrear un poco, era en concreto controlar el display LCD de 16 columnas y 2 filas. En el kit el display viene con un adaptador con el bus de comunicación I2C. El display se puede usar sin este bus pero requiere utilizar muchos más pines GPIO de datos de los limitados 17 que ofrece la Raspberry Pi 1 y los 26 de las Raspberry Pi B+, 2 y 3. Controlar el display con I2C requiere únicamente 2 pines, por contra sin usar I2C requiere un número significativamente mayor 4 u 8 pines.

El display 1602 con su adaptador para el bus I2C que viene con el kit ya incorporado en la parte trasera es el siguiente.

Display LCD 1602 y adaptador bus I2C

El esquema de conexionado para controlar el display requiere usar los pines de la Raspberry Pi SDA y SDL además de un pin para proporcionar un voltaje de 5V y otro pin para la tierra. El pin SDA es el número 2 según la numeración de pines de la Raspberry Pi y el SDL es el 5. El pin SDA es utilizado en el bus I2C para transmitir los datos y el SDL para la señal de reloj o sincronización. Utilizando la placa de extensión wiringPi de 26 pines los pines SDA y SDL se encuentran identificados por su nombre y el de la placa de extensión de 40 pines que viene con el kit de iniciación también, deberemos identificar estos pines y realizar las conexiones adecuadamente.

Cableado en la breadboard

Hay que emplear varios cables macho-macho y hembra-hembra para conectar a los pines del adaptador I2C del display a los pines del voltaje de 5V, tierra, SDA y SDL de la placa de pruebas sin soldadura.

Unión cables macho-hembra

El siguiente paso será activar el bus I2C en la Raspberry Pi que por defecto está desactivado. Esto requiere añadir unos parámetros en la configuración de arranque y cargar unos módulos del kernel que finalmente crearán un dispositivo tal que en /dev/i2c-0 o /dev/i2c-0. Si instalamos el paquete i2c-tools podremos detectar el display en el bus I2C, en la captura de pantalla en la dirección 27 que hay que usar al construir la instancia del controlador del display. Estos cambios en la configuración de inicio requieren reiniciar la Raspberry Pi. En un sistema con la distribución Arch Linux ARM los cambios son los siguientes.

Detectción del display 1602 en el bus I2C

Según la especificación del display 1602 este componente soporta varios comandos para controlarlo, algunos son para limpiar el texto, cambiar la dirección de escritura, añadir caracteres personalizados y emitir texto en la línea o posición del display que queramos. No es simple el controlar el display a bajo nivel ya que hay que trabajar en momentos con binario y usar bytes, por ello para el ejemplo usaré la librería diozero que ya trae una implementación de controlador con funciones de alto nivel I2CLcd que en versiones más recientes de la librería ha sido renombrada a HD44780Lcd mucho más cómoda que enviar bytes a bajo nivel al bus I2C, el código fuente de la clase HD44780Lcd está disponible y podemos verlo si hay curiosidad.

En mi caso con la Raspberry Pi 1 he tenido que utilizar la versión 0.9 de la librería diozero porque la 0.8 me generaba un stacktrace de una excepción java.lang.UnsupportedOperationException. Obtener esta versión de la librería como aún era de desarrollo y no estaba publicada en Maven Central la he descargado de un google drive que ha creado el autor y usado en Gradle como una dependencia del sistema de ficheros. Como librería subyacente de diozero para controlar los pines GPIO he usado pigpio.

En el ejemplo mostraré un texto en cada una de las lineas del display y usaré una de las funciones del para mostrar caracteres personalizados con los que es posible crear emojis o caracteres nuevos. El controlador de diozero ya contiene una buena colección de caracteres personalizados que definen el patrón de 5x8 puntos que siguen, los nombres de estos caracteres personalizados están en la clase interna Characters de HD44780Lcd aunque también podemos definir nuevos. El ejemplo es el siguiente donde se muestra el uso de los métodos setText y setCharacter, también el constructor donde hay que indicar la dirección asignada al dispositivo en el bus I2C que siendo la 27 corresponde con el valor definido en una constante. Pero también hay otros métodos como clear, cursorOff y cursorOn para apagar y encender el cursor, displayOff displayOn para apgar y encender el display y createChar para crear nuevos caracteres definidos como una array de 8 posiciones donde cada byte indica los pixeles encendidos de cada fila del caracter de 5x8 y con setCharacter para emitir uno de los 8 posibles que se pueden usar al mismo tiempo. Además de estos también hay otros pocos métodos más relacionados con el cursor.

Mensaje en LCD 1602

Pudiendo mostrar mensajes en display es posible mostrar cualquier información que un programa sea capaz de capturar como temperatura y humedad del correspondiente sensor en el mismo kit, estado de un pulsador, espacio disponible en el disco del sistema, y memoria libre, uptime del sistema, fecha y hora, … cualquier cosa que se nos ocurra.

El ejemplo parece simple, y el programa Java lo es, pero requiere conocer varias cosas que en internet está dispersas como activar el bus I2C o conocer la librería diozero para controlar el display que simplifica enormemente el código y nos evita comunicarnos a más bajo nivel con el display, realizar las conexiones eléctricas también requiere algo de conocimiento. Averiguar todo esto me costó una buena cantidad de tiempo.

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

Jueves 16 de marzo de 2017

Gaspar Fernández

Gaspar Fernández
Poesía Binaria

Cómo recuperar pestañas perdidas en Google Chrome

En Internet hay dos tipos de personas: esos que como mucho tienen tres pestañas abiertas a la vez, y parece que les cuesta dinero tener pestañas abiertas. Y los que, como yo, abrimos una pestaña, la dejamos pa’ luego, descubrimos algo interesante y lo abrimos, o incluso mientras buscamos información abrimos todas las entradas del buscador en pestañas para ir mirándolas poco a poco. Total, al final te juntas (sin exagerar) con unas 500 pestañas. Afortunadamente, los navegadores modernos gestionan esto de forma más o menos eficiente.

Acumulando pestañas

Por si las moscas, ya que Chrome/Chromium tiene todo abierto a la vez y muchas veces el sistema no se suspende automáticamente porque alguna página lo prohíbe, yo utilizo la extensión The Great Suspender que se encarga de suspender pestañas que no uso tras un tiempo sin hacerles caso. Esto es sólo para liberar memoria y recursos del ordenador.

Reabriendo pestañas

De la misma manera que se puede abrir una pestaña cerrada recientemente haciendo click con el botón derecho en la pestaña y luego “Volver a abrir pestaña cerrada” o pulsando Control + Mayúscula + T podemos abrir todas las pestañas que teníamos en la ventana cuando la cerramos. Por lo que si hemos cerrado accidentalmente el navegador podemos volver a tener todo abierto con esta combinación de teclas.

Chrome también nos permite guardar en marcadores todas las pestañas que tenemos abiertas con (Control + Mayúscula + D), que nos puede venir muy bien.

Que automáticamente restaure las pestañas

Si entramos en la configuración de Chrome, veremos en las primeras opciones cómo queremos que el navegador se presente ante nosotros, en Iniciar Sesión / Al abrir el navegador… podemos marcar “Abrir todo como estaba antes de cerrar”, tal y como aparece en la foto. Esto puede variar ligeramente con la versión.

Pero a veces hay problemas…

Pero a veces podemos tener serios problemas cuando tienes muchas pestañas abiertas, se cierra la ventana por algún problema (o porque tuviste un accidente, que un error humano no lo podemos descartar) y cuando arrancamos de nuevo el navegador no se restauran las pestañas. Cuando ya no sabes ni qué tenías abierto pero que seguro que era interesante y tarde o temprano echarías en falta (y que no la encuentras en el historial porque tienes demasiadas cosas). Aquella pestaña que abriste hace meses y no le has hecho ni caso pero ahora se vuelve una gran pérdida en tu corazón.

Todavía no está todo perdido. ¡No hagas nada! ¡No toques nada!. Este navegador guarda una copia de la sesión anterior en los archivos de usuario. Para ello, dependiendo de tu sistema operativo encontrarás los archivos en un sitio u otro. Más o menos:

  • GNU/Linux: /home/usuario/.config/{chrome}/Default ({chrome} lo pongo entre llaves porque puede ser “chrome” / “chromium” o “google chrome”
  • Mac OS X: Users/usuario/Library/Application Support/Google/Chrome/Default
  • Windows 7, 8.1 y 10: C:\Users\\AppData\Local\Google\Chrome\User Data\Default

Allí encontramos algunos archivos:

  • Current Session
  • Current Tabs
  • Last Session
  • Last Tabs

Estos archivos están en formato binario, aunque las direcciones de las pestañas abiertas se pueden leer perfectamente, si tienes GNU/Linux o cualquier Unix, puedes utilizar strings para ver su contenido (seguro que para Windows encontramos también alguna herramienta):

strings Current\ Session
http://www.bodurov.com/JsonFormatter/
https://colorlib.com/polygon/metis/

Pero estos ficheros también podemos copiarlos fuera (por seguridad, ya lo veremos), o machacar Current Session con Last Session y Current Tabs con Last Tabs. Para asegurarnos de que todo va bien, es recomendable, antes de cerrar el navegador hacer una copia de seguridad de todos:

cp Current\ Session{,.backup}
cp Current\ Tabs{,.backup}
cp Last\ Session{,.backup}
cp Last\ Tabs{,.backup}

Ahora tendremos Current Session y Current Session.backup , Current Tabs y Current Tabs.backup y así con los demás. Ahora, cerramos el navegador, que seguramente reescriba los archivos (pero no las copias de seguridad que hemos hecho).
Ahora copiamos Last Session.backup en Last Session (y en Current Session también si queremos) y hacemos lo mismo con Last Tabs.backup:

cp Last\ Session.backup Current\ Session
cp Last\ Session.backup Last\ Session
cp Last\ Tabs.backup Current\ Tabs
cp Last\ Tabs.backup Last\ Tabs

Ahora podemos volver a abrir el navegador normalmente y si es necesario restaurar las pestañas. ¡Espero que las hayas podido recuperar!

Copias de seguridad periódicas de las pestañas

Si dejas abierto mucho tiempo el navegador y tienes largas sesiones de navegación que pueden durar incluso días. No estaría mal tener una copia de seguridad periódica de estas pestañas. Que se realice automáticamente cada cierto tiempo, para ello puedes hacer un cron con este script:

1
2
3
4
5
#!/bin/bash

cd /home/usuario/.config/chromium/Default/
tar cvjpf /home/usuario/Chromebackups/chrometabs_20170302_22_32_52.tar.bz2 "Current Session" "Current Tabs" "Last Session" "Last Tabs"
find -mtime +30 -exec rm {} +

Cambiando los directorios de usuario y de chrome y ejecutándolo un par de veces al día podemos tener por seguro que no perderemos muchas pestañas. Con el script anterior estaremos guardando un mes de pestañas en el tiempo (la última línea de find se encarga de borrar los que sean muy antiguos).

The post Cómo recuperar pestañas perdidas en Google Chrome appeared first on Poesía Binaria.

Las fuentes «STIX Two»

Este artículo es parte de la serie Recomendando fuentes tipográficas El proyecto STIX (Scientific and Technical Information eXchange) nació hace ya varios años como una colaboración entre American Mathematical Society (AMS), American Institute of Physics (AIP), American Physical Society (APS), American Chemical Society (ACS), Institute of Electrical and Electronic Engineers (IEEE) y Elsevier para satisfacer […]

Alpha Litebook tu portátil Linux como si estuvieras en Macbook

A día de hoy, todos sabemos ya que si Linux no está mucho más extendido es por la falta de integración de este sistema operativo en los ordenadores que nos venden en nuestro día a día. Normalmente si vamos a una tienda a comprar un ordenador de sobremesa o un portátil, no nos ofrecerán ninguno de los dos con Linux como sistema operativo integrado, a no ser que vayamos a una tienda

Lunes 13 de marzo de 2017

Gaspar Fernández

Gaspar Fernández
Poesía Binaria

Experimento: Creando un nuevo efecto de imagen para el secuenciador de vídeo de Blender (VSE) con código fuente


Lo que pongo aquí es solo un experimento. Como dije en mi anterior post, me encanta Blender para hacer montajes de vídeo y para mí, es el mejor editor de vídeo disponible para GNU/Linux. Aunque tiene un pequeño defecto, bueno, muy grande… apenas tiene efectos para los vídeos, por lo que si quieres algún efecto que no sea un crossfade, una corrección de color, o un blur, vas a tener que hacerlo de otra forma y eso implica exportar vídeo y luego importarlo cuando esté hecho. Con el gran inconveniente de que si el efecto no ha quedado exactamente como quieres, si de verdad te quedan ganas para modificarlo tienes que repetir el proceso.

Me gustan los efectos, y quiero hacer pruebas, porque no había mirado mucho el código fuente de Blender, me parece una bestia, tiene muchas cosas, y partes que se han quedado un poco viejas, como es el VSE (Video Sequence Editor), el módulo de Blender que más utilizo. Así que, ¿por qué no empezar a crear algunos efectos?

Construyendo Blender

Lo malo de todo esto, es que al contrario que con programas privativos, Blender no soporta plugins para efectos. Lo hizo en el pasado, pero por razones que no llego a comprender (supongo que relacionadas con el mantenimiento, con que nadie quiso hacerse cargo del módulo y con que tal vez les reportaban muchos fallos sobre efectos cuando el fallo no estaba en Blender, sino en el que realizaba el propio efecto). Lo malo, es que si queremos incluir un nuevo efecto en Blender, debemos recompilar nuestra versión de Blender. No tarda mucho, pero tiene algunas dependencias algo pesadas. Una vez que lo has hecho, las siguientes compilaciones no tardarán mucho, ya que sólo compila el código nuevo (lo que hacemos nosotros).

Bueno, he dicho que Blender no tiene API… ¡claro que tiene! Lo malo es que es una API en Python, y personalmente (que lo he probado), efectos que renderizan a 25fps hechos en C, van a 0.3fps hechos en Python. Es cierto que no he utilizado ninguna de las fantásticas bibliotecas de imagen digital disponibles para Python, pero de todas formas hay que hacer que el vídeo se exporte a Python, y sólo lo he conseguido hacer con alguna guarrada que me da vergüenza mencionar aquí…

Lo primero es decargarte el código fuente de la página principal o del git oficial de Blender (git://git.blender.org/blender.git). Si vas a compartir lo que haces con la comunidad, te recomiendo utilizar git para poder enviar parches y demás.

El caso es que si queremos compilar Blender, necesitamos un entorno de compilación GCC, y las siguientes bibliotecas con sus cabeceras para programación: python, numpy, libx11, libjpeg, libpng, boost, ffmpeg, libopencolorio, libilm, libopenexr y algunas más. Las encuentras todas en blender/build_files/build_environment/install_deps.sh

Antes de meterme con código

Si echas un vistazo por encima al código parece muchísimo, ¡ pero no es tanto ! Como es un programa tan grande, en muchos archivos, para que sepamos qué tenemos que tocar. Como no puedo decir la línea exacta ya que este programa se modifica a menudo he decidido poner unas cuantas líneas, o funciones completas a modo de referencia. Cuando lo que nos afecta es lo referente a CUSTOM_EFFECT.

¡Empezamos con la aventura!

Botón en la interfaz

Lo primero, es que desde la interfaz podamos añadir un nuevo efecto. Que cuando estemos en el secuenciador, pulsando Shift+A -> Effect aparezca nuestro efecto en el menú, para eso, tenemos que editar

Para eso, editamos el archivo source/blender/makesdna/DNA_sequence_types.h y añadimos una nueva constante con nuestro effecto. Mi efecto se llamará CUSTOMEFFECT, además, incrementamos SEQ_TYPE_MAX. En mi caso, la cosa queda más o menos así (cerca de la línea 500, en la versión 2.78c):

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
enum {
    SEQ_TYPE_IMAGE       = 0,
    SEQ_TYPE_META        = 1,
    SEQ_TYPE_SCENE       = 2,
    SEQ_TYPE_MOVIE       = 3,
    SEQ_TYPE_SOUND_RAM   = 4,
    SEQ_TYPE_SOUND_HD    = 5,
    SEQ_TYPE_MOVIECLIP   = 6,
    SEQ_TYPE_MASK        = 7,

    SEQ_TYPE_EFFECT      = 8,
    SEQ_TYPE_CROSS       = 8,
    SEQ_TYPE_ADD         = 9,
    SEQ_TYPE_SUB         = 10,
    SEQ_TYPE_ALPHAOVER   = 11,
    SEQ_TYPE_ALPHAUNDER  = 12,
    SEQ_TYPE_GAMCROSS    = 13,
    SEQ_TYPE_MUL         = 14,
    SEQ_TYPE_OVERDROP    = 15,
    /* SEQ_TYPE_PLUGIN      = 24, */ /* Deprecated */
    SEQ_TYPE_WIPE        = 25,
    SEQ_TYPE_GLOW        = 26,
    SEQ_TYPE_TRANSFORM   = 27,
    SEQ_TYPE_COLOR       = 28,
    SEQ_TYPE_SPEED       = 29,
    SEQ_TYPE_MULTICAM    = 30,
    SEQ_TYPE_ADJUSTMENT  = 31,
    SEQ_TYPE_GAUSSIAN_BLUR = 40,
    SEQ_TYPE_TEXT = 41,
    SEQ_TYPE_CUSTOMEFFECT = 42,

    SEQ_TYPE_MAX  = 42
};

Nuestro efecto, tendrá el índice 42, aunque no nos importa mucho la posición que ocupe. Ahora vamos al archivo source/blender/editors/space_sequencer/sequencer_edit.c, metemos el mismo efecto:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
EnumPropertyItem sequencer_prop_effect_types[] = {
    {SEQ_TYPE_CROSS, "CROSS", 0, "Crossfade", "Crossfade effect strip type"},
    {SEQ_TYPE_ADD, "ADD", 0, "Add", "Add effect strip type"},
    {SEQ_TYPE_SUB, "SUBTRACT", 0, "Subtract", "Subtract effect strip type"},
    {SEQ_TYPE_ALPHAOVER, "ALPHA_OVER", 0, "Alpha Over", "Alpha Over effect strip type"},
    {SEQ_TYPE_ALPHAUNDER, "ALPHA_UNDER", 0, "Alpha Under", "Alpha Under effect strip type"},
    {SEQ_TYPE_GAMCROSS, "GAMMA_CROSS", 0, "Gamma Cross", "Gamma Cross effect strip type"},
    {SEQ_TYPE_MUL, "MULTIPLY", 0, "Multiply", "Multiply effect strip type"},
    {SEQ_TYPE_OVERDROP, "OVER_DROP", 0, "Alpha Over Drop", "Alpha Over Drop effect strip type"},
    {SEQ_TYPE_WIPE, "WIPE", 0, "Wipe", "Wipe effect strip type"},
    {SEQ_TYPE_GLOW, "GLOW", 0, "Glow", "Glow effect strip type"},
    {SEQ_TYPE_TRANSFORM, "TRANSFORM", 0, "Transform", "Transform effect strip type"},
    {SEQ_TYPE_COLOR, "COLOR", 0, "Color", "Color effect strip type"},
    {SEQ_TYPE_SPEED, "SPEED", 0, "Speed", "Color effect strip type"},
    {SEQ_TYPE_MULTICAM, "MULTICAM", 0, "Multicam Selector", ""},
    {SEQ_TYPE_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", ""},
    {SEQ_TYPE_GAUSSIAN_BLUR, "GAUSSIAN_BLUR", 0, "Gaussian Blur", ""},
    {SEQ_TYPE_TEXT, "TEXT", 0, "Text", ""},
    {SEQ_TYPE_CUSTOMEFFECT, "CUSTOMEFFECT", 0, "Custom Effect", "Create a strip with customized effect" },
    {0, NULL, 0, NULL, NULL}
};

Dentro de cada elemento del array tendremos:

  • Índice, para lo que cogemos un valor de nuestro enum de antes. Será de uso interno,
  • String clave, será una cadena en clave, que manejaremos desde Python para referirnos al efecto.
  • El 0 siguiente indica que no hay icono asociado, por ahora no tenemos iconos
  • Luego el nombre del efecto, para mostrarlo
  • Por último, la descripción del efecto

Ahora en el archivo source/blender/makesrna/intern/rna_sequencer_api.c:

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
void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop)
{
    StructRNA *srna;
    PropertyRNA *parm;
    FunctionRNA *func;

    static EnumPropertyItem seq_effect_items[] = {
        {SEQ_TYPE_CROSS, "CROSS", 0, "Cross", ""},
        {SEQ_TYPE_ADD, "ADD", 0, "Add", ""},
        {SEQ_TYPE_SUB, "SUBTRACT", 0, "Subtract", ""},
        {SEQ_TYPE_ALPHAOVER, "ALPHA_OVER", 0, "Alpha Over", ""},
        {SEQ_TYPE_ALPHAUNDER, "ALPHA_UNDER", 0, "Alpha Under", ""},
        {SEQ_TYPE_GAMCROSS, "GAMMA_CROSS", 0, "Gamma Cross", ""},
        {SEQ_TYPE_MUL, "MULTIPLY", 0, "Multiply", ""},
        {SEQ_TYPE_OVERDROP, "OVER_DROP", 0, "Over Drop", ""},
        {SEQ_TYPE_WIPE, "WIPE", 0, "Wipe", ""},
        {SEQ_TYPE_GLOW, "GLOW", 0, "Glow", ""},
        {SEQ_TYPE_TRANSFORM, "TRANSFORM", 0, "Transform", ""},
        {SEQ_TYPE_COLOR, "COLOR", 0, "Color", ""},
        {SEQ_TYPE_SPEED, "SPEED", 0, "Speed", ""},
        {SEQ_TYPE_MULTICAM, "MULTICAM", 0, "Multicam Selector", ""},
        {SEQ_TYPE_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", ""},
        {SEQ_TYPE_GAUSSIAN_BLUR, "GAUSSIAN_BLUR", 0, "Gaussian Blur", ""},
        {SEQ_TYPE_TEXT, "TEXT", 0, "Text", ""},
        {SEQ_TYPE_CUSTOMEFFECT, "CUSTOM_EFFECT", 0, "Custom Effect", "" },
        {0, NULL, 0, NULL, NULL}
    };

Seguimos con la interfaz de Python. Para que el elemento aparezca en el menú debemos incluir lo siguiente en el archivo release/scripts/startup/bl_ui/space_sequencer.py (añadir la última línea, más o menos alrededor de la línea 380, blender 2.78c):

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
class SEQUENCER_MT_add_effect(Menu):
    bl_label = "Effect Strip..."

    def draw(self, context):
        layout = self.layout

        layout.operator_context = 'INVOKE_REGION_WIN'

        layout.operator("sequencer.effect_strip_add", text="Add").type = 'ADD'
        layout.operator("sequencer.effect_strip_add", text="Subtract").type = 'SUBTRACT'
        layout.operator("sequencer.effect_strip_add", text="Alpha Over").type = 'ALPHA_OVER'
        layout.operator("sequencer.effect_strip_add", text="Alpha Under").type = 'ALPHA_UNDER'
        layout.operator("sequencer.effect_strip_add", text="Cross").type = 'CROSS'
        layout.operator("sequencer.effect_strip_add", text="Gamma Cross").type = 'GAMMA_CROSS'
        layout.operator("sequencer.effect_strip_add", text="Gaussian Blur").type = 'GAUSSIAN_BLUR'
        layout.operator("sequencer.effect_strip_add", text="Multiply").type = 'MULTIPLY'
        layout.operator("sequencer.effect_strip_add", text="Over Drop").type = 'OVER_DROP'
        layout.operator("sequencer.effect_strip_add", text="Wipe").type = 'WIPE'
        layout.operator("sequencer.effect_strip_add", text="Glow").type = 'GLOW'
        layout.operator("sequencer.effect_strip_add", text="Text").type = 'TEXT'
        layout.operator("sequencer.effect_strip_add", text="Transform").type = 'TRANSFORM'
        layout.operator("sequencer.effect_strip_add", text="Color").type = 'COLOR'
        layout.operator("sequencer.effect_strip_add", text="Speed Control").type = 'SPEED'
        layout.operator("sequencer.effect_strip_add", text="Multicam Selector").type = 'MULTICAM'
        layout.operator("sequencer.effect_strip_add", text="Adjustment Layer").type = 'ADJUSTMENT'
        layout.operator("sequencer.effect_strip_add", text="Custom Effect").type = 'CUSTOM_EFFECT'

Ahora definimos el color del elemento una vez lo pongamos en la línea de tiempo. Para ello en source/blender/editors/space_sequencer/sequencer_draw.c vamos a la función color3ubv_from_seq() donde, dentro del case, dejamos algo como esto (es aproximado, podemos definirle el color si queremos, pero yo me he basado en el color de otros elementos parecidos):

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
        /* effects */
        case SEQ_TYPE_TRANSFORM:
        case SEQ_TYPE_SPEED:
        case SEQ_TYPE_ADD:
        case SEQ_TYPE_SUB:
        case SEQ_TYPE_MUL:
        case SEQ_TYPE_ALPHAOVER:
        case SEQ_TYPE_ALPHAUNDER:
        case SEQ_TYPE_OVERDROP:
        case SEQ_TYPE_GLOW:
        case SEQ_TYPE_MULTICAM:
        case SEQ_TYPE_ADJUSTMENT:
        case SEQ_TYPE_GAUSSIAN_BLUR:
        case SEQ_TYPE_CUSTOMEFFECT:
            UI_GetThemeColor3ubv(TH_SEQ_EFFECT, col);

            /* slightly offset hue to distinguish different effects */
            if      (seq->type == SEQ_TYPE_ADD)           rgb_byte_set_hue_float_offset(col, 0.04);
            else if (seq->type == SEQ_TYPE_SUB)           rgb_byte_set_hue_float_offset(col, 0.08);
            else if (seq->type == SEQ_TYPE_MUL)           rgb_byte_set_hue_float_offset(col, 0.12);
            else if (seq->type == SEQ_TYPE_ALPHAOVER)     rgb_byte_set_hue_float_offset(col, 0.16);
            else if (seq->type == SEQ_TYPE_ALPHAUNDER)    rgb_byte_set_hue_float_offset(col, 0.20);
            else if (seq->type == SEQ_TYPE_OVERDROP)      rgb_byte_set_hue_float_offset(col, 0.24);
            else if (seq->type == SEQ_TYPE_GLOW)          rgb_byte_set_hue_float_offset(col, 0.28);
            else if (seq->type == SEQ_TYPE_TRANSFORM)     rgb_byte_set_hue_float_offset(col, 0.36);
            else if (seq->type == SEQ_TYPE_MULTICAM)      rgb_byte_set_hue_float_offset(col, 0.32);
            else if (seq->type == SEQ_TYPE_ADJUSTMENT)    rgb_byte_set_hue_float_offset(col, 0.40);
            else if (seq->type == SEQ_TYPE_GAUSSIAN_BLUR) rgb_byte_set_hue_float_offset(col, 0.42);
            else if (seq->type == SEQ_TYPE_CUSTOMEFFECT)  rgb_byte_set_hue_float_offset(col, 0.52);
            break;

Si compilamos y ejecutamos Blender, seguramente nuestro efecto aparezca y lo podremos añadir, pero no hará nada, sólo soltar errores por la consola.

Definiendo algunas propiedades

Debemos definir antes de continuar algunas propiedades básicas del strip. En source/blender/makesrna/intern/rna_sequencer.c haremos varias modificaciones. Primero, en la función rna_def_sequence() (alrededor de la línea 1380), volvemos a meter nuestro efecto:

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
static void rna_def_sequence(BlenderRNA *brna)
{
    StructRNA *srna;
    PropertyRNA *prop;

    static const EnumPropertyItem seq_type_items[] = {
        {SEQ_TYPE_IMAGE, "IMAGE", 0, "Image", ""},
        {SEQ_TYPE_META, "META", 0, "Meta", ""},
        {SEQ_TYPE_SCENE, "SCENE", 0, "Scene", ""},
        {SEQ_TYPE_MOVIE, "MOVIE", 0, "Movie", ""},
        {SEQ_TYPE_MOVIECLIP, "MOVIECLIP", 0, "Clip", ""},
        {SEQ_TYPE_MASK, "MASK", 0, "Mask", ""},
        {SEQ_TYPE_SOUND_RAM, "SOUND", 0, "Sound", ""},
        {SEQ_TYPE_CROSS, "CROSS", 0, "Cross", ""},
        {SEQ_TYPE_ADD, "ADD", 0, "Add", ""},
        {SEQ_TYPE_SUB, "SUBTRACT", 0, "Subtract", ""},
        {SEQ_TYPE_ALPHAOVER, "ALPHA_OVER", 0, "Alpha Over", ""},
        {SEQ_TYPE_ALPHAUNDER, "ALPHA_UNDER", 0, "Alpha Under", ""},
        {SEQ_TYPE_GAMCROSS, "GAMMA_CROSS", 0, "Gamma Cross", ""},
        {SEQ_TYPE_MUL, "MULTIPLY", 0, "Multiply", ""},
        {SEQ_TYPE_OVERDROP, "OVER_DROP", 0, "Over Drop", ""},
        {SEQ_TYPE_WIPE, "WIPE", 0, "Wipe", ""},
        {SEQ_TYPE_GLOW, "GLOW", 0, "Glow", ""},
        {SEQ_TYPE_TRANSFORM, "TRANSFORM", 0, "Transform", ""},
        {SEQ_TYPE_COLOR, "COLOR", 0, "Color", ""},
        {SEQ_TYPE_SPEED, "SPEED", 0, "Speed", ""},
        {SEQ_TYPE_MULTICAM, "MULTICAM", 0, "Multicam Selector", ""},
        {SEQ_TYPE_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", ""},
        {SEQ_TYPE_GAUSSIAN_BLUR, "GAUSSIAN_BLUR", 0, "Gaussian Blur", ""},
        {SEQ_TYPE_TEXT, "TEXT", 0, "Text", ""},
        {SEQ_TYPE_CUSTOMEFFECT, "CUSTOM_EFFECT", 0, "Custom Effect", "" },             
        {0, NULL, 0, NULL, NULL}
    };

Luego en la línea 2390 más o menos modificamos la estructura def_effects añadiendo la definición de nuestro nuevo efecto:

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
static EffectInfo def_effects[] = {
    {"AddSequence", "Add Sequence", "Add Sequence", NULL, 2},
    {"AdjustmentSequence", "Adjustment Layer Sequence",
     "Sequence strip to perform filter adjustments to layers below", rna_def_input, 0},
    {"AlphaOverSequence", "Alpha Over Sequence", "Alpha Over Sequence", NULL, 2},
    {"AlphaUnderSequence", "Alpha Under Sequence", "Alpha Under Sequence", NULL, 2},
    {"ColorSequence", "Color Sequence",
     "Sequence strip creating an image filled with a single color", rna_def_solid_color, 0},
    {"CrossSequence", "Cross Sequence", "Cross Sequence", NULL, 2},
    {"GammaCrossSequence", "Gamma Cross Sequence", "Gamma Cross Sequence", NULL, 2},
    {"GlowSequence", "Glow Sequence", "Sequence strip creating a glow effect", rna_def_glow, 1},
    {"MulticamSequence", "Multicam Select Sequence", "Sequence strip to perform multicam editing",
     rna_def_multicam, 0},
    {"MultiplySequence", "Multiply Sequence", "Multiply Sequence", NULL, 2},
    {"OverDropSequence", "Over Drop Sequence", "Over Drop Sequence", NULL, 2},
    {"SpeedControlSequence", "SpeedControl Sequence",
     "Sequence strip to control the speed of other strips", rna_def_speed_control, 1},
    {"SubtractSequence", "Subtract Sequence", "Subtract Sequence", NULL, 2},
    {"TransformSequence", "Transform Sequence",
     "Sequence strip applying affine transformations to other strips", rna_def_transform, 1},
    {"WipeSequence", "Wipe Sequence", "Sequence strip creating a wipe transition",
     rna_def_wipe, 2},
    {"GaussianBlurSequence", "Gaussian Blur Sequence", "Sequence strip creating a gaussian blur",
     rna_def_gaussian_blur, 1},
    {"TextSequence", "Text Sequence", "Sequence strip creating text",
     rna_def_text, 0},
    {"CustomEffectSequence", "Custom Effect Sequence", "Sequence strip creating custom effects",
     rna_def_custom_effect, 1},
    {"", "", "", NULL, 0}
};

Donde, el 1 que acompaña la declaración del efecto es el número de entradas que necesitamos. Al aplicarse sobre otro strip, necesitamos un 1 aquí. Si fuera un generador, sería 0 y una transición tendría 2.

Ahora, junto con los demás efectos (línea 2100 más o menos), creamos la función rna_def_customeffect donde definiremos los parámetros que se podrán tocar de nuestro efecto, que luego tendremos que vincular con Python, que no se nos olvide:

1
2
3
4
5
6
7
8
9
10
static void rna_def_custom_effect(StructRNA *srna)
{
    PropertyRNA *prop;

    RNA_def_struct_sdna_from(srna, "CustomEffectVars", "effectdata");
    prop = RNA_def_property(srna, "property", PROP_FLOAT, PROP_UNSIGNED);
    RNA_def_property_ui_text(prop, "One property", "One float prop for practising");
    RNA_def_property_ui_range(prop, 0.0f, FLT_MAX, 1, -1);
    RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
}

Y añadimos nuestro efecto a la función rna_sequence_refine():

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
static StructRNA *rna_Sequence_refine(struct PointerRNA *ptr)
{
    Sequence *seq = (Sequence *)ptr->data;

    switch (seq->type) {
        case SEQ_TYPE_IMAGE:
            return &RNA_ImageSequence;
        case SEQ_TYPE_META:
            return &RNA_MetaSequence;
        case SEQ_TYPE_SCENE:
            return &RNA_SceneSequence;
        case SEQ_TYPE_MOVIE:
            return &RNA_MovieSequence;
        case SEQ_TYPE_MOVIECLIP:
            return &RNA_MovieClipSequence;
        case SEQ_TYPE_MASK:
            return &RNA_MaskSequence;
        case SEQ_TYPE_SOUND_RAM:
            return &RNA_SoundSequence;
        case SEQ_TYPE_CROSS:
            return &RNA_CrossSequence;
        case SEQ_TYPE_ADD:
            return &RNA_AddSequence;
        case SEQ_TYPE_SUB:
            return &RNA_SubtractSequence;
        case SEQ_TYPE_ALPHAOVER:
            return &RNA_AlphaOverSequence;
        case SEQ_TYPE_ALPHAUNDER:
            return &RNA_AlphaUnderSequence;
        case SEQ_TYPE_GAMCROSS:
            return &RNA_GammaCrossSequence;
        case SEQ_TYPE_MUL:
            return &RNA_MultiplySequence;
        case SEQ_TYPE_OVERDROP:
            return &RNA_OverDropSequence;
        case SEQ_TYPE_MULTICAM:
            return &RNA_MulticamSequence;
        case SEQ_TYPE_ADJUSTMENT:
            return &RNA_AdjustmentSequence;
        case SEQ_TYPE_WIPE:
            return &RNA_WipeSequence;
        case SEQ_TYPE_GLOW:
            return &RNA_GlowSequence;
        case SEQ_TYPE_TRANSFORM:
            return &RNA_TransformSequence;
        case SEQ_TYPE_COLOR:
            return &RNA_ColorSequence;
        case SEQ_TYPE_SPEED:
            return &RNA_SpeedControlSequence;
        case SEQ_TYPE_GAUSSIAN_BLUR:
            return &RNA_GaussianBlurSequence;
        case SEQ_TYPE_TEXT:
            return &RNA_TextSequence;
        case SEQ_TYPE_CUSTOM_EFFECT:
            return &RNA_CustomEffectSequence;
        default:
            return &RNA_Sequence;
    }
}

Por último en source/blender/makesrna/RNA_access.h metemos esta línea, más o menos en la 280:

1
extern StructRNA RNA_CustomEffectSequence;

Insertamos las propiedades de nuestro efecto

Por ahora sólo estoy metiendo una, y no hace nada, sólo estar ahí, pero me sirve como plantilla para futuros efectos. Antes de que se nos olvide, vamos a añadirla desde la interfaz de Python. En el archivo en el archivo release/scripts/startup/bl_ui/space_sequencer.py en la clase CLASS_PT_EFFECT(), al final del todo añadimos nuestro efecto:

1
2
3
4
5
6
7
8
9
10
11
12
         col = layout.column(align=True)
        if strip.type == 'SPEED':
            col.prop(strip, "multiply_speed")
        elif strip.type in {'CROSS', 'GAMMA_CROSS', 'WIPE', 'ALPHA_OVER', 'ALPHA_UNDER', 'OVER_DROP'}:
            col.prop(strip, "use_default_fade", "Default fade")
            if not strip.use_default_fade:
                col.prop(strip, "effect_fader", text="Effect fader")
        elif strip.type == 'GAUSSIAN_BLUR':
            col.prop(strip, "size_x")
            col.prop(strip, "size_y")
        elif strip.type == 'CUSTOM_EFFECT':
            col.prop(strip, 'property')

Ahora declaramos las propiedades de nuestro efecto. Para ello en el archivo source/blender/makesdna/DNA_sequence_types.h insertamos lo sigueinte (cerca de la 290, junto con los demás efectos, ya los veréis):

1
2
3
typedef struct CustomEffectVars {
    float property;
} CustomEffectVars;

Mi propiedad se llamaba property, porque soy muy original, pero aquí pondremos las que necesitemos. Podremos poner arrays de char para cadenas de caracteres, char, short para flags, enteros y float, por ejemplo, los colores van en float. Podríamos poner otros tipos de variable, pero no he probado… no soy tan valiente.

Para que las propiedades de nuestro efecto se guarden cuando salvamos el archivo .blend hacemos, editamos source/blender/blenloader/intern/writefile.c añadiendo la estructura de nuestro efecto, alrededor de la límea 2660:

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
            SEQ_BEGIN(ed, seq)
            {
                if (seq->strip && seq->strip->done == 0) {
                    /* write strip with 'done' at 0 because readfile */

                    if (seq->effectdata) {
                        switch (seq->type) {
                            case SEQ_TYPE_COLOR:
                                writestruct(wd, DATA, SolidColorVars, 1, seq->effectdata);
                                break;
                            case SEQ_TYPE_SPEED:
                                writestruct(wd, DATA, SpeedControlVars, 1, seq->effectdata);
                                break;
                            case SEQ_TYPE_WIPE:
                                writestruct(wd, DATA, WipeVars, 1, seq->effectdata);
                                break;
                            case SEQ_TYPE_GLOW:
                                writestruct(wd, DATA, GlowVars, 1, seq->effectdata);
                                break;
                            case SEQ_TYPE_TRANSFORM:
                                writestruct(wd, DATA, TransformVars, 1, seq->effectdata);
                                break;
                            case SEQ_TYPE_GAUSSIAN_BLUR:
                                writestruct(wd, DATA, GaussianBlurVars, 1, seq->effectdata);
                                break;
                            case SEQ_TYPE_CUSTOMEFFECT:
                                writestruct(wd, DATA, CustomEffectVars, 1, seq->effectdata);
                                break;
                            case SEQ_TYPE_TEXT:
                                writestruct(wd, DATA, TextVars, 1, seq->effectdata);
                                break;
                        }
                    }

                    writestruct(wd, DATA, Stereo3dFormat, 1, seq->stereo3d_format);

Definiciones de nuestro efecto

Ya va quedando menos, tenemos esto casi configurado, sólo quedan algunos callbacks con las llamadas que hacen los propios filtros, vamos, ahora es cuando nuestro filtro hace algo, aunque es necesario definirlo para que el programa no explote:

En el archivo source/blender/blenkernel/intern/seqeffects.c encontramos el código de estos efectos. Lo primero será introducir las definiciones de nuestro efecto en la función get_sequence_effect_impl() en la línea 3315 o así, buscamos los efectos del switch y ponemos el nuestro al final:

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
        case SEQ_TYPE_ADJUSTMENT:
            rval.supports_mask = true;
            rval.num_inputs = num_inputs_adjustment;
            rval.early_out = early_out_adjustment;
            rval.execute = do_adjustment;
            break;
        case SEQ_TYPE_GAUSSIAN_BLUR:
            rval.init = init_gaussian_blur_effect;
            rval.num_inputs = num_inputs_gaussian_blur;
            rval.free = free_gaussian_blur_effect;
            rval.copy = copy_gaussian_blur_effect;
            rval.early_out = early_out_gaussian_blur;
            rval.execute = do_gaussian_blur_effect;
            break;
        case SEQ_TYPE_TEXT:
            rval.num_inputs = num_inputs_text;
            rval.init = init_text_effect;
            rval.free = free_effect_default;
            rval.copy = copy_effect_default;
            rval.early_out = early_out_text;
            rval.execute = do_text_effect;
            break;
        case SEQ_TYPE_CUSTOMEFFECT:
            rval.init = init_custom_effect_effect;
            rval.num_inputs = num_inputs_custom_effect;
            rval.free = free_custom_effect_effect;
            rval.copy = copy_custom_effect_effect;
            rval.early_out = early_out_custom_effect;
            rval.execute = do_custom_effect_effect;
            break;

Aquí definiremos:

  • rval.init : función que inicializa nuestro efecto
  • rval.num_inputs : número de strips de entrada que necesita nuestro strip. Los efectos necesitan estas sobre un strip, las transiciones sobre dos, los generadores no necesitan strips.
  • rval.free : Qué hacemos cuando se quita nuestro efecto (para liberar memoria)
  • rval.copy : Qué hacer cuando copian nuestro efecto.
  • rval.early_out : A veces, podemos saber si es necesario o no aplicar el efecto antes de ponernos a procesar. Aquí veremos si procesamos, si devolvemos el valor de la entrada, o no devolvemos nada
  • rval.execute : NUESTRO EFECTO !!!
  • rval.supports_mask : ¿Soporta máscaras? (es un booleano, no un callback
  • rval.load : Qué hacer cuando se acaba de cargar el efecto?
  • rval.init_execution : Este callback se ejecutará antes de hacer el render de nuestro efecto.
  • rva.multithreaded : El efecto soporta threads. Y en lugar de llamar a rval.execute se llamará a rval.execute_slice, por lo que si hacemos nuestro efecto multihilo tendremos que hacerlo independiente de las líneas de origen y fin que nos pasen (Blender ya se encarga de crear hilos y de todo lo demás, nosotros sólo tenemos que definir lo que hace cada uno).

Encontraremos toda la información en source/blender/blenkernel/BKE_sequencer.h

Como todo lo que hemos puesto son callbacks, tendremos que definirlos, voy a poner todo el código seguido, pero si queréis tenerlo ordenado buscad funciones parecidas de otros efectos y poned el vuestro por 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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/*********************** Custom Effect *************************/
static void init_custom_effect_effect(Sequence *seq)
{
    if (seq->effectdata)
        MEM_freeN(seq->effectdata);

    seq->effectdata = MEM_callocN(sizeof(CustomEffectVars), "customeffectvars");
}

static int num_inputs_custom_effect(void)
{
    return 1;
}

static void free_custom_effect_effect(Sequence *seq)
{
    if (seq->effectdata)
        MEM_freeN(seq->effectdata);

    seq->effectdata = NULL;
}

static void copy_custom_effect_effect(Sequence *dst, Sequence *src)
{
    dst->effectdata = MEM_dupallocN(src->effectdata);
}

static int early_out_custom_effect(Sequence *seq, float UNUSED(facf0), float UNUSED(facf1))
{

    /* source/blender/blenkernel/BKE_sequencer.h */
    /* #define EARLY_NO_INPUT      -1 */
    /* #define EARLY_DO_EFFECT     0 */
    /* #define EARLY_USE_INPUT_1   1 */
    /* #define EARLY_USE_INPUT_2   2 */
   
    CustomEffectVars *UNUSED(data) = seq->effectdata;
    /* I will always do my effect */
    /* if (data->property == 0) { */
    /*  return EARLY_USE_INPUT_1; */
    /* } */
    return EARLY_DO_EFFECT;
}

// NUESTRO EFECTO !!!!!!!!!!!!!
static ImBuf *do_custom_effect_effect(const SeqRenderData *context, Sequence *seq, float UNUSED(cfra), float UNUSED(facf0), float UNUSED(facf1),
                                     ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3)
{
    ImBuf *out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3);

    CustomEffectVars *cv = (CustomEffectVars *)seq->effectdata;

    unsigned char *rect, *orig;
    int x= context->rectx;
    int y= context->recty;
    float prop = cv->property;

    if (out->rect) {
        orig = (unsigned char *)ibuf1->rect;
        rect = (unsigned char *)out->rect;
        while (y--) {
            x = context->rectx;
            while (x--) {
                rect[0] = (orig[0]+ prop*orig[1])/(1+prop);
                rect[1] = (orig[1]+ prop*orig[2])/(1+prop);
                rect[2] = (orig[2]+ prop*orig[1])/(1+prop);
                rect[3] = 220;
                rect += 4;
                orig += 4;
            }
        }
    }
    else if (out->rect_float) {
        orig = (unsigned char *)ibuf1->rect_float;
        rect = (unsigned char *)out->rect_float;
        while (y--) {
            x = context->rectx;
            while (x--) {
                rect[0] = (orig[0]+ prop*orig[1])/(1+prop);
                rect[1] = (orig[1]+ prop*orig[2])/(1+prop);
                rect[2] = (orig[2]+ prop*orig[1])/(1+prop);
                rect[3] = 0.5;
                rect += 4;
                orig += 4;
               
            }
        }
    }
    return out;
}

¡Y listo! Si compilamos Blender ya tenemos nuestro efecto.

En la función do_custom_effect_effect(), tenemos los siguientes parámetros para la entrada:

  • const SeqRenderData *context : El contexto, aquí tenemos acceso a muchísimas cosas, demasiado para enumerarlo aquí, pero accedemos a la estructura Main que contiene casi todo, podemos acceder a la escena, elementos guardados y miles de cosas más.
  • Sequence *seq : Toda la información del strip actual
  • float cfra: Fotograma actual, puede tener un error de +-0.5 frames.
  • float facf0: Cuando estamos operando con contenido entrelazado y estamos animando un efecto, qué porcentaje de efecto recae sobre el campo 0?
  • float facf1: lo mismo pero para el campo 1.
  • ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3: Son las imágenes asociadas al efecto, dependiendo del efecto, habrá varias imágenes implicadas en él.

Y… como extra, si no estamos utilizando una variable, pero la queremos dejar ahí, para que el compilador no se queje podemos envolverla con la macro UNUSED()

La comunidad Blender

En https://developer.blender.org/ encontramos un sistema en el que se ponen en común bugs y pequeñas características (si quieres colaborar en algo grande, tienes que contactar con ellos). Y actualmente el secuenciador lo tienen un poco abandonado, de todas formas, hay una parte importante de la comunidad que sigue ahí, enviando parches y mejoras.

The post Experimento: Creando un nuevo efecto de imagen para el secuenciador de vídeo de Blender (VSE) con código fuente appeared first on Poesía Binaria.

Guillermo Garron

Guillermo Garron
GNU Linux

{{ post.title }}

{{ post.content | xml_escape }}
Juanje Ojeda

Juanje Ojeda
Nada de particular

Cambio de profesión

El 8 de noviembre del año pasado cumplí 38 años y me siento mejor de lo que me sentía con 20, así que estoy muy contento :-)

Además, celebré mi cumpleaños regalándome un cambio de profesión. He vuelto a una de mis 2 grandes pasiones, el cuerpo humano y la educación física.

Después de estar un tiempo reciclándome (hace 15 años que estudié Ciencias de la Actividad Física y del Deporte y han cambiado muchas cosas desde entonces...) y dedicándome a mejorar mi salud, me decidí a tirarme a la piscina y dejar los ordenadores para dedicarme a las personas.

Hacía mucho que no estaba tan motivado con algo :-)

Ya llevo casi un año metido en esa aventura y cada día más motivado. Aprendo mucho cada día e intento compartir ese conocimiento en mi nuevo blog profesional:
Juanje Ojeda

La mayoría de mis clientes son personas con mi antiguo perfil. Personas sedentarias que trabajan todo el día con ordenadores y que les cuesta encontrar tiempo y fuerza de voluntad para tomar las riendas de su salud.
Incluso he empezado a ayudar de forma remota a antiguos compañeros de trabajo y gente del gremio. Es lo bueno de Internet y las nuevas tecnologías :-P
Entrenamiento online

Espero seguir así de contento e ilusionado con esta nueva etapa durante mucho tiempo. Pero si no es así, al menos lo intenté y lo disfrutaré mientras dure :-)
Juanje Ojeda

Juanje Ojeda
Nada de particular

Nace ASOLIF. Una apuesta de futuro y colaboración

Copio el anuncio que hizo el amigo Agustín sobre el nacimiento de la asociación de empresas de software libre federadadas (ASOLIF) en la lista de socios de Hispalinux, que el lo explica mejor de lo que lo haría yo ;-)

Ayer precisamente vi a Gonzalo (Fotón), que venía de la firma de la misma y que venía muy animado y esperanzado con el proyecto. Más tarde se nos unió Victor Fernandez (gerente, socio y amigo de Emergya) y tuvimos una cena muy agradable con tapitas y cervezas en la que hablamos de ASOLIF, los diferentes modelos de negocio y enfoques de las empresas que producen y consumen software libre, y más temas relacionados y muy interesantes.
Fué un debate intenso, interesante y muy constructivo. Que es lo más importante. Exponer opiniones, argumentarlas y sacar lo mejor de cada una de ellas para mejorar y avanzar.

Bueno, no me enrollo más, les dejo el mensaje de Agustín, para que aquellos que no están en la lista, puedan enterarse de esta interesante y prometedora noticia.

-----Original Message-----
From: Agustín Benito Bethencourt

Date: Fri, 29 Feb 2008 16:25:46
To:socios EN hispalinux PUNTO es
Subject: [Socios-HispaLinux] nace asolif


Hola a todos,

me congratulo en comentar que hoy nace oficialmente ASOLIF, la asociación de
empresas de software libre federadas. Forman parte de ella inicialmente las
asociaciones regionales ESLIC (Canarias), ESLE (País Vasco) y CatPL
(Cataluña). La inauguración ha sido auspiciada por el CENATIC esta mañana.

Como miembro fundador (y de la actual Junta Directiva) de ESLIC, quiero
decirles que se trata de una iniciativa que ha costado un año llevar adelante
y que esperamos todos sea la chispa que nos permita a las empresas de
software libre disponer de un foro efectivo, donde poder conectarnos formando
una red de empresas que den soporte e impulsen el software libre a nivel
empresarial en nuestro pais. El software libre SI tiene quien lo soporte en
España.

Sé que hay muchos empresarios que pertenecen a Hispalinux y sé que la propia
asociación ha servidor muchas veces como vehículo de nuestras demandas e
inquietudes. Sólo espero que la colaboración entre Hispalinux y la nueva
Federación sea lo más fructífera posible. Nos necesitamos.

Si eres profesional o empresa, permíteme invitarte a moverte para formar una
asociación de empresas en tu Comunidad (hay algunas que lo están haciendo ya)
y pasar a formar parte de esta Federación. Debemos estar todos para que el
esfuerzo que hemos puesto en esto tenga sentido.

Saludos
--
Agustín Benito Bethencourt
Grupo CPD
abenito @ grupocpd.com
http://www.grupocpd.com
http://agustin.ejerciciosresueltos.com
http://www.toscalix.blogspot.com
_______________________________________________


IMPORTANTE: Los mensajes y opiniones que aparecen en esta lista son de la exclusiva responsabilidad de sus autores. No son atribuibles a Hispalinux ni a los gestores de la lista.
-----Original Message-----


A ver qué tal va este asunto. ¡Mucha suerte a todos! :-)



Juanje Ojeda

Juanje Ojeda
Nada de particular

Sobre la BlackBerry desde la BlackBerry (III)

Lo prometido es deuda, aquí tienen el listado de mis aplicaciones favoritas para la BlackBerry.

He buscado cosas libres, pero es complicado encontrarlas. En su defecto he encontrado aplicaciones gratuitas. No es lo mismo, pero siendo prácticos, me sirven.

Listaré las aplicaciones por funcionalidad:


Y algunas aplicaciones vía web o wap:

¿Qué es lo que más uso yo? Pues después de probar mucho y pasarseme algo de la novedad lo que realmente uso y me resulta bastante práctico es:
(ordenado por frecuencia de uso)


Por cierto, el Opera Mini está muy bien, pero tiene algunas cosas que no terminan de gustarme y no se integra bien con la Perla. El trackball no funciona como esperas y no te deja ir a un enlace directamente con él, tienes que dar dos pasos...
Menú -> Selecionar

Usabilidad: -10 :-(

Una pena porque en cuanto a rapidez de carga y formateo de páginas es genial.

Otro día una escribo una revisión a algunas de estás webs o aplicaciones que uso. Pero espero que esta pequeña relación de enlaces le resulte útil a más de uno. A mí tener algo así me hubiera ahorrado bastante tiempo...
Otra cosa de la que me gustaría hablar es sobre el PIN. Si alguien tiene información útil e interesante sobre el tema, que lo diga, así me documento mejor del tema ;-)


Sábado 11 de marzo de 2017

Pedro L. Lucas

Pedro L. Lucas
Cartas de Linux

La potencia de los recortes de código (snipples)

Un recorte de código es una pequeña plantilla que podemos reutilizar dentro de un editor de textos. Esta plantilla se pega, en el texto que se está editando, al escribir una palabra y pulsar el tabulador. En el siguiente ejemplo, al escribir html5 y pulsar tabulador, se pega la plantilla correspondiente:

Una vez pegada la plantilla se puede ver que al escribir en ciertas partes del texto, el texto se copia a otros lugares de forma automática. Pulsando tabulador, se van saltando a los diferentes campos de la plantilla.

Los recortes de código (snipples) están presentes en numerosos editores de texto como pueden ser Gedit, Vim, Sublime Text, Kate,…

Por ser Gedit un editor de textos muy extendido, en este artículo se va a mostrar cómo se activan y cómo se crean en él los recortes de código.

Activando los recortes en Gedit

Para activar los recortes de código se debe ir al menú “Editar/Preferencias” y en la pestaña “Complementos” activar “Recortes”:

También suele ser práctico activar el “Completado de palabras”.

Viendo los recortes disponibles

En el menú “Herramientas/Manage snipples” se pueden ver los recortes disponibles y la palabra que los dispara:

Como se puede ver en la imagen, para los archivos html se tienen numerosos recortes. En la parte izquierda de la ventana se pueden ver los recortes disponibles y en negrita la palabra que hay que escribir para activarlos. Por ejemplo, si se escribe html5 y se pulsa tabulador, se sustituirá por el texto, la plantilla, que aparece a la derecha. Más adelante nos meteremos en la forma de crear las plantillas.

Usando los recortes

Ya se han localizado los recortes disponibles. Sólo hay que escribir su disparador y pulsar tabulador, pero seguramente que si intentamos usarlos, no funcionen. Cada recorte sólo funciona para el tipo de archivo en el que se haya definido. Por ejemplo, los recortes de HTML sólo funcionarán si el archivo que se está editando se ha almacenado con la extensión html. Los recortes de C++ sólo funcionarán para los archivos con extensión “cpp”.

También podemos forzar el tipo de archivo seleccionándolo en la parte inferior del navegador:

Creando nuestras plantillas

Para crear una plantilla sólo hay que ir al menú “Herramientas/Manage snipples”, seleccionar en la parte izquierda el tipo de archivo para el que se desea crear el disparador y hacer clic sobre el símbolo “+” para añadirlo:

Le pondremos un nombre y en la parte inferior-derecha se escribe el disparador que deseamos que se ejecute. Ahora en la parte superior derecha escribimos el texto que se desea que se introduzca.

Por ejemplo, si se crea el disparador “hola” y en la parte superior derecha se escribe el texto “Hola mundo”, al escribir “hola” y pulsar el tabulador, se escribirá “Hola mundo”.

Pero lo interesante de las plantillas son los campos. Para definir los diferentes campos se usará $1, $2, $3,… una vez insertada la plantilla, al ir pulsando tabulador, el cursor irá saltando a las posiciones marcadas por $1, $2, $3,… Por ejemplo, se crea la plantilla:

Nombre: $1
Primer Apellido: $2
Segundo Apellido: $3
$0

Al insertarla el cursor aparecerá en la posición $1, allí escribimos el dato correspondiente. Si se vuelve a pulsar tabulador, saltará a la posición $2, rellenamos el primer apellido. Si se vuelve a pulsar tabulador, saltará a $3, rellenamos el segundo apellido. Si se pulsa tabulador una vez más, como ya no hay más posiciones a las que saltar, la plantilla se considerará finalizada y saltará a la posición indicada por $0.

Es llamativo que $0 sea la posición final.

Nos fijamos ahora en la siguiente plantilla:

Nombre: $1
Primer Apellido: $2
Segundo Apellido: $3
Nombre completo: $2 $3, $1
$0

Se puede ver que la posición $1 aparece repetida dos veces, eso significa que cuando se rellene el nombre, copiará dicho nombre en el segundo $1. De forma idéntica con $2 y $3:

A veces interesa que ciertos campos ya aparezcan rellenos con algún texto por defecto, para ello se usa la siguiente notación:

${número:Texto por defecto}

Por ejemplo:

${1:Ejemplo de texto}

En el ejemplo que se estaba desarrollando, se puede añadir un último campo, Teléfono, que por defecto muestre el texto “No disponible”:

Nombre: $1
Primer Apellido: $2
Segundo Apellido: $3
Teléfono: ${4:No disponible}
Nombre completo: $2 $3, $1
$0

Un último apunte

Los recortes de código están disponibles en numerosos editores de texto y suelen usar una sintaxis parecida para definir las plantillas, por lo que, en principio, será fácil trasladarlas de unos editores a otros.

El uso de recortes de código hace que la tarea de escribir un texto pueda ser más ágil en el caso de repetir algún cierto patrón de texto. A la hora de programar una página web, un código en C, o algo similar, los recortes de texto disminuyen los errores y ahorran tiempo.

Que los disfrutéis.


Viernes 10 de marzo de 2017

BlogDRAKE: Humor: La comunidad en estos momentos 2
José María Morales Vázquez

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

Chuletillas (y XXXXVII) – Instalar un programa de debian Stretch mientras que usas debian stable (Jessie)

chuletaSi quieres instalar un determinado programa (y sus dependencias obligatorias) incluido en la próxima versión de Debian (Stretch) mientras continuas usando la versión stable (Jessie) puedes hacerlo de la siguiente forma:

En primer lugar edita tu fichero sources.list (en el directorio /etc/apt) e incluye al final las direcciones de los repositorios de Stretch pero sin eliminar ni modificar los que ya usas de Jessie. Por ejemplo así:

# Repositorios de Jessie
deb http://http.debian.net/debian/ jessie main contrib non-free
deb-src http://http.debian.net/debian/ jessie main contrib non-free
deb http://security.debian.org/ jessie/updates main contrib non-free
deb-src http://security.debian.org/ jessie/updates main contrib non-free

# Updates de Jessie, antes conocidos como 'volatile'
deb http://http.debian.net/debian/ jessie-updates main contrib non-free
deb-src http://http.debian.net/debian/ jessie-updates main contrib non-free

# Backports de Jessie
deb http://http.debian.net/debian jessie-backports main contrib non-free

#Repositorios de Stretch
deb http://http.debian.net/debian/ stretch main contrib non-free
deb-src http://http.debian.net/debian/ stretch main contrib non-free
deb http://security.debian.org/ stretch/updates main contrib non-free
deb-src http://security.debian.org/ stretch/updates main contrib non-free

# Updates de Stretch
deb http://http.debian.net/debian/ stretch-updates main contrib non-free
deb-src http://http.debian.net/debian/ stretch-updates main contrib non-free

A continuación creamos un fichero llamado stretch en el directorio /etc/apt/preferences.d y escribimos en el lo siguiente:

Package: *
Pin: release n=jessie
Pin-Priority: 900

Package: *
Pin: release n=stretch
Pin-Priority: 100

Con esto estamos modificando la prioridad con la que Debian actualizará nuestros paquetes. Por defecto instala siempre la versión más moderna de todas las que tenga disponibles en sus repositorios. Con este fichero le dará preferencia a cualquier paquete de jessie frente a uno de stretch aunque tenga una versión menor. Es decir, mantendremos nuestro sistema con las versiones de jessie salvo que un paquete no exista en esta y si en stretch… O se lo indiquemos manualmente durante la instalación que es lo que vamos a ver a continuación. Si quieres maś información sobre la forma de establecer preferencia para apt puedes echarle un vistazo a esta página.

Y ya lo tenemos todo listo. Ahora, tenemos que actualizar nuestros repositorios (apt update) y cuando queramos instalar un paquete directamente de stretch lo especificamos manualmente en el comando apt. Por ejemplo, si quisiéramos instalar la versión de apache de stretch lo haríamos así:

apt-get install -t stretch apache2

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: Chuletillas (y XXXXVII) – Instalar un programa de debian Stretch mientras que usas debian stable (Jessie) || Hospedado en un Cloud VPS de Gigas.

Jueves 09 de marzo de 2017

Más sobre el soporte OpenType en LibO 5.3+

Como comenté hace unos meses, LibO 5.3 nos ha sorprendido con el soporte OpenType completo. Esto ciertamente significa que la próxima edición de cierto libro (cuando llegue) vendrá con el capítulo sobre tipografía completamente reescrito… Pero bueno, mientras esperamos he pensado que conviene dejar un artículo detallado sobre el tema. Pues bien, como ya comenté […]

Miércoles 08 de marzo de 2017

Aprender Linux con los cursos gratuitos de Linux Foundation

Si eres de los que todavía no ha probado Linux porque piensas que todavía no vas a ser capaz de afrontar el cambio de un sistema operativo a uno más puro o que te faltan conocimientos para ello, no pares de leer, quizá este post haga que cambies de opinión. Desde hace ya unos años la fundación Linux tiene disponibles unos cursos online tanto para profesionales que en algún ámbito de sus
Liher Sanchez

Liher Sanchez
El blog de Liher

Un año con el Xiaomi Redmi 3

Hace aproximadamente un año que compre un Xiaomi Redmi Note 3. Cuando llevaba con el un mes, mas o menos, a mi madre se le estropeó su móvil y decidí regalárselo y comprar para mi el Xiaomi Redmi 3. Ya llevamos un año con ellos y os voy a contar mis impresiones y mi opinión sobre estos terminales y sobre la marca en general.

Antes de comprar el Xiaomi Redmi Note 3 llevaba tiempo queriendo tener un móvil de dicha marca, había leído muy buenas opiniones de ellos y quería comprobarlo de primera mano. Mirando varios Xiaomi encontré muchos modelos y me costó decidirme, uno que me gustó mucho fue el Xiaomi mi5. Cuando me llegó la primera impresión que me llevé es que era muy grande para mi. El Note 3 es un móvil de 5,5 pulgadas de pantalla, ademas los botones no forman parte de la pantalla, están justo debajo, lo cual hace que sea mas grande. Si me paro a pensar la verdad es que la diferencia de tamaño con respecto al Redmi 3 no es mucha, pero ya el de 5 pulgadas se me hace un poco grande.

 

 

La verdad es que quizás sea la única pega que le encontré al Note 3, y no es que sea algo malo, pero son preferencias personales. Si te gustan los móviles grandes es una muy buena elección. Por eso, cuando recibí el Xiaomi Redmi 3 estaba mas satisfecho, ya que su tamaño me gustaba mucho mas.

En cuanto a las características de los móviles son prácticamente iguales. Ambos tienen un procesador de 8 núcleos, 2 GB de RAM, 16GB de espacio y una batería de unos 4.000 Mah. En ambos móviles he instalado juegos potentes para ver como los movían y la respuesta ha sido muy buena, quizás sea una de las mejores formas de comprobar su rendimiento y han superado la prueba con creces.

La multitarea funciona en ambos realmente bien y puedes moverte entre las diferentes aplicaciones que tengas abiertas con total soltura y sin sufrir nada de lag. La cámara tiene muy buena calidad, hace buenas fotos y graba buenos vídeos, quizás un punto flaco sea las fotos y vídeos nocturnos, pero eso pasa en prácticamente todos los móviles a no ser que sean de muy alta gama.

Una de las cosas que mas me preocupaba era la batería. Vienen con una batería de unos 4.000 Mah y, en principio debería servir para usar el móvil un día entero sin ningún problema, lo cual he podido comprobar. Ha habido varias ocasiones en las cuales la batería me ha aguantado dos días sin problemas, y dándole bastante uso. La mayoría de los días lo pongo a cargar por la noche aun quedándole un 40% de batería. Su capacidad, después de un año, no se ha visto mermada ni un ápice, sigue igual que el primer día, en ambos modelos.

En cuanto a su robustez puedo decir que son unos teléfonos muy duros. Yo soy muy torpe y el mio se me ha caído de las manos en varias ocasiones, de hecho tiene las cuatro esquinas marcadas ya que ha caído sobre ellas en mas de una ocasión y apenas tiene unas ligeras marcas y la pantalla esta intacta, por lo tanto estamos hablando de unos terminales muy resistentes.

Una cosa que me preocupaba era los posibles problemas que podrían surgir por si el terminal se estropeaba y como tramitar el tema de la garantía. Para evitar malos ratos lo mejor seria comprar un Xiaomi en una tienda en España. Mirando por Internet encontré esta tienda en la cual se pueden comprar cualquier móvil Xiaomi, ordenadores, tablets y componentes de Xiaomi y dan 2 años de garantía. Si, en el periodo de garantía, lo que hayas comprado se estropea ellos lo recogen, lo arreglan y te lo devuelven sin coste alguno y no lo mandan a China, lo arreglan aquí en España. Ademas, si no tiene arreglo te dan uno nuevo. Lo que compres en esa tienda lo tienes en casa en 24/48 horas, lo cual es algo muy bueno también y solo trabajan con Xiaomi.

Después de usar durante un año dos móviles Xiaomi tengo que decir que mi próximo móvil será de esta misma marca seguro, no me cabe ninguna duda. No creo que haya otra marca de teléfonos móviles que ofrezca una mejor relación calidad/precio que ellos, yo estoy muy satisfecho con mi compra.

Un saludo a todos.

Jueves 02 de marzo de 2017

José María Morales Vázquez

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

Nueva página: Herramientas web de testing y monitorización

herramientas En muchos de los articulos que publico por aquí referencio herramientas web encaminadas a ayudar con la configuración, pruebas o análisis de diversos elementos de nuestra infraestructura informática. Servidores Web, certificados SSL, Disponibilidad, Correo Electrónico, Seguridad, etc. El enlace a la página está en el índice lateral y aquí:

Herramientas web de Testing y Monitorización

El propósito de esta nueva página es recogerlas en un único lugar para mantener una referencia completa, cómoda y perfectamente autorizada. Todas las herramientas relacionadas en ella son gratuitas al menos en un modo básico aunque podrían tener un modo de pago más completo. Y si conoces alguna otra que no aparece y crees que puede ser útil no dejes de enviármela a través de un comentario por favor. Gracias.

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: Nueva página: Herramientas web de testing y monitorización || Hospedado en un Cloud VPS de Gigas.

Lunes 27 de febrero de 2017

José María Morales Vázquez

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

Chuletillas (y XXXXVI) – Solventar el error de wordpress que lo deja bloqueado en modo de mantenimiento

chuleta Si trabajas habitualmente con wordpress te habrá pasado montones de veces. Tras actualizar un plugin, un tema o el propio wordpress la instancia web se queda “eternamente” mostrando un mensaje como el que sigue a pesar de que debería (y lo ha hecho) haber concluido ya la actualización en cuestión.

Briefly unavailable for scheduled maintenance. Check back in a minute.

En esos casos recurres a buscar en google un blog (como este) donde te cuentan la solución o le pides a algún amigo (que hará o habrá hecho lo mismo en alguna ocasión) que te lo solucione. En el peor de los casos le pagas a alguien para que te solucione el problema o recurres a la empresa que te lleva el mantenimiento.

La solución es muy sencilla. wordpress “detecta” que debe de mostrar el mensaje de mantenimiento porque en el directorio raiz de la instancia web existe un archivo llamado .maintenance En algunas ocasiones el borrado de ese fichero falla una vez concluida la actualización y wordpress se queda ahí encallado. Para solucionarlo basta con borrar manualmente ese fichero desde el panel web que usemos para acceder a nuestro servidor (si somos novatos) o desde la consola si nos manejamos un poco mejor. Fácil, eh?

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: Chuletillas (y XXXXVI) – Solventar el error de wordpress que lo deja bloqueado en modo de mantenimiento || Hospedado en un Cloud VPS de Gigas.

Domingo 19 de febrero de 2017

Marcelo Fortino

Marcelo Fortino
Fortinux

Tutorial Instalar PHP Server Monitor en Ubuntu GNU/Linux

En este tutorial vamos a instalar PHP Server Monitor en un servidor Ubuntu 14.04. PHP Server Monitor es una aplicación web open source que sirve para monitorear servidores web y/o sitios web.

Sábado 18 de febrero de 2017

Liher Sanchez

Liher Sanchez
El blog de Liher

Usar el icono del Launcher de Ubuntu para maximizar una ventana

El otro día os hable de como podemos minimizar todas las ventanas que tenemos abiertas de nuestro Ubuntu de una vez con una combinación de teclas para así poder ver nuestro escritorio. También os mostré como podéis añadir el botón de Mostrar escritorio al Launcher. Quizás esa opción debería venir por defecto, quizás no, pero la que os voy a comentar en este post me parece mas útil y si que debería venir activada, por lo menos esa es mi opinión. Se trata de que cuando tenemos una aplicación abierta, al hacer click en su icono en el Launcher, la ventana de dicha aplicación se minimice. Por defecto no viene activado, pero es muy fácil hacerlo.

Muchos dirán que las cosas que tienen que venir por defecto activadas o no en Ubuntu dependen de nuestra forma de movernos con el ordenador y que Cannonical no puede atender todas las peticiones o bien hacer un Ubuntu que sea del agrado de todos con estas pequeñas cositas, pero en fin, cada uno tiene su opinión 😀 Por suerte estas coas tienen muy fácil y rápida solución.

Personalmente, me parece que es muy útil que podamos minimizar las ventanas de los programas haciendo click en su icono, ademas de si esta minimizada poder ponerla en primer plano al hacer click también en su correspondiente icono. Digamos que es un comportamiento tipo dock que yo usaba mucho cuando tenia instalado el Cairo dock.

Si queréis que cuando una aplicación este abierta la podamos minimizar al hacer click en su icono en el Launcher de Ubuntu lo único que tenéis que hacer es abrir una Terminal y escribir el siguiente comando en ella:

gsettings set org.compiz.unityshell:/org/compiz/profiles/unity/plugins/unityshell/ launcher-minimize-window true

Solo hace falta teclear ese comando y pulsar Enter para poder disfrutar de esa posibilidad. Si, por alguna razón, queréis volver al estado inicial y no tener esa opción activada lo único que tenéis que hacer es teclear el mismo comando pero con “false” en vez de “true” al final, quedando el comando de la siguiente forma:

gsettings set org.compiz.unityshell:/org/compiz/profiles/unity/plugins/unityshell/ launcher-minimize-window false

Como podéis es bastante sencillo. Ahora solo queda que lo probéis y toméis la decisión de usarlo o no.

Un saludo a todos.

Lunes 13 de febrero de 2017

Liher Sanchez

Liher Sanchez
El blog de Liher

Los juegos que me gustan

Siempre me han gustado los videojuegos. Muchos de los que usamos ordenador hemos tenido épocas en las que los hemos usado, en mayor o menor medida. En mi caso ha habido muchos juegos que me han gustado y me gustan y quiero hablaros un poco de ellos, ademas de recordaros algunos que seguro conocéis.

Mi primer ordenador lo tuve con 14 años, era un 386 con 2 MB de RAM y 43 MB de disco duro. Por aquel entonces los juegos venían en uno o varios disketes de 3 ½. Seguramente algunos de vosotros no hayáis usado este medio, os dejo una imagen para que los podáis conocer:

 

disketes

 

Tenia una capacidad de 1,44 MB, algunos juegos ocupaban varios disketes y otros entraban de sobra en ellos. De aquella época guardo buenos recuerdos de varios juegos en especial de 3. El primero es The secret of Monkey island era un juego de tipo aventura gráfica en el cual tenias que ir saliendo airoso de varias situaciones gracias a tu ingenio, era un juego gracioso y entretenido del que seguro que muchos de mi generación guardan un buen recuerdo.

 

the secret of monkey island

 

Otro juego fue Prince of persia, era un juego de plataformas y lucha en el cual tenias que ir por diferentes niveles para rescatar a un princesa. Estaba muy entretenido y me gustó mucho.

 

prince of persia

 

El tercero es Warcraft, un juego de estrategia de guerra en el cual tenías que crear una aldea, recolectar recursos, prosperar y conquistar otras aldeas, muy parecido a Clash of clans.

 

 

Por supuesto que jugué a muchos mas juegos, pero esos tres son los que más me gustaron de aquella época.
Posteriormente, al ir cambiando de ordenador y tener una máquina más potente puede ir accediendo a juegos mas actuales como el FIFA o el Quake. Uno que me gustó mucho también fue el Age of Empires, en la linea del Warcaft, siempre me gustaron ese tipo de juegos de estrategia y guerra.

Con 22 años, mas o menos, tuve mi primera consola de videojuegos, la PS One, con ella tuve una enganchada importante al Gran Turismo 2, de hecho conseguí pasarme el juego entero. Prácticamente solo jugaba a ese juego, aunque el Driver y el FIFA me ocuparon muchas horas también.

También tuve una época en la que usaba un emulador llamado MAME con el cual se podían usar juegos de casi todas las videoconsolas y las máquinas recreativas, en un DVD podías tener el emulador en sí mismo y miles de juegos, desde los de Atari de los años 80 hasta juegos como el Tekken.

Hace tiempo que no tengo videojuegos en el ordenador, a día de hoy no tengo ninguno, ya que como se que soy de fácil enganche lo mejor es no tener ningún instalado, conócete a ti mismo ;D

También tuve una temporada en la que jugaba a algún juego online. Uno de ellos era un juego de poker. Al principio estaba bastante perdido con las reglas y el valor de las posibles combinaciones pero en Internet siempre podemos encontrar ayuda como en esta página, en la cual podemos aprender todo lo necesario gracias a un glosario del juego, y así podemos mejorar nuestra habilidad y aumentar nuestros conocimientos sobre un juego del que mucha gente piensa que es cuestión de azar y no es así, necesitamos de destreza e ingenio para jugar bien.

A día de hoy el único juego que uso es el Clash of Clans, siempre me han gustado los juegos de estrategia y con el tengo el entretenimiento que necesito. Aun a pesar de ser un juego sencillo, tiene un sinfín de posibilidades. Atacar una aldea y ganar el ataque, a la vez que tener una buena defensa en tu aldea es como una partida de ajedrez donde cada elemento tiene un propósito y hay que averiguar la mejor forma de usarlo. De echo tengo en mente crear una web sobre el juego con consejos, diseños de aldea y demás, aunque voy poco a poco.

 

clash of clans

 

Y bueno, eso es un poco todo, la verdad es que me encantaría que compartieseis los juegos que usáis, aquellos que más os gustan o los que recordáis con nostalgia. Un saludo a todos.

Martes 07 de febrero de 2017

Ramón Miranda

Ramón Miranda
Ramon Miranda

TRUN videogame cover for VGsource


Talking about TRON is talking about a classic science fiction film and one of the best tributes to creativity and imagination in the world of cinema. Somewhat misunderstood film at first, but time makes justice and put TRON in its place. And if we talk about mythical elements of the film, we have to talk about bikelight racings ...

TRUN is a videogame created in Z80 assembler based on  original TRON.
The creators of the game are Vgsource, an indie development group that codes for MSX.
A few months ago, I was contacted to design their videogame cover and thus give it a greater visual impact.
It was an interesting work because from the first moment we looked for a 80's look"  immitating the style of covers of the era of Dinamic or Topo (spanish companies), where Azpiri was king illustrating those beautiful casettes and the less important was the result on screen (at least for people like me)
The first thing I did was to take references, and as it was not going to be otherwise the TRON movie itself was the main source of inspiration. I had several keys in mind while painting this illustration:
  •     blue
  •     Light
  •     No Fx overlay.
  •     Speed
  •     80's smell
Do you want to see how development was? Then we analyze the different phases briefly.

Sketches Phase

After analyzing what I want to emphasize in the image I start working on the sketches.
These are not very detailed drawings, but you can see the main elements of the design.


I decide for the first by movement feeling.



As we know the diagonals add movement to the composition and as I want to transmit speed I choose the design with that scheme and the broad to be able to study where to place each thing. Something that in the end I will change are the bikes. Finally will be even more "homage" to the original light bikes designed by Syd Mead.

References Phase

Being the game a "clone" of the game of TRON does not seem crazy to me to take references of the film. Since we are going to make a copy of a classic we will do well. Let it be noticed! That's why I create a composition with multiple references to then paint over what I need and get the result I want, not so photo but 2d. There is still a lot of work left. This system is not the only one I use for my illustrations.
This is the result of collage done inside Krita. All images have their corresponding copyright. We only use this as an idea. At the end, 100% of the illustration is repainted.



From this point we will work the Backgrounds. For the backgrounds, brushes that are quick for "covering big areas" are usually used. I use a brush that has the characteristic that diffuses the paint when low pressure is used and is adding more paint as the pressure increases. This is what I show you in the capture.




It has a Knive effect and belongs to the set I made for the DVD of the krita foundation #muses. If you are interested you can download it here totally free.

PACK bundle muses

Note: If for some reason you see that this brush produces somekind of "Lag", a very useful thing that speed up this brush and many of Krita's brushes is to use the "precision" parameter inside the brush editor and lower it from 5 to 1 If you also use large sizes you can increase the brush spacing to 0.5 or 0.7. It can be further optimized to gain speed in very large sizes.




Beyond it you will see that it is very fluid but loses a little of quality. These brushes require important computation operations for the CPU but give very interesting results.
What I want is to blur the photo effect but respecting the colors that are underneath while still being spots and at the same time giving me more freedom to paint over. You will see that the result is very pictorial. Handcrafted within the digital.

 
Now it's time to start defining all the elements of the image.
The face in the photo does not show an emotion according to what I look for, come on man! You're playing with your life in a race! :)
I have created this Gif for those who like to follow the evolution of the steps to follow.


You can see how the lighting changes as I work the metal. The gif was done with Gimp. It explains much more than a page of text. Among other things it is seen how the light is affecting the face of the character and his helmet.

The same thing happens in the background. When I go detailing the bikes and the kind of hangar where they come from.

When completing the image we run the risk of adding too many details. So beware of the Glow and the additive or color dodge modes that hook.
Making lines or curves accurately is complicated with freehand so one way to avoid headaches is to use paint assistants.

For example a use would be in the curve that defines the motorcycle panel of the character.


LightBykes

A main element of this image are the light bikes. Let's do something simple so we do not separate too much from what will be seen on the screen.


 

The problem as I see it is that the bikes need some lines of movement. This will convey more sense of career. In the end I choose lines not on the whole bike but in part. The result is something more shocking.


Logotype design for the cover

All we have left to do is create a logo for the cover design. For that task I better use an image editor like Gimp and a vector design program like Inkscape.

In Gimp I select the text tool with the previously downloaded typography that is very similar to TRON.


To vary slightly the layout i adjust and complete the contour of the word "TRUN" That way I have a good basis for editing in Inkscape and that can be adapted to any size without loss of quality.


Now we can add the text to our image.
And the end result is what we expected. Did you like it?

** If you liked the article and learned something to help you, you can support me by sharing the news with your friends. See you in the next article.

If you want to know more about the video game these links may seem interesting.


Some photos

Asociación de amigos del MSX




https://www.msx.org/es/news/software/es/trun-nuevo-juego-de-msx
 



Ramón Miranda

Ramón Miranda
Ramon Miranda

Portada para videojuego TRUN de VGsource


Hablar de TRON es hablar de un clásico de la ciencia ficción y de uno de los mejores tributos a la creatividad e imaginación en el mundo del cine. Película un tanto incomprendida al inicio, pero el tiempo le dio la razón y la puso en su lugar. Y si hablamos de elementos míticos de la película, tenemos que hablar de las carreras de motos de luz...

TRUN es un videojuego creado en ensamblador Z80 basado en TRON.
Los creadores del Juego son Vgsource, un grupo indie de desarrollo que programa para MSX.
Hace unos meses, me contactaron para diseñar su portada y así darle un impacto visual mayor.
Fue un trabajo interesante porque desde el primer momento se buscaba un "look" ochentero imitando el estilo de portadas de la época de Dinamic o Topo, donde Azpiri era el rey ilustrando esos bellos casettes y lo de menos era el resultado en pantalla ( al menos para personas como yo)
Lo primero que hice fue coger referencias, y como no iba a ser de otra forma la propia película de TRON fue la principal fuente de inspiración. Tenía varias claves en mente mientras pintaba esta ilustración:
  • Azul
  • Luz
  • No Fx overlay.
  • Velocidad
  • Espíritu 80's
¿Os apetece ver como fue el desarrollo? Pues analizamos las diferentes fases brevemente.

    Fase de Bocetos

    Después de analizar qué quiero destacar en la imagen empiezo a trabajar en los bocetos.
    Estos son dibujos no muy detallados en los que se pueden ver los elementos principales del diseño.



    Me decido por la primera por la sensación de movimiento.



    Como ya sabemos las diagonales añaden movimiento a la composición y como quiero transmitir velocidad elijo el diseño con ese esquema y lo amplio para poder estudiar dónde colocar cada cosa. Algo que al final voy a cambiar son las motos. Finalmente serán aun más “homenaje” a las originales motos de luz diseñadas por Syd Mead.

    Fase de referencias

    Siendo el juego un calco del juego de TRON no me parece una locura coger referencias de la película. Ya que vamos a hacer una copia de un clásico vamos a hacerlo bien. ¡Que se note! Por eso creo una composición con las múltiples referencias para luego pintar por encima lo que necesite y llegar al resultado que quiero, no tan foto sino más 2d. Queda aun mucho trabajo.Este sistema no es el único que uso para mis ilustraciones.

    Este es el resultado del collage realizado dentro de Krita. Todas las imágenes tienen sus derechos de autor correspondientes. Esto solo lo usamos como idea. Al final se repinta el 100% de la ilustración.



    A partir de este punto vamos a trabajar los fondos. Para los fondos normalmente se usan pinceles que sean rápidos que "cubran" Utilizo un pincel que tiene la característica que difumina la pintura cuando se ejerce poca presión y va añadiendo más pintura según aumenta la presión. Es este que os muestro en la captura.



    Tiene un efecto como de espátula y pertenece al set que hice para el DVD de la krita foundation #muses. Si os interesa os lo podéis descargar aquí totalmente gratis.

    PACK bundle muses

    Nota: Si por alguna razón veis que este pincel produce algo de "Lag", una cosa muy útil que acelera tanto este pincel como muchos de los de Krita es utilizar el parámetro "precisión" dentro del editor de pinceles y bajarlo de 5 a 1. Si además utilizas tamaños grandes puedes aumentar el espaciado del pincel hasta 0.5 o 0.7. Se puede optimizar aun más para ganar velocidad en tamaños muy grandes.




    Más allá verás que va muy fluido pero pierde un poco de calidad. Estos pinceles exigen operaciones de cómputo importantes para la CPU pero dan resultados muyyy interesantes.  

    Lo que quiero es desdibujar el efecto foto pero respetando los colores que hay debajo aun siendo manchas  y a la vez darme más libertad para pintar por encima. Veréis que el resultado es muy pictórico. Artesanal dentro de lo digital.


     

    Ahora es tiempo de empezar a definir todos los elementos de la imagen.

    La cara en la foto no muestra una emoción acorde a lo que busco, vamos hombre! ¡Que te estás jugando la vida en una carrera! :)

    He creado este Gif para los que les gusta seguir una evolución de los pasos a seguir.

    Se puede apreciar como va cambiando la iluminación según voy trabajando el metal. El gif lo hice con Gimp. Explica mucho más que una página de texto. Entre otras cosas se ve cómo la luz va afectandola cara del personaje y su casco.
    Lo mismo sucede en el fondo. Cuando voy detallando las motos y la especie de hangar de donde salen.


    Al ir completando la imagen corremos el riesgo de añadir demasiados detalles. Así que cuidado con el Glow y los modos aditivos o color dodge que enganchan.
    Hacer lineas o curvas con precisión es complicado a mano alzada por eso una forma de evitarnos quebraderos de cabeza es utilizar los asistentes de pintura.



    Por ejemplo un uso sería en la curva que define el panel de la moto del personaje.


    Motos de Luz.

    Un elemento principal de esta imagen son las motos de Luz. Vamos a hacer algo sencillo para no separarnos demasiado de lo que se verá en pantalla.

     

    El problema según veo es que las motos necesitan unas lineas de movimiento. Esto va a transmitir más sensación de carrera. Al final opto por lineas no en toda la moto sino en parte. El resultado es algo más impactante.


    Diseño de Logo para la portada

    Ya solo nos queda realizar un logotipo para el diseño de la portada. Para esa tarea mejor utilizo un editor de imágenes como Gimp y un programa de diseño vectorial como Inkscape.

    En Gimp selecciono la herramienta texto con la tipografía previamente descargada que es muy parecida a la de TRON.



    Para variar un poco el diseño ajusto y completo el contorno de la palabra TRUN De esa forma ya tengo una buena base para editarlo en Inkscape y que se pueda adaptar a cualquier tamaño sin perdida de calidad.

    Ahora ya podemos añadir el texto a nuestra imagen.
    Y el resultado final es lo que esperábamos . ¿Os ha gustado?
    **Si te ha gustado el artículo y has aprendido algo que te ayude, puedes apoyarme compartiendo la noticia con tus amigos. Nos vemos en el próximo artículo.
    Si quieres saber más del video juego estos enlaces te pueden parecer interesantes.

    Algunas fotos

    Asociación de amigos del MSX


    https://www.msx.org/es/news/software/es/trun-nuevo-juego-de-msx
     




    Martes 31 de enero de 2017

    Tutorial de Maud, motor de plantillas HTML para Rust

    Seguimos aprendiendo en el blog sobre interesantes proyectos hechos para Rust. Ya hemos visto Iron, Piston y Neon. Hoy veremos Maud, un potente motor de plantillas que se centra en la eficiencia. Maud se compara a otras soluciones como Razor, ERB, Liquid,  Handlebars o Jade pero esta vez escribiremos nuestro HTML en Rust. ¿Locura? No, y de hecho funciona de forma bastante transparente. Vamos a verlo en acción

    Comparativa de velocidad de diferentes motores. Maud es el más rápido (menos es mejor)

    Instalando Maud

    Maud usa plugins del compilador, una característica que a día de hoy no está activado ni en el canal estable ni el canal beta, solamente en el canal nightly. Para obtener una copia de Rust nightly lo ideal es usar Rustup.

    Una vez hecho eso, creamos un nuevo proyecto y añadimos las dependencias de Maud al fichero Cargo.toml.

    maud = "*"
    maud_macros = "*"
    

    Una simple plantilla

    Ahora abrimos el archivo src/main.rs y vamos a empezar a usar Maud.

    #![feature(plugin)]
    #![plugin(maud_macros)]
    
    extern crate maud;
    
    fn main(){
            let name = "Adrián";
            let markup = html!{
                p { "Hola, soy " (name) " y estoy usando Maud"}
            };
            println!("{}", markup.into_string());
    }
    
    

    La potencia de Maud se ve en la mega-macro html!. En esta macro escribiremos la plantilla que será compilada de forma nativa a Rust, lo que nos asegura una velocidad de ejecución excepcional. En este caso la salida será una etiqueta P de párrafo con la variable interpolada.

    Simple, ¿no?

    PreEscaped y otros elementos básicos

    Por defecto en Maud todos el texto se convierte a HTML seguro. Es decir, no se pueden introducir etiquetas nuevas en el texto. Si por alguna razón necesitásemos añadir etiquetas nuevas podemos usar PreEscaped, que no realiza esta transformación de seguridad. Veamos el siguiente código:

    #![feature(plugin)]
    #![plugin(maud_macros)]
    
    extern crate maud;
    
    use maud::PreEscaped;
    
    fn main(){
            let name = "Adrián";
            let markup = html!{
                    p { "Hola, soy " (name) " y estoy usando Maud" }
                    p { "<h5>Esto no funcionará</h5>" }
                    p { (PreEscaped("<h5>Esto sí funcionará</h5>")) }
            };
            println!("{}", markup.into_string());
    }
    
    

    El primer H5 se convertirá a código HTML seguro, es decir, no añadirá la etiqueta, en cambio se verá h5 en la web. Por contra con PreEscaped se añadirá la etiqueta h5 tal cual.

    Los elementos son muy fáciles de añadir en Maud y por lo general no deberías usar PreEscaped salvo contadas ocasiones. Veamos como añadir más etiquetas.

    #![feature(plugin)]
    #![plugin(maud_macros)]
    
    extern crate maud;
    
    fn main(){
            let name = "Adrián";
            let markup = html!{
                    p { "Hola, soy " (name) " y estoy usando Maud" }
                    p {
                            "Si la montaña no viene a Mahoma"
                            br /
                            "Mahoma va la montaña"
                            small em "Atribuido a Francis Bacon"
                    }
            };
            println!("{}", markup.into_string());
    }
    
    

    En este ejemplo vemos como las etiquetas que no llevan texto como BR o INPUT debemos cerrarlas con una barra. Por otro lado es posible aglutinar varios niveles de etiquetas en una sola línea ( SMALL->EM->Texto).

    Atributos, clases e IDs

    En Maud es posible asignar atributos también, usando literales o variables. Para los atributos de texto la sintaxis es muy parecida a HTML.

    #![feature(plugin)]
    #![plugin(maud_macros)]
    
    extern crate maud;
    
    fn main(){
            let name = "Adrián";
            let amazon = "http://www.amazon.com";
            let markup = html!{
                    p { "Hola, soy " (name) " y estoy usando Maud" }
                    p {
                            "Este texto contiene enlaces a "
                            a href="http://www.google.com" "Google"
                            " y a "
                            a href=(amazon) "Amazon"
                    }
            };
            println!("{}", markup.into_string());
    }
    

    Además existen en HTML atributos vacíos. Es decir, atributos que con su sola presencia basta y normalmente no llevan valor asignado.

    #![feature(plugin)]
    #![plugin(maud_macros)]
    
    extern crate maud;
    
    fn main(){
            let name = "Adrián";
            let allow_editing = true;
            let markup = html!{
                    p { "Hola, soy " (name) " y estoy usando Maud" }
                    p contenteditable?[allow_editing] {
                    }
            };
            println!("{}", markup.into_string());
    }
    

    En este caso el atributo contenteditable se añade si la variable allow_editing es true. Si queremos añadir atributos vacíos en cualquier circunstancia podemos simplemente quitar [allow_editing] y dejar p contenteditable? {}.

    Los IDs y las clases se añaden usando la sintaxis esperable, puntos y almohadillas.

    #![feature(plugin)]
    #![plugin(maud_macros)]
    
    extern crate maud;
    
    fn main(){
            let name = "Adrián";
            let markup = html!{
                    p { "Hola, soy " (name) " y estoy usando Maud" }
                    p.red.font-big#editor contenteditable? {
                    }
            };
            println!("{}", markup.into_string());
    }
    

    Estructuras de control

    Maud soporta las estructuras de control básicas de Rust, if/else, if/let, for in y match.

    #![feature(plugin)]
    #![plugin(maud_macros)]
    
    extern crate maud;
    
    fn main(){
            let loggedIn = false;
            let email = Some("mariscal@example.com");
            let fonts = ["Arial","Times New Roman","Verdana"];
            let markup = html!{
                    @if loggedIn {
                            h1 { "Has iniciado sesión" }
                    } @else {
                            h1 { "Por favor, inicia sesión primero" }
                    }
    
                    @if let Some(mail) = email {
                            p { "Su email es " (mail) }
                    }
                    ol {
                            @for font in &fonts {
                                    li (font)
                            }
                    }
    
            };
            println!("{}", markup.into_string());
    }
    

    Como vemos, Maud posee suficientes características para ser interesante. Maud además permite extender el motor para representar cualquier tipo de dato. Por defecto Maud mirá si está implementado std::fmt::Display pero si queremos añadir etiquetas extra este método no funcionará. En cambio si se implementa la trait maud::Render tendrás control total sobre como va a mostrar Maud las variables de ese tipo. En la crate maud_extras se encuentran implementaciones por ejemplo de Markdown para Maud.

    Maud se integra además con web frameworks de Rust, en especial con Iron y con Rocket. Sin duda, una de mis crates favoritas.

    La entrada Tutorial de Maud, motor de plantillas HTML para Rust aparece primero en Blog - Adrianistan.eu.

    Domingo 29 de enero de 2017

    Gorka Urrutia

    Gorka Urrutia
    Nideaderedes

    Cómo instalar PrestaShop con Vagrant

    Para evtiar dolores de cabeza y tener que andar configurando un servidor local en Linux o algún Wamp en Windows o Mamp en Mac podemos usar Vagrant. He creado una máquina virtual que puedes usar como entorno de desarrollo para PrestaShop.

    Cómo instalar PrestaShop con Vagrant

     

    Gorka Urrutia

    Gorka Urrutia
    Nideaderedes

    La guía definitiva del código espagueti II: Que tus variables y funciones confundan al enemigo

    Porque elegir unos nombres horribles para tus variables y funciones es un arte:

    La guía definitiva del código espagueti II: Que tus variables y funciones confundan al enemigo

    Gorka Urrutia

    Gorka Urrutia
    Nideaderedes

    Programación orientada a objetos en PHP. 3: Encapsulación

    Otra entrega más (y ya van tres) del mini curso de programación orientada a objetos en PHP. Esta vez hablo de encapsulación. No te lo pierdas:

    Programación orientada a objetos en PHP capítulo 3: ¿Por qué no hacer todo public? (Encapsulación).

    Viernes 27 de enero de 2017

    Tutorial de Neon – Combina Node.js con Rust

    Hoy en día muchas webs se diseñan con Node.js. Es una solución fantástica para respuestas rápidas pero numerosos benchmarks han demostrado que su rendimiento empeora en respuestas complejas. Estos mismos benchmarks recomiendan usar Java o .NET si preveemos que nuestra aplicación web va a generar respuestas complejas. Sin embargo renunciar a las ventajas de Node.js no es del agrado de muchos. Afortunadamente hay otra solución, usar Rust. Todo ello gracias a Neon.

    Con Neon podemos generar módulos para Node.js que son escritos y compilados en Rust con las ventajas que supone desde un punto de vista de rendimiento y con la certeza de que en Rust la seguridad está garantizada.

    Usando Neon puedes desarrollar tu aplicación en Node.js y si alguna parte tiene problemas de rendimiento sustituirla por su equivalente en Rust. Para el ejemplo voy a hacer un módulo de Markdown.

    Instalando Neon

    En primer lugar instalamos la herramienta de Neon desde npm.

    npm install -g neon-cli
    

    Una vez esté instalado podemos usar la herramienta de Neon para construir un esqueleto de módulo. Este esqueleto tendrá dos partes, un punto de entrada para Node.js y otro para Rust.

    neon new PROYECTO
    

    Hacemos un npm install como nos indica. Esto no solo obtendrá dependencias de Node.js sino que también se encargará de compilar el código nativo en Rust.

    El código Node.js

    Nuestro módulo contiene un archivo de Node.js que sirve de punto de entrada. Allí lo único que se debe hacer es cargar el módulo en Rust y hacer de pegamento. Puede ser algo tan simple como esto:

    var addon = require("../native");
    
    module.exports = addon; // se exportan todos los métodos del módulo nativo
    

    Aunque si queremos añadir un tratamiento específico también es posible.

    var addon = require("../native");
    
    module.exports = {
        render: function(str){
            return addon.render(str);
        }
    }
    

    El código en Rust

    Nos dirigimos ahora al archivo native/src/lib.rs. Ahí definimos los métodos nativos que va a tener el módulo. Lo hacemos a través de la macro register_module!.

    register_module!(m,{
        m.export("render",render)
    });
    

    Ahora vamos a implementar la función render, que toma el texto en Markdown y lo devuelve en HTML.

    fn render(call: Call) -> JsResult<JsString> {
        let scope = call.scope; // obtener el contexto
        let md: Handle<JsString> = try!(try!(call.arguments.require(scope,0)).check::<JsString>()); // obtener primer argumento como JsString. aquí puede hacerse tratamiento de fallos
        let string = md.value(); // Pasar JsString a String
        let html: String = markdown::to_html(&string); // usamos la crate markdown para renderizar a html
        Ok(JsString::new(scope, &html).unwrap()) // devolvemos un JsString con el contenido del HTML
    }
    
    

    Las funciones que interactuan con Node deben devolver un JsResult de un tipo JsXXX, por ejemplo, JsString, JsUndefined o JsInteger. Siempre aceptan un argumento llamado de tipo Call que nos da toda la información necesaria y que podemos usar para sacar argumentos. El scope o contexto es muy importante y lo deberemos usar en las funciones que interactúen con Node.

    Código completo del fichero Rust

    #[macro_use]
    extern crate neon;
    extern crate markdown;
    
    use neon::vm::{Call, JsResult};
    use neon::js::JsString;
    use neon::mem::Handle;
    
    fn render(call: Call) -> JsResult<JsString> {
        let scope = call.scope;
        let md: Handle<JsString> = try!(try!(call.arguments.require(scope,0)).check::<JsString>());
        let string = md.value();
        let html: String = markdown::to_html(&string);
        Ok(JsString::new(scope, &html).unwrap())
    }
    
    register_module!(m, {
        m.export("render", render)
    });
    

    Y no te olvides de añadir la dependencia markdown al fichero Cargo.toml.

    Probándolo

    Es muy fácil probarlo. Con el REPL de Node podemos probar partes del módulo antes de publicarlo a npm.

    Para abrir el REPL ejecuta Node sin argumentos

    node
    

    E introduce línea por línea lo que quieras probar:

    var md = require("./");
    md.render("__Esto es Markdown__");
    

    Verás el resultado por la pantalla:

    Ahora que ya sabemos que funciona podemos publicarlo a npm si queremos con:

    npm publish
    

    Aunque recuerda revisar antes el fichero package.json para especificar la licencia y la descripción. Una vez esté publicado su uso en un nuevo proyecto será muy sencillo y de forma transparente se compilará el código nativo.

    var md = require("rust-markdown");
    var http = require('http');
    var fs = require("fs");
    
    var server = http.createServer((req, res) => {
      fs.readFile("index.md","utf-8",function(err,data){
         var html = md.render(data);
         res.statusCode = 200;
         res.setHeader('Content-Type', 'text/html');
         res.end(html);
      });
    });
    
    server.listen(8080, "127.0.0.1", () => {
      console.log("Server running");
    });
    
    
    
    

     

     

    La entrada Tutorial de Neon – Combina Node.js con Rust aparece primero en Blog - Adrianistan.eu.

    Sábado 21 de enero de 2017

    Ramón Miranda

    Ramón Miranda
    Ramon Miranda

    Underwater Romance


    Hola a todos mis lectores y colegas. Se fue el 2016, y el 2017 ya lo tenemos aquí.
    Este pequeño artículo es de esos momentos en los que uno hace balance de cómo le fue el año y se pone nuevas metas.Para mi ha sido espectacular. Lo más importante es que al fin di el sí quiero con la mujer que amo. Se llama Lara y es parte fundamental de que esté aquí en Málaga, en esta tierra de luz y color donde tantas veces veranee de pequeño. Nos casamos de manera discreta y sin mucho ruido como queríamos que fuera. Así que en estos momentos estoy muy feliz. Quizás algún día asome por el blog, aunque de momento os digo que no tiene nada que ver con el mundo de la imagen.

    Ya metidos en materia también es muy destacable toda la evolución que ha habido dentro del mundo Krita. Increíble trabajo el de los desarrolladores. Una de las imágenes que la fundación decidió utilizar, fue esta que publico la cual pinté exclusivamente para ellos como recompensa para los que apoyaron la campaña de Kickstarter de Krita en este año. Este es el resultado de apoyar a Krita. la recompensa de ver cómo mejora cada día y ver que más usuarios puedan aprender desentrañando la imagen en alta resolución viendo todas las capas correctamente nombradas. Si quieres apoyar para que el proyecto sea aun mas grande aquí tienes un link https://krita.org/en/support-us/donations/




    Cabe destacar que la idea de hacer la ilustración como vista en el fondo del mar, se le ocurrió a mi mujer tras ver lo que estaba haciendo y los colores que estaba usando. 

    La cara de ella quizás ha sido la parte más difícil. 3 veces la repetí hasta dar con el gesto que buscaba, una pose de inocencia y a la vez de "me dejo seducir por este guapo sireno" ;D



    Si os gusta el resultado seguro que vais a disfrutar con el próximo artículo donde explicaré cómo se hizo esta imagen desde el boceto de color a la pintura acabada.

    Nos leemos






    English Readers

    Hello to all my readers and colleagues. 2016 has gone, and 2017 is already here

    This small article is one of those moments in which you think about how the year went and set new goals. For me it has been spectacular. The most important thing is that finally! I said "yes, i do" to the woman I love. Her name is Lara and she is a fundamental part for being here in Malaga, in this land of light and color where i spent so many summers as a child. We married discreetly and without too much noise as we wanted it to be. So right now I'm very happy. Maybe someday she will write something here, for now I swear you she has nothing to do with the world of the image. :D

    Talking about the picture... is also very remarkable all the evolution that has been in the Krita world. Incredible work for the developers. One of the images that the foundation decided to use, was this one that I published exclusively for them as a reward for those who supported Krita's Kickstarter campaign this year. The bakers with 50$ baked if i remember well received the image in high res and .kra format to learn more about how to use krita. If you want to support krita more there you have a link https://krita.org/en/support-us/donations/



    It is noteworthy that the idea of ​​making the illustration as seen on the bottom of the sea, occurred to my wife after seeing what i was doing and the colors i was putting on canvas.

    Mermaid's face has been the hardest part. I repeated 3 times until I found the gesture I was looking for, a pose of innocence and at the same time "I let myself be seduced by this handsome siren";D





    If you like the result you will enjoy with the next article where I will explain how this image was made from the color sketch to the finished painting.









    Martes 17 de enero de 2017

    Tutorial de Piston, programa juegos en Rust

    Ya he hablado de Rust varias veces en este blog. La última vez fue en el tutorial de Iron, que os recomiendo ver si os interesa el tema del desarrollo web backend.

    Hoy vamos a hablar de Piston. Piston es una de las librerías más antiguas del ecosistema Rust. Surgida cuando todavía no existía Cargo, esta librería está pensada para el desarrollo de juegos. No es la única que existe en Rust pero sí la más conocida. Piston es una librería que te enseñará Rust de la mejor forma. Y ahora quiero disculparme, porque Piston no es una librería, son un montón, pero eso lo veremos enseguida. En primer lugar creamos un proyecto nuevo con Cargo.

    cargo new --bin ejemplo_piston
    cd ejemplo_piston

    Ahora abrimos el archivo Cargo.toml, vamos a añadir las dependencias necesarias. Las dependencias en Piston son un poco complicadas, veamos:

    • Existen las dependencias core, implementan la API fundamental pero no pueden usarse por separado, son window, input y event_loop. Se usan a través de piston.
    • Los backends de window, existen actualmente 3 backends: glutin, glfw, sdl2. Se importan manualmente.
    • Graphics, una API 2D, no presente en core, pero al igual que las dependencias core necesita un backend.
    • Los backends de graphics son varios: opengl, gfx y glium.
    • Existe una dependencia que nos deja todo montado, piston_window. Esta trae por defecto el core de Piston, glutin, graphics y gfx.
    • Luego existen dependencias extra, como por ejemplo para cargar texturas, estas las podremos ir añadiendo según las necesite el proyecto.

    Para simplificar añadimos piston_window únicamente:

     

    [package]
    name = "piston_example"
    version = "0.1.0"
    authors = ["Adrián Arroyo Calle"]
    
    [dependencies]
    piston_window = "0.59.0"
    

     

    Ahora abrimos el archivo main.rs. Añadimos la crate de piston_window y los módulos que vamos a usar.

    extern crate piston_window;
    
    use piston_window::*;
    use std::path::Path;
    

     

    Así mismo definimos un par de cosas para el resto del programa, la versión de OpenGL que usará Piston internamente y una estructura para guardar los movimientos de teclado.

    const OPENGL: OpenGL = OpenGL::V3_1;
    
    struct Movement{
        up: bool,
        down: bool,
        left: bool,
        right: bool
    }
    

     

    En la función main podemos crear la ventana, especificando título y tamaño. Más opciones como V-Sync, pantalla completa y demás también están disponibles.

    fn main() {
    
        let mut window: PistonWindow = WindowSettings::new("Piston - Adrianistan",[640,480])
            .exit_on_esc(true)
            .opengl(OPENGL)
            .build()
            .unwrap();
    

     

    Ahora cargamos la tipografía Sinkin Sans, que vamos a usar para dibujar texto en pantalla. Como hay dos posibles localizaciones comprobamos esos dos lugares antes de salir del programa si no se consigue cargar la fuente.

        let mut glyphs = Glyphs::new(Path::new("SinkinSans.ttf"),window.factory.clone()).unwrap_or_else(|_|{
            let glyphs = Glyphs::new(Path::new("target/debug/SinkinSans.ttf"),window.factory.clone()).unwrap_or_else(|_|{
                panic!("Failed to open the font file. Check that SinkinSans.tff is in the folder");
            });
            glyphs
        });
    

     

    Inicializamos la estructura de movimientos, generamos las dimensiones iniciales del rectángulo (que será un cuadrado en este caso), su color y la posición del ratón.

        let mut mov = Movement{
            up: false,
            down: false,
            left: false,
            right: false
        };
    
        let mut dims = rectangle::square(50.0,50.0,100.0);
        let mut rect_color = color::BLACK;
    
        let mut mc: [f64; 2] = [0.0,0.0];
    

     

    Ahora viene la parte importante, el bucle de eventos. El bucle va a funcionar infinitamente generando eventos por el camino (pueden ser eventos de inactividad también). Usamos la función draw_2d para dibujar en 2D. Hay dos maneras de dibujar un rectángulo, en primer lugar tenemos la forma abreviada y en segundo lugar una más completa que permite más opciones. Por último dibujamos el texto usando la fuente y realizando una transformación para que no quede el texto en la posición 0,0.

     while let Some(e) = window.next() {
            window.draw_2d(&e, |c, g| {
                clear([0.5, 0.5, 0.5, 1.0], g);
                rectangle([1.0, 0.0, 0.0, 1.0], // color rojo, rgba
                            [0.0, 0.0, 100.0, 100.0], // dimensiones
                            c.transform, g); // transormacion y donde se va a dibujar
    
                let rect = Rectangle::new(rect_color);
                rect.draw(dims,&c.draw_state,c.transform,g);
                text(color::BLACK,18,"¡Saludos desde Piston!",&mut glyphs,c.transform.trans(100.0,200.0),g); // aplicamos una transormacion, movemos las X 100 y las Y 200
            });
    

     

    A continuación vamos a tratar cada evento de forma independiente, como todos los métodos devuelven Option, hemos de usar esta sintaxis con Some. En primer lugar tenemos un UpdateEvent, que básicamente nos informa del tiempo delta transcurrido. Recomiendo usar este evento para realizar los cambios en las geometrías, en este caso para mover el rectángulo.

    if let Some(upd_args) = e.update_args() {
                let dt = upd_args.dt;
                
                    if mov.right {
                        dims[0] += dt*100.0;
                    }
                    if mov.left {
                        dims[0] -= dt*100.0;
                    }
                    if mov.up {
                        dims[1] -= dt*100.0;
                    }
                    if mov.down {
                        dims[1] += dt*100.0;
                    }
            }
    

    Los siguientes dos eventos son opuestos, uno se activa cuando pulsamos una tecla y el otro cuando la soltamos. Comprobamos la tecla y modificamos la estructura movement en consecuencia.

    if let Some(Button::Keyboard(key)) = e.press_args() {
                if key == Key::W {
                    mov.up = true;
                }
                if key == Key::S {
                    mov.down = true;
                }
                if key == Key::A {
                    mov.left = true;
                }
                if key == Key::D {
                    mov.right = true;
                }
            };
            if let Some(Button::Keyboard(key)) = e.release_args() {
                if key == Key::W {
                    mov.up = false;
                }
                if key == Key::S {
                    mov.down = false;
                }
                if key == Key::A {
                    mov.left = false;
                }
                if key == Key::D {
                    mov.right = false;
                }
            };
    

    Por último, si queremos comprobar clicks del ratón hacemos algo similar. He añadido código para que cambio el color del rectángulo si pulsamos sobre él.

    if let Some(Button::Mouse(mb)) = e.release_args() {
                if mb == MouseButton::Left {
                    let x = mc[0];
                    let y = mc[1];
                    if x > dims[0] && x < dims[0] + dims[2] { if y > dims[1] && y < dims[1] + dims[3] {
                            rect_color = if rect_color == [1.0,0.0,0.0,0.7]{
                                [0.0,1.0,0.0,0.7]
                            } else if rect_color == [0.0,1.0,0.0,0.7] {
                                [0.0,0.0,1.0,0.7]
                            } else{
                                [1.0,0.0,0.0,0.7]
                            }
                        }
                    }
                    
                }
            }
    

    A continuación un pequeño evento que guarda la última posición del ratón.

            if let Some(mouse_cursor) = e.mouse_cursor_args() {
                mc = mouse_cursor;
            }
        }
    }
    

     

    Y con esto ya tenemos hecho un ejemplo en Piston.

    Si quieres tener un ejecutable para Windows sin que se muestre primero la consola debes compilar la versión que vas a distribuir con unos parámetros especiales. Si usas Rust con GCC usarás:

    cargo rustc --release -- -Clink-args="-Wl,--subsystem,windows"

    Si por el contrario usas Visual C++:

    cargo rustc --release -- -Clink-args="/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup"

     

    Piston todavía se encuentra en fuerte desarrollo, en la API estan documentados todos los métodos pero aun así muchas veces no se sabe como hacer ciertas cosas. Piston soporta además 3D, contando con una librería especializada en vóxels. Veremos como evoluciona esta librería.

    La entrada Tutorial de Piston, programa juegos en Rust aparece primero en Blog - Adrianistan.eu.

    Miércoles 11 de enero de 2017

    Pedro L. Lucas

    Pedro L. Lucas
    Cartas de Linux

    Creando un archivo que se puede leer desde Linux pero no desde Windows

    Hace poco, por accidente, creé una archivo que se podía manejar desde Linux, pero Windows no podía con él. La cuestión es bastante sencilla:

    Windows usá los dos puntos “:”, para identificar unidades, como por ejemplo, C:, D:, G:,… Por lo tanto el símbolo : no debería usarse en Windows para poner nombres a ficheros.

    En mi caso en el nombre del fichero había puesto una hora en el formato: “20:30:00”. Claro, el separador era “:”.

    Al llegar a Windows, me encontré que el navegador de ficheros lo listaba pero no lo podía abrir. Daba igual la aplicación que intentase usar. Para colmo el mismo error se producía si intentaba renombrar el archivo desde Windows.

    ¿La solución? En mi caso me fue más sencillo volver a Linux y cambiar el nombre del archivo.


    Domingo 08 de enero de 2017

    David Moreno

    David Moreno
    dm's blog

    Thanks Debian

    I sent this email to debian-private a few days ago, on the 10th anniversary of my Debian account creation:

    Date: Fri, 14 Aug 2015 19:37:20 +0200
    From: David Moreno 
    To: debian-private@lists.debian.org
    Subject: Retiring from Debian
    User-Agent: Mutt/1.5.23 (2014-03-12)
    
    [-- PGP output follows (current time: Sun 23 Aug 2015 06:18:36 PM CEST) --]
    gpg: Signature made Fri 14 Aug 2015 07:37:20 PM CEST using RSA key ID 4DADEC2F
    gpg: Good signature from "David Moreno "
    gpg:                 aka "David Moreno "
    gpg:                 aka "David Moreno (1984-08-08) "
    [-- End of PGP output --]
    
    [-- The following data is signed --]
    
    Hi,
    
    Ten years ago today (2005-08-14) my account was created:
    
    https://nm.debian.org/public/person/damog
    
    Today, I don't feel like Debian represents me and neither do I represent the
    project anymore.
    
    I had tried over the last couple of years to retake my involvement but lack of
    motivation and time always got on the way, so the right thing to do for me is
    to officially retire and gtfo.
    
    I certainly learned a bunch from dozens of Debian people over these many years,
    and I'm nothing but grateful with all of them; I will for sure carry the project
    close to my heart — as I carry it with the Debian swirl I still have tattooed
    on my back ;)
    
    http://damog.net/blog/2005/06/29/debian-tattoo/
    
    I have three packages left that have not been updated in forever and you can
    consider orphaned now: gcolor2, libperl6-say-perl and libxml-treepp-perl.
    
    With all best wishes,
    David Moreno.
    http://damog.net/
    
    
    [-- End of signed data --]
    

    I received a couple of questions about my decision here. I basically don’t feel like Debian represents my interests and neither do I represent the project – this doesn’t mean I don’t believe in free software, to the contrary. I think some of the best software advancements we’ve made as society are thanks to it. I don’t necessarily believe on how the project has evolved itself, whether that has been the right way, to regain relevancy and dominance, and if it’s remained primarily a way to feed dogmatism versus pragmatism. This is the perfect example of a tragic consequence. I was very happy to learn that the current Debian Conference being held in Germany got the highest attendance ever, hopefully that can be utilized in a significant and useful way.

    Regardless, my contributions to Debian were never noteworthy so it’s also not that big of a deal. I just need to close cycles myself and move forward, and the ten year anniversary looked like a significant mark for that.

    Poke me in case you wanna discuss some more. I’ll always be happy to. Specially over beer :)

    Peace.

    Miércoles 21 de diciembre de 2016

    Juanjo Amor

    Juanjo Amor
    DrAmor's Blog

    Acabemos con los intersticiales

    ¡Interstitials!

    Vaya palabro. “Interstitials”. Intersticiales en español. Anuncios intersticiales; que para la RAE serían aquellos que ocupan los intersticios, pero que, realmente, son anuncios que ocupan toda la pantalla y son especialmente molestos porque,

    • Impiden visualizar la página que queremos ver. Vamos, que molestan, y mucho más, que los pop-ups de toda la vida.
    • Incitan al click fraudulento: La mayor parte de las veces que pulsamos sobre el anuncio, no es para acceder al producto anunciado sino para cerrar el mismo. El botón para cancelarlo suele requerir de una especial destreza (o puntería) del usuario sobre su pantalla multitáctil… a menos que tengas los dedos del tamaño de la cabeza de un alfiler.

    Anuncio Intersticial, imagen de Google

    Pues bien, hace ahora más de 4 meses, Google anunció que iba a penalizar el uso de anuncios intersticiales en las búsquedas desde móvil a partir de enero de 2017, algo que ya está a la vuelta de la esquina.

    Es bueno recordarlo porque, a día de hoy, la mayor parte de las páginas de actualidad en Internet siguen incorporando este tipo de anuncios como si nada, haciendo muy incómoda la lectura, sobre todo en móviles, donde deshacerse del anuncio resulta complicado y por lo que, muchas veces, un servidor decide abandonar el medio de comunicación elegido para irme a uno alternativo que me informe más y me moleste menos.

    Aún me queda la esperanza de que esta penalización del buscador realmente consiga su efecto. Mientras tanto, seguiremos haciendo uso extensivo y abusivo de los bloqueadores de anuncios, pese a los avisos de determinados medios de que eso les hace daño.

    Lunes 05 de diciembre de 2016

    Emiliano A. González Salgado

    Emiliano A. González Salgado
    El blog de Emi

    Error al inicio de Linux debido a CUPS

    Uso Fedora 25 KDE. Desde hace tiempo y, con varias versiones anteriores. se está produciendo el mismo fallo al inicio del sistema.

    Para ver los errores que se han producido en el inicio de sesión, en los sistemas que incorporan Systemd, hay que teclear el comando:

    [root@HOST-PC ~]# journalctl -b -p err

    Uno de los que estaba arrojando últimamente era:
    cupsd[1213]: Missing value on line 11 of /var/cache/cups/job.cache.

    Los números 1213 y 11 pueden variar. El primero debe ser un índice de Journal (el registro de logs de Systemd) y el segundo hace referencia a la línea del fichero job.cache que produce el fallo.

    Es este caso era debido a que cups-pdf (la impresora virtual) al crear un fichero no le asignó un nombre en el archivo job.cache.

    Intenté borrar la caché de Cups desde el administrador de impresión (system-config-printer), pero no se encontraban trabajos pendientes ni terminados. También desde la interfaz web del servidor cups: http://localhost:631/jobs?which_jobs=all

    No era posible. No se podía borrar. Incluso eliminé el contenido de  job.cachecon un editor de texto, pero al volver a iniciarse el contenido estaba otra presente, así como el error se reproducía.

    Al final la solución llegó a través de la consola.

    Los comandos a ejecutar son:

    Parar Cups:

    [root@HOST-PC ~]# systemctl stop cups.service

    Ver la lista de trabajos completados:

    [root@HOST-PC ~]# lpstat -W completed -o

    Ver la lista de trabajos no completados:

    [root@HOST-PC ~]# lpstat -o

    Eliminar todos los trabajos:

    [root@HOST-PC ~]# cancel -a -x

    Esto cancelará todos los trabajos.

    Editar el fichero  /var/cache/cups/job.cache, borrar el contenido y guardar de nuevo.

    por ejemplo con nano como root

    [root@HOST-PC ~]# nano /var/cache/cups/job.cache

    Reiniciar el sistema y ver si se ha solucionado el fallo.

    SI las respuestas dadas aquí no funcionan:

    ps aux | grep printer kill {printer job}

    Este último comando no lo he probado. con lo anterior fue suficiente.

    Un saludo,

    Emiliano

     


    Jueves 01 de diciembre de 2016

    Luis Vilchez

    Luis Vilchez
    El blog de Jabba

    Pillars of Eternity, el heredero espiritual de Baldur's Gate para OSX y Linux

    Hablar de Baldur’s Gate es hablar del gran clásico entre los clásicos de los juegos de rol computerizado. Su legado y su influencia están muy presentes en gran cantidad de los títulos que conforman el panorama del videojuego actual. Un juego con una profundidad, libertad y capacidad de personalización nunca vistas hasta entonces. Un juego que muchos tenemos como uno de los mejores -sino el mejor- RPG de la historia.


    Quince años después Pillars of Eternity pretende devolvernos la magia, la ambientación, la jugabilidad y esa aura cautivadora y mítica propia de los grandes clásicos del género; un deleite para los sentidos de los veteranos en los juegos de rol y una experiencia inigualable para los recién llegados. Me han bastado unas semanas perdiéndome virtualmente por el mundo de Eora para confirmar que Pillars of Eternity es la oportunidad de volver a revivir un JUEGAZO infinity engine de corte clásico como los de antaño. Un juego que rezuma a Baldur's Gate del bueno por los cuatro costados. ¿Y sabéis lo mejor? Con versiones nativas para OSX y... ¡Linux!

    Es de recibo decir que gran parte de la culpa de todo esto la tienen los fans y el modelo kickstarter que sus creadores usaron para financiar el proyecto (por aquel entonces bajo el nombre de Project Eternity). El resultado ha sido un RPG de corte occidental distribuido por Paradox Interactive y desarrollado por Obsidian Entertainment, creadores de sagas como Fallout, IceWind Dale o Neverwinter Nights, además del citado Baldur’s Gate.

    Como en Baldur's Gate, la primera cosa que hay que hacer en Pillars of Eternity es crear un personaje. Aspectos como las diferentes ventajas e inconvenientes de cada raza, los atributos, las clases, las limitaciones de atributo por clase, las alineaciones morales, las habilidades complementarias, afinidad de armas, selección de conjuros, clases duales... habrá que tenerlos muy en cuenta antes incluso de comenzar la "aventura". Y seguramente no es el sistema de creación de personajes más amplio de la historia del género, pero sí es MUY completo. Incluso me atrevo a decir que podrá parecer algo complejo para los recién llegados pero hará las delicias de los veteranos del género. A fin de cuentas aprender forma parte de la esencia del rol y eso pasa por cosas como la creación de nuestro personaje. A continuación os dejo un vídeo para que lo veáis en acción.


    En otras plataformas no sé, pero en Linux sin duda estamos ante el juego del año :)

    Miércoles 30 de noviembre de 2016

    Raúl González Duque

    Raúl González Duque
    Linux – Mundo Geek

    Cómo crear un pendrive USB bootable con Ubuntu en Windows

    Tener un USB con Ubuntu siempre listo en el bolsillo puede ser muy útil para solucionar problemas con Windows, eliminar virus, realizar operaciones seguras en Internet, o simplemente para jugar un poco con Linux.

    Para crear una unidad USB arrancable con Ubuntu me gusta utilizar Rufus, que es gratuita, muy ligera, rápida y cuenta con versión portable. Además de Rufus, sólo necesitaremos una ISO de Ubuntu y un pincho USB con al menos 2GB de espacio, que debe estar vacío, o no importarte mucho su contenido, porque se formateará durante el proceso.

    Conecta el pincho USB a tu equipo y ejecuta Rufus.

    En “Dispositivo” selecciona tu pincho USB.

    Marca la opción “Crear disco de arranque con:”, selecciona “Imagen ISO”, y haz clic sobre el icono del CD Rom para abrir un diálogo en el que buscar la imagen ISO que has descargado

    USB booteable Ubuntu

    Pulsa el botón “Empezar”. Te avisará de que necesita descargar un par de archivos de Internet, pulsa en “Sí”.

    Cuando te pregunte por el modo de escritura de la imagen, selecciona “Escribir en modo Imagen ISO (Recomendado)”.

    A continuación te avisará de que va a proceder a formatear el dispositivo USB. Haz clic en “Aceptar” para empezar el proceso.

    Martes 08 de noviembre de 2016

    Raúl González Duque

    Raúl González Duque
    Linux – Mundo Geek

    ¿Cuántos usuarios de Linux se necesitan para cambiar una bombilla?

    Sea merecida o no, lo cierto es que los usuarios y desarrolladores de GNU/Linux tenemos fama de arrogantes, extremistas y de perdernos en los detalles. Desde el Proyecto GNU se toman con humor estos estereotipos calculando cuántos usuarios de Linux se necesitarían para cambiar una bombilla.

    • 1 para publicar un hilo en la lista de correo informando de que la bombilla se ha fundido
    • 1 para sugerir reiniciar la bombilla usando la línea de comandos
    • 1 para quejarse de que el usuario rompiera la bombilla
    • 1 para preguntar qué bombilla se debería instalar
    • 1 para aconsejar que no se use la palabra “fundida” para referirse a una bombilla rota, porque puede interpretarse que la bombilla se ha prendido fuego, en lugar de haberse estropeado por un exceso de corriente eléctrica
    • 25 para sugerir todos los tipos de bombilla imaginables
    • 5 para para decir que la bombilla fundida es un fallo de origen
    • 1 novato para sugerir instalar una bombilla de Microsoft
    • 250 usuarios para inundar el correo del susodicho novato
    • 300 para decir que la bombilla de Microsoft se pondría azul y tendrías que reiniciarla constantemente para que volviera a funcionar
    • 1 antiguo usuario de GNU/Linux, que todavía frecuenta el foro, para sugerir una iBombilla de Apple, que tiene un diseño fresco e innovador y sólo cuesta 250$
    • 20 para decir que las iBombillas no son libres, y que tienen muchas menos funcionalidades que una bombilla estándar 20 veces más barata
    • 15 para sugerir una bombilla nacional
    • 30 para decir que las bombillas nacionales son copias de las bombillas extranjeras y que no ofrecen nada nuevo
    • 23 para discutir si la bombilla debe ser blanca o transparente
    • 1 para recordar a todo el mundo que el nombre correcto es GNU/Bombilla
    • 1 para decir que las bombillas son sólo para usuarios de Window$ y los usuarios de GNU/Linux de verdad no tienen miedo a la oscuridad
    • 1 para anunciar finalmente el modelo de la bombilla elegida
    • 217 para descartar el modelo escogido y sugerir otro
    • 6 para quejarse de que el modelo elegido tiene elementos propietarios, y que debería usarse otro
    • 20 para decir que una bombilla 100% libre sería incompatible con el interruptor
    • Los mismos 6 anteriores para sugerir cambiar el interruptor por uno compatible
    • 1 para chillar “¡DEJAD DE DISCUTIR Y CAMBIAR LA P*#@!%¡# BOMBILLA DE UNA VEZ, POR EL AMOR DE DIOS!”
    • 350 para preguntar al usuario anterior a qué Dios se refiere, y si tiene pruebas empíricas de su existencia
    • 1 para explicar cómo funciona la electricidad y por qué una bombilla eléctrica es ineficiente
    • 1 para decir que no se puede confiar en una bombilla fabricada por una corporación y que deberíamos confiar en bombillas hechas por la comunidad
    • 1 para publicar un enlace a un archivo ODF explicando cómo construir una bombilla desde cero
    • 14 para quejarse del formato del archivo anterior, pidiendo que se envíe en txt o LaTeX
    • 5 para decir que no les gustó la decisión y van a hacer forks de la instalación eléctrica de la casa para instalar una lámpara mejor
    • 1 para publicar una serie de comandos a introducir para cambiar la bombilla
    • 1 para comentar que ejecutó los comandos y obtuvo un mensaje de error
    • 1 para aconsejar que los comandos deberían ejecutarse como root

    Y finalmente:

    • El padre del usuario original, que mientras todos estaban discutiendo, se acercó a la tienda y compró la bombilla más barata que vendían

    Lunes 07 de noviembre de 2016

    Raúl González Duque

    Raúl González Duque
    Linux – Mundo Geek

    Los 10 comandos más útiles de Linux

    CommandlineFu es una web donde los usuarios pueden enviar sus comandos Linux favoritos, añadir comentarios, y votar los comandos enviados por otros usuarios; un recurso imprescindible si queréis convertiros en verdaderos expertos en el uso de la consola. Y para muestra, un botón: estos son los 10 comandos más votados por sus usuarios.

    sudo !!

    Ejecuta el último comando introducido como root.

    python -m SimpleHTTPServer

    Inicia un servidor web que sirve los archivos del directorio actual en http://localhost:8000

    ^foo^bar

    Ejecuta el último comando, reemplazando el texto “foo” por “bar”

    Ctrl + X, Ctrl E

    Invoca un editor de textos en el que poder escribir el comando que vamos a ejecutar. El comando se ejecutará una vez se cierre el editor

    Alt + .

    Inserta el último argumento utilizado en el punto en que esté situado el cursor

    reset

    Resetea la consola

    mount | column -t

    Muestra los puntos de montaje actuales con un formato amigable para la lectura

    echo “ls -l” | at midnight

    Ejecuta un comando en el momento indicado

    curl ip.appspot.com

    Descarga el documento de http://ip.appspot.com para mostrar la IP externa del equipo

    man ascii

    Muestra la página de ayuda con la tabla de caracteres ASCII

    Domingo 30 de octubre de 2016

    Marcelo Fortino

    Marcelo Fortino
    Fortinux

    Tutorial usar git-annex para sincronizar archivos entre dispositivos GNU/Linux

    Tutorial usar git-annex como repositorio de archivos Una forma de tener nuestros archivos sincronizados entre el notebook, desktop y otros dispositivos es usar como herramienta git-annex. Git-annex gestiona archivos con Git sin verificar el contenido de los mismos. Esto permite trabajar con archivos grandes usando repositorios sincronizados.

    Martes 18 de octubre de 2016

    わき毛の抜毛には女性の大きな関心事だ。幾ら素敵な装い

    わき毛の抜毛にはマミーの大きな関心事だ。
    幾ら素敵な装いをし立としても、傍らのむだ毛が伸びていたら、ガッカリですね。
    好感触に感じていた輩も瞬く間にきらいになってしまうかも知れません。
    薄着の季節では余計に傍ら後が開いた洋服が多くなりますし、自分で処理をすると皮膚が炎症を起こしたりして余計な不便まで秘める片付けになります。
    抜毛店舗実践のお値段ですが、いつの抜毛店舗かで予算は違ってきますし、希望の抜毛要素次第で移り変わるでしょう。
    大手の抜毛店舗でよく言えるようなお得なキャンペーンの利用によって、案外低料金の抜毛が可能になる場合もあるでしょう。
    またワキや拳固など抜毛ニーズ部位ごとに通うお店を取りかえる、つまり抜毛要素それぞれでちがう抜毛店舗に通うようにするといった華奢に抜毛が進められそうです。
    また一つのお店だけを利用するのに比べてリザーブを格段に取り去り易く罹るのもうれしい部分だ。
    経済的に無理なく抜毛しようと、最初から抜毛器で自己処理やる分と抜毛店舗に任せるパイと、区別してある輩もある。
    適性もありますが、自家用の抜毛器を上手に使えば、各回、抜毛のために抜毛店舗を予約しなくてもすむでしょう。
    厳しい部分は抜毛店舗で施術してもらい、そのほかの部分は抜毛器で自己処理やる為す。
    但し抜毛器もそれなりの性能のものでないとその抜毛器による店だけムダ毛余りしてしまう結果、購入前のプレ認証は不可欠です。
    カラダ抜毛をしたら、ムダ毛のお手伝いを自分でするわずらわしさから解放され、処置がヤバイ楽になる事は確実です。
    但し、お金が幾らくらい陥るのか、ムダ毛はどのくらいきれいになるのか事前に調べておきましょう。
    カラダ脱毛するお店や店舗にて、抜毛作用やそのために加わる費用が非常に違ってきます。
    むだ毛の抜毛の手当て方法の中で、ニードル法は無限抜毛作用が最も期待できる抜毛法だと思われます。
    今は病院です抜毛病舎や一部の抜毛店舗でしか行われていない抜毛法だ。
    著しい痛みがあるので、興味はレーザー抜毛の方が高いようですが、大きい効果が期待できる結果、この方法をわざと選ぶ人も少なくないようです。
    間違って認識してる輩もいるようですが、店舗をめぐってもツルッパゲスキンになるまで、一度や二都度の手入れで抜毛が完了し立とは言えません。
    抜毛を受ける要素にても変りますが、おおまかに言って、6回から18回ほど抜毛を受ける人が多いようです。
    ですが、スキンへの恐怖によって、手入れを受けた数日後にまた抜毛が行なえる所以ではなく、頭髪回転の階級が二ヵ月なので、それくらいのスパンを空けて伺うのが最適です。
    ただただ「抜毛」と言ってもこのように長期戦になる結果、売店が多いなどで利用しやすい店舗で行ないましょう。
    できるだけ抜毛代金を安く終えるために、破格値の抜毛店舗を探している輩は少なくないです。
    ただし激安予算ばかりが売りの抜毛店舗は無事故や浄化をおろそかにしているかも知れません。
    低価格なパイ、普通の回数ではほとんど効果が出ないとか、スキンを傷める結果になっては給与も損害ですが、かけた日数ってスキンは戻って来ないでしょう。
    スキンを傷めたらムダ毛手当ては当分できません。
    予算の低廉さばかりを代物にする抜毛店舗の場合はあらかじめ評価や手答えをチェックしておいた方がいいでしょう。
    きれいに脱毛するには少々抜毛店舗に通うことになりますから、自分に当てはまるリザーブ切り口があるか確認してから契約するべきです。
    立とえばリザーブ切り口が連絡のみの抜毛店舗だと忙しさにかまけているとリザーブ電話をかけるのが後回しになりがちだ。
    リザーブがタブレットから叶う抜毛店舗だったら、単なる合間に予約できるので、心づもりをずらす必要がありません。
    綺麗に抜毛しようと思ったら、抜毛店舗に何度となく乗り物を運ばなければなりませんから、手入れのリザーブが取り易いかどうかは店舗選びの重大要素のひとつです。

    Lunes 17 de octubre de 2016

    家屋でのムダ毛加工はヘビーな操作だ。剃ろうにもビデオラ

    住宅でのムダ毛作製はヘビーな工程だ。
    剃ろうにも映像路線や背中は上手くできなかったり、毎日ムダ毛のお手入れをするのは煩わしくて疲れたり、問題に感じている方もいるのではないでしょうか。
    抜け毛店舗を利用すれば、たえず苦労しているフィールドの抜け毛も平安、自宅での作製のもめごとも気にしなくてよくなります。
    体内抜け毛店舗はたくさんありますが、抜け毛で失敗し立と感じないためには、じっさいに体内抜け毛を先輩のクチコミを聞いてみるのが一番良いでしょう。
    感想は自身によるの部分はありますが、誰もがいいという店舗は粗方決まってくる。
    重要視するのは出来ばえや早さですとか、やはり短いのが有難いとか、自分が抜け毛でやはり重視する主題を決めておくってきっと納得できるはずです。
    妊婦様であれば、多くの抜け毛店舗ではメンテナンスを行ないません。
    懐妊内輪はホルモンの不調でメンテナンスを通じても抜け毛の効力が出にくかったり、神経質になっているスキンは、少しのモチベーションも荒れてしまうからだ。
    抜け毛が完了していないうちに懐妊のリサーチが出てきたら、店舗によっては産後2ヶ月ぐらいまで休会ができる店舗もあるので申込む前にそぐういう通り道や制度を確認しましょう。
    抜け毛料金がサラリー制のところもありますから、一通りの抜け毛承認までに総額が予見できずに困ってしまっ立という自身も要るかも知れません。
    体内抜け毛総額確認の際には、抜け毛フィールドといった抜け毛承認までに陥る値段を比べて、メンテナンスのアポイントメントを入れ易い店舗を選ぶことも重要なのです。
    どんどん一度の抜け毛で全てのパートを施術して得る店舗ならひときわ容易でしょう。
    指のムダ毛は凄く自身には映るものです。
    他人のしかたを見ればわかりますが、例えネイルやかざりで盛装していても、指頭髪があるという冴えない自身認定されてしまう。
    指のお手入れの基本としてムダ毛作製を抜け毛店舗で講じる側は以前からすごく多いのです。
    しかたや指のように表皮の無い部分は考えも素晴らしいので、抜け毛手法は事前にぐっすり検討したほうがよいでしょう。
    見立て抜け毛は効力が持続するかわりに痛みを伴うので、低モチベーションの光線抜け毛様式を施術するのが一般的なようです。
    出向ける場所に一種しか仕事場がない場合はレンジがありませんが、仕事場が沢山あれば、各仕事場の詳細などを比較してから、抜け毛店舗を選択するという良いでしょう。
    では、効力、総額、アポイントメントの取り方、姿勢行為などをサイトなどの人づてなどを見て確認しなければならないことが山ほどあります。
    いくつか選択をサイトなどで通り道や人づてにおいて選んでから必ず、自分自身に合っているのか、事実通り道にあたって判断しましょう。
    ニードル抜け毛は何かと障害が多いと言います。
    最近のレギュラーな抜け毛法ではないのでほとんど知られていない手法なのかもしれませんが、ニードル抜け毛にはひどくの痛みがあるのです。
    もう一度、毛孔の全てに針をより刺していくのです極の時間がかかります。
    痛みがある上に長時間のメンテナンスが必須となるって、それなりに障害も多くなってくるのだと思います。
    華奢ゾーンの抜け毛を抜け毛店舗ですると、キレイな出来ばえだったし、肌荒れが起きにくいといわれています。
    ただし、抜け毛店舗の全てがVIO抜け毛が出来ない場合もあるのでウェブサイトなどで確認してから行きましょう。
    華奢ゾーンの抜け毛は気まずいという方も、よくいますが、同性それぞれですし、ベテランが行なうほうが自分で行うからセキュリティだ。

    Domingo 16 de octubre de 2016

    Marcelo Fortino

    Marcelo Fortino
    Fortinux

    Tutorial instalar Plone CMS en Ubuntu server

    En este tutorial veremos como podemos instalar el gestor de contenidos Plone en un servidor Ubuntu 14.04 o 16.04. Plone es un gestor de contenidos basado en el servidor de aplicaciones Zope que es bastante utilizado como Intranet en gobiernos y empresas, entre ellos, el gobierno brasileño, la universidad de Oxford (Reino Unido) o Google.

    仮に代価に余裕があるなら、その代価で抜毛ショップの加療

    もしも財貨に余裕があるなら、その財貨で抜け毛店先の施術費用を払って仕舞うのもありです。
    資金で支払うのですから、あとでカードの支払いお日様も気になりません。
    ただし、仮に資金が手もとにあって高額な先払いをしてしまうと、途中で通えない原因ができ立ときは空白分の精算が必要になります。
    それに、抜け毛店先そのものが潰れたら、先払いしてあった分だけ損をすることになります。
    少額だったり、そのつど払う場合は資金支払いも良いですが、そこそこの金額に繋がるようならカード支払いをお薦めします。
    月々定額(月収制)の抜け毛店先の場合、清算が明確なので気軽に抜け毛できるのでお薦めです。
    とはいえ体の一端しか抜け毛したくないときは、月収制を選ぶというかえってロスかも知れません。
    発毛周期を見ながら脱毛するので、もし1ポイントだけなら隔月に一度の抜け毛になるからだ。
    そのかわり、思いポイントが多いほど月収制による有難みがあるといえるだと言えます。
    ご自身の場合はどうしたいかを明確にして、ピッタリ合う抜け毛店先によるっていいだと言えます。
    「ムダ毛の憂慮」で多くの人が走り込む抜け毛スパのランキングには、大御所エステティックサロンのTBC、エルセーヌなどのエースがデイリー、上位に食い込んでいらっしゃる。
    これとは別に、抜け毛店先をこういうランキングに含めたタイミング、たとえば、ミュゼプラチナム、シースリー(C3)、抜け毛研究所、等々が上の順番に名称を連ねます。
    人気といえば、ピュウベッロやキレイモなどもあります。
    その中には、要望する抜け毛フィールドを通じてもくろみごとに分けて向かう方もいらっしゃる。
    何とか抜け毛スパに通うとすると、気にならなくなるまで脱毛するなら12回等前文向かう必要があるようです。
    気になるフィールドが上腕や脚等、他とくらべて分厚く無いポイントであるならば、5、6回の施術で感動する方もあるだと言えます。
    ただし、横やアンダーヘア等の眼たつ濃い毛が生えてしまってあるところは、ベイビー(ベイビーが生まれるまでは乳幼児好きじゃなかった方も、自分の乳幼児が産まれてみると、ベイビーがかわいくて仕方がないということがよくあるみたいです)のお肌の様なツルッとしたお肌にしようとすると、上腕や脚等の二ダブルは施術回数が必要になるケースと思います。
    皮膚がデリケートであるヤツですと剃刀負債が発生することがあるだと言えます。
    そういう人におすすめしたいのが抜け毛店先における灯抜け毛だ。
    これならば、アトピー風習の人も安全に施術をうけることが出来る為す。
    横の抜け毛に耐えるのだったら、ぜひ試してちょうだい。
    駅前駅近で目にする行いの多い抜け毛店先ですが、ムダ毛と呼ばれる体の邪魔な毛に、美専用の電気道具などを使用し、ムダ毛が出現するチェーンを遅らせたり、発毛しないように治療をするおみせのことです。
    以前は抜け毛製作というとエステでするというのが一般的なスタンスでしたが、抜け毛にもハイテクノロジーが普及した現在では短時間で効率的に抜け毛できるようになった事で抜け毛というサービスに限定して商売始めるサロンの飛躍的な繁殖につながったりゆうだ。
    ほとんどの女性がムダ毛製作を考え始めるのは温暖な春から初夏程だ。
    皮膚が周囲にふれる機会が多くなりますし、歩き、上腕のムダ毛だけでなく横などもプロフェショナルにきれいにしてもらいたいといった指し初めるのです。
    とくにいよいよ顧客はこの時期が多く、抜け毛店先が大混雑始めるぐらいですし、貸し賃は安くありません。
    貸し賃が短いのは、温度が薄くなり皮膚の登場がなくなる年代だと言えます。
    抜け毛だけでなく益々まとまりたいヤツはジェイエステティックが良いだと言えます。
    美顔、シェイプアップスパ、美貌脚も揃えたすべて美店先だ。
    一般の抜け毛店先みたい、灯方式の抜け毛を取り扱っています。
    格安で同店の美肌抜け毛を体験できるお試し教科も用意され、サロン単位の設定もスムーズなのがジェイエステティックのウリだ。
    サロンは全国に100サロン以上あり、思わぬところにおみせがあったり決める。
    もしも近くに支店があったら、キャリア教科などで様式を探るのもいいかも知れませんね。

    Lunes 29 de agosto de 2016

    David Moreno

    David Moreno
    dm's blog

    Webhook Setup with Facebook::Messenger::Bot

    The documentation for the Facebook Messenger API points out how to setup your initial bot webhook. I just committed a quick patch that would make it very easy to setup a quick script to get it done using the unreleased and still in progress Perl’s Facebook::Messenger::Bot:

    use Facebook::Messenger::Bot;
    
    use constant VERIFY_TOKEN => 'imsosecret';
    
    my $bot = Facebook::Messenger::Bot->new(); # no config specified!
    $bot->expect_verify_token( VERIFY_TOKEN );
    $bot->spin();
    

    This should get you sorted. What endpoint would that be, though? Well that depends on how you’re giving Facebook access to your Plack’s .psgi application.