El Token De Seguridad, Un Recurso Para Proteger Nuestras Cuenta

28/06/2017
Artículo original

A medida que han ido siendo más habituales todo tipo de transaccione online, tanto los servicios que las ofrecen como los usuarios que la utilizan muestran una mayor preocupación por reforzar la seguridad a acometer este tipo de operaciones. Buena prueba de ello es como la banc ha trabajado sin descanso por evitar el fraude que se comete a través d la suplantación de identidad con fórmulas como el sistema de pag Vini, con tarjetas virtuale y diversos métodos

Aunque la obsesión por la seguridad no es exclusiva de las entidade bancarias ya que hay miles de sites que dependen en gran medida de l confianza que ofrecen a sus usuarios. Por ello un servicio de token d seguridad puede ser un respaldo más que interesante para las persona que manejan passwords que protegen su información personal y su actividades

Un ejemplo de esto podría ser la sala de póker online PokerStars dond sus usuarios pueden disponer de un servicio opcional de token de seguridad para proteger su cuenta personal. En este caso la misma sala proporciona el token de autenticación a través de su Tienda VIP, algo que e habitual en estos dispositivos.

Este pequeño aparato electrónico puede presentar diferentes tipos, desde los token USB que almacenan claves criptográficas que pueden contene datos biométricos o firmas digitales, hasta un generador de contraseña dinámicas “OTP” (One Time Password) que generan una clave operativ durante un espacio limitado de tiempo para el ingreso a una cuent determinada. En el caso del mencionado token de seguridad de PokerStars cada vez que se pulsa el dispositivo, éste crea una clave que aparece e la pantalla durante solamente dos segundos y que permite el inicio d sesión en el software del usuario que tiene asignado el token

La contraseña del token es adicional al password usual que utiliza e usuario y cada vez que se pulsa el dispositivo genera una nueva clave caduca la anterior. Este método es conocido como autenticación en pasos al requerir usar Usuario > Password > Token, por lo que s alguien pretende suplantar la identidad y tener acceso a la cuenta además de hacerse con el password del usuario debería robar físicament el token

La parte negativa de estos dispositivos es que en el caso de robo pérdida el usuario se ve privado de la posibilidad de ingresar a s cuenta hasta llevar a cabo todo el protocolo establecido para esto casos con su proveedor del servicio, lo que puede resultar un desagradable molestia

Algunos sitios, principalmente bancos, ofrecen estos token de segurida a través de aplicaciones para móvil. Otro de los servicios que ofrece l posibilidad de un token de seguridad en el móvil es Google, por lo que través de iPhone, Blackberry o Android se puede reforzar la seguridad e las cuentas de Gmail, Google Reader, etc… Para ello debes activarlo través de tu cuenta de Google en est dirección, par posteriormente descargar Google Ahutenticator en tu Smartphone ingresar el código token que recibes.

Lo habitual es configurar la aplicación de modo que no nos solicite e código en el equipo que utilizamos normalmente, porque se puede hacer u bastante pesado lo de tener que ingresar el token cada vez que t logueas en tu cuenta

En resumen, los token de seguridad son una opción más a la hora d proteger nuestra información personal, aunque por otro lado tampoco s pueden considerar infalibles, de hecho la empresa RS Security dedicada a l criptografía y software de seguridad, reconoció en 2011 una intrusión e sus sistemas de seguridad que le obligó a sustituir muchos de su dispositivos

Sincronización de proyectos en git con hooks (ganchos)

28/06/2017
Artículo original

Sincronización de proyectos en git con hooks (ganchos)

Repositorio espejo (Mirror repo)

Problema

Hace unos días me encontré con un problema a resolver. Supongamos que tenemos dos repositorios en git, y queremos que todo lo que publicamos en uno se publique automáticamente en el otro, para mantenerlos sincronizados. Ésto es lo que se llama un repo espejo (mirror repos)

Repositorios a sincronizar

Supongamos que los repositorios se llaman repo1 y repo2. Pretendemos que repo2 esté sincronizado (sea un espejo) del repo1. Ésto significa que no tendremos que clonar en ningún momento el repo2. En local únicamente tendremos el repo1.

Solución

La respuesta, como es habitual, la encontré tras buscar un poco en stackoverflow. Gracias a Manoj Govindan

Añadir repo2 como remote

Dentro de repo1 añadiremos un nuevo remote que sea el repo2:

git remote add repo2 <url-repo2>

Configurar el hook (gancho) post-commit

Dentro del repositorio, crearemos un nuevo hook que se ejecute cada vez que hagamos un commit en repo1. Por cada commit, ejecutaremos un git push repo2, lo cual enviará los cambios al repo2.

# Crear el hook que se ejecutará en cada commit
mv .git/hooks/pre-commit.sample .git/hooks/post-commit
# Añadir el comando a ejecutar
echo -e "#!/bin/bash\n\ngit push repo2 -f --mirror" > .git/hooks/post-commit

En contenido del hook, para que se vea más claro es el siguiente:

#!/bin/bash

git push repo2 -f --mirror

Conclusión

Nota: Con este gancho, se mantendrán sincronizados ambos repositorios. Es necesario notar que tras hacer el commit del repo1, sigue siendo necesario ejecutar git push en repo1

Mantener sincronizada una única rama

Un problema similar podría ser mantener sincronizado en repo2 únicamente las ramas master. De forma que podamos crear tantas ramas como necesitemos en repo1 sin que se vean reflejadas en repo2. Para ello, en lugar de usar el hook post-commit, usaremos post-merge. Éste hook se ejecutará cada vez que se haga un git merge <rama distinta="distinta" de="de" master="master"> sobre master.

Para activarlo:

# Crear el hook que se ejecutará en cada commit
mv .git/hooks/pre-commit.sample .git/hooks/post-merge
# Añadir el comando a ejecutar
echo -e "#!/bin/bash\n\ngit push repo2 master:master" > .git/hooks/post-merge

El contenido del hook es:

#!/bin/bash

git push repo2 master:master

git push repo2 master:master podría leerse como: Publica en el repo2 en la rama master, el contenido de la rama master del repo actual

Referencias

Automatically mirror a git repository

Nueva Guía Gratuita: Java Concurrency Essentials

28/06/2017
Artículo original

{{ page.title }}

Concurrency is always a challenge for developers and writing concurrent programs can be extremely hard. There is a number of things that could potentially blow up and the complexity of systems rises considerably when concurrency is introduced. However, the ability to write robust concurrent programs is a great tool in a developer’s belt and can help build sophisticated, enterprise level applications.

In this course, you will dive into the magic of concurrency. You will be introduced to the fundamentals of concurrency and concurrent code and you will learn about concepts like atomicity, synchronization and thread safety. As you advance, the following lessons will deal with the tools you can leverage, such as the Fork/Join framework, the java.util.concurrent JDK package. To sum those up, you will learn about testing concurrent applications.

Descárgala

Visita la página Manuales gratuitos o consulta el catálogo completo.

Como Usar Los Filtros Smudge Y Clean en Git

28/06/2017
Artículo original

En el anterior artículo, hablamos sobre cómo sincronizar dos repositorios en git, también se vio algo de hooks.

Hoy vamos a ver cómo usar filtros en git para cambiar automáticamente la url de una web hecha con jekyll en función de si estamos en local o en el servidor. Es decir, cuando estemos desarrollando o escribiendo un artículo, querremos ir viendo los resultados en local, para ello la url del fichero _config.yml debe estar vacía, cuando esté en el servidor deberá ser el nombre del dominio.

Creando el script para smudge

Bastará con crear un script que contenga:

ruby -e '$stdout.puts $stdin.read.gsub(/url: http:\/\/elbauldelprogramador\.com/, "url: ")'

Lo llamaremos siteurl.smudge, y le daremos permisos de ejecución.

Creando el script para clean

Similar al anterior:

ruby -e '$stdout.puts $stdin.read.gsub(/url: /, "url: http:\/\/elbauldelprogramador\.com")'

Añadir los scripts a los filtros

Solo resta añadir los filtros a la configuración de git:

$ git config filter.siteurl.smudge siteurl.smudge
$ git config filter.siteurl.clean siteurl.clean

Nota: Los scripts tienen que estar en el PATH del sistema, y tener permisos de ejecucion. {: .notice}

El Gitattributes

Gracias al comentario de Julián, me dí cuenta de que faltaba una última cosa por especificar. A qué ficheros se aplicarán los filtros. Para ello, añadimos lo siguiente al fichero .gitattributes:

_config.yml filter=siteurl

Gracias Julián.

Conclusión

Ejecutados todos los pasos, ahora tendremos la url en local cuando estemos desarrollando, y se sustituirá automáticamente por el dominio cuando se publique en github.

Referencias

Cómo Crear Imagenes Con Un Marco Circular Al Estilo G+ en LaTeX

28/06/2017
Artículo original

En éste artículo vamos a ver algo curioso que aprendí hace poco. Con el paquete tikz de LaTeX.

Los que uséis G+ sabréis que las fotos de perfil aparecen encuadradas en un círculo, en lugar de un cuadrado. Rellenando mi Currículum se me ocurrió que podría insertar mi foto con ese mismo estilo.

Por supuesto, podría haber creado la imagen directamente con forma circular, pero ya que estoy usando una plantilla LaTeX para el Curriculum, me propuse buscar la manera de implementarlo.

Resulta que es bastante sencillo, el siguiente código conseguirá el efecto deseado:

\documentclass[border=5mm]{article}
\usepackage[skins]{tcolorbox}

\begin{document}

  \resizebox{256pt}{256pt}{
    \begin{tikzpicture}
      \node[circle,draw,inner sep=1cm,fill overzoom image=./pictures/image.jpg] (A) {};
    \end{tikzpicture}
  }

\end{document}

Donde:

  • image=./pictures/image.jpg es la ruta a la imagen.
  • \resizebox{256pt}{256pt} es el tamaño que queremos.
  • sep=1cm El borde de la imagen.

Tras compilar el código, el resultado es el siguiente:

Cómo Crear Imagenes Con Un Marco Circular Al Estilo G+ en LaTeX

Referencias

Nueva Guía Gratuita: Learning JavaScriptMVC -- Free 14 Page Excerpt

28/06/2017
Artículo original

{{ page.title }}

JavaScriptMVC is a client-side, JavaScript framework that builds maintainable, error-free, lightweight applications as quickly as possible.

As it does not depend on server components, it can be combined with any web service interface and server-side language.

“Learning JavaScriptMVC” will guide you through all the framework aspects and show you how to build small- to mid-size well-structured and documented client-side applications you will love to work on.

This book starts from JavaScriptMVC installation and all its components are explained with practical examples. It finishes with an example of building a web application. You will learn what the JavaScriptMVC framework is, how to install it, and how to use it efficiently.

This book will guide you on how to build a sample application from scratch, test its codebase using unit testing, as well as test the whole application using functional testing, document it, and deploy the same. After reading Learning JavaScriptMVC you will learn how to install the framework and create a well-structured, documented and maintainable client-side application.

Packt Enterprise books can be summed up through the tagline “Professional Expertise Distilled”. They take in-the-trenches knowledge from experienced software professionals, and distil it into a single, easy to follow manuscript.

Descárgala

Visita la página Manuales gratuitos o consulta el catálogo completo.

Cómo Crear Un Bundle Symfony2

28/06/2017
Artículo original

Éste artículo es una colaboración de Alejandro Blanco, Director de desarrollo en smsup.es

En este articulo vamos a ver los pasos que he seguido para crear un bundle de symfony 2 de forma que sea redistribuible mediante composer. Este bundle servirá para facilitar la interacción con la api de smsup, desde symfony2 y poder enviar sms masivos. Es un bundle simple, pero tiene varias cosas interesantes (requiere otra librería, utiliza parámetros de configuración, etc.), y puede ser una buena introducción.

Voy a describir paso a paso como lo he creado, habrá otras formas igualmente válidas y seguramente mejores, esto es solo como yo lo he hecho.

Asumo que ya tenemos composer instalado, si no es así, se puede instalar siguiendo estos pasos.

Instalar symfony2

Lo primero es instalar symfony, en este caso voy a instalar la versión 2.3, que es la versión menor con soporte ahora mismo, ya que quiero que sea compatible con el máximo de versiones posible y para ello lo mejor es crearlo sobre la menor versión. Lo instalamos usando el comando siguiente:

composer create-project symfony/framework-standard-edition /ruta/hasta/directorio-raiz-servidor-web/Symfony 2.3.0

Creamos la base del bundle

Una vez instalado, creamos dentro de vendors el directorio del bundle siguiendo la estructura en la que queramos que luego se instale. En este caso voy a usar la estructura smsup\smsup-api-bundle.

Ahora creamos dentro los archivos mínimos que debe tener el bundle para funcionar:

DependencyInjection/SmsupapiExtension.php: este archivo gestiona la carga de la configuración de los servicios definidos por el bundle. Aquí vamos cargar el archivo services.yml.

namespace smsup\SmsupapiBundle\DependencyInjection;
  use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;

class SmsupapiExtension extends Extension
{
    public function load(array $configs, ContainerBuilder $container)
    {
        $loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
        $loader->load('services.yml');
    }
}

Resources/config/services.yml: aquí se definen los servicios que expone el bundle. Vamos a definir solo un servicio que expondrá los métodos de la api y gestionara las peticiones a la librería. También podemos incluir en este archivo parámetros de configuración que luego queramos usar.

services:
  smsup.smsupapi.sender:
      class: smsup\SmsupapiBundle\Clases\SmsupSender

Clases/SmsupSender.php: esta será la clase que hemos definido para usar como servicio, en principio solo definiremos un método que haga un echo en pantalla para comprobar que funciona.

namespace smsup\SmsupapiBundle\Clases;
class SmsupSender {
  public function Send($mensaje)
  {
    echo "Su mensaje es: " . $mensaje;
  }
}

SmsupapiBundle.php: clase que extiende de Bundle y sirve para cargarlo.

namespace smsup\SmsupapiBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle;
class SmsupapiBundle extends Bundle
{
}

Con esto tendríamos definidos los archivos mínimos para crear el bundle y poder usarlo. Para probar que funciona bien vamos a modificar el archivo de autoload generado por composer (solo a modo de prueba, esto no debe hacerse ya que cada vez que instalamos algo con composer se modifican estos archivos), para simular como quedará una vez nuestro bundle sea instalado y añadiremos la carga del bundle en AppKernel.

En vendor\composer\autoload_psr4.php, añadir esta entrada en el array devuelto:

'smsup\\SmsupapiBundle\\' => array($vendorDir . '/smsup/SmsupapiBundle'),

En AppKernel añadimos:

new smsup\SmsupapiBundle\SmsupapiBundle(),

Ahora solo queda comprobar que todo funciona bien, para ello vamos a Acme\DemoBundle\Controller\WelcomeController.php y en el método indexAction añadimos el siguiente código:

$sender = $this->get('smsup.smsupapi.sender');
$sender->send('entró y funciona');

Esto simplemente obtendrá el servicio definido en nuestro bundle y llamara al método send que definimos, pasando el mensaje “entró y funciona”. Al ejecutar en el navegador localhost/RUTA_SYMFONY/web/app_dev.php/ deberíamos ver la página de bienvenida de symfony, pero en la primera línea debe aparecer el texto “Su mensaje es: entró funciona”, lo cual nos indica que todo ha ido bien.

Subida al repositorio

Como ya sabemos que funciona correctamente nuestro bundle, aunque no haga nada útil aun, vamos a subirlo a nuestro repositorio git y a añadirlo a packagist para que pueda ser descargado usando composer. Para esto debemos añadir el archivo composer.json, en el que vamos a definir nuestro bundle. En nuestro caso quedaría así:

{
  "name": "smsup/smsup-api-bundle",
  "type": "symfony-bundle",
  "description": "Bundle Symfony2 para el uso de la api de smsup.es para el envio de sms",
  "keywords": ["sms", "sms api", "bundle sms"],
  "homepage": "https://www.smsup.es",
  "license": "MIT",
  "require": {
      "php": ">=5.3.2",
      "smsup/smsuplib": "~2.0"
  },
  "autoload": {
      "psr-4": { "smsup\\SmsupapiBundle\\": "" }
  }
}

Los parámetros importantes aquí son los siguientes:

  • name: es el nombre que le damos y deber ser único
  • type: indicamos el tipo que es, en este caso un bundle de symfony
  • require: indicamos las dependencias de nuestro bundle, en este caso la librería “smsup/smsuplib”
  • autoload: indicamos que el namespace smsup\SmsupapiBundle hace referencia a la raíz de nuestro bundle.

Ya solo debemos declarar nuestro paquete en packagist, para lo cual tenemos que acceder a https://packagist.org y hacer login. Luego vamos a “Submit” e indicamos el enlace al repositorio y solo con esto ya nos cargara el mismo. Para que cada vez que actualicemos nuestro repositorio packagist actualice los datos, se recomienda añadir un webhook al repositorio. En el caso de github, debemos ir a Settings -> Weebhooks & Services -> Add Service. Seleccionar tipo Packagist e indicar el nombre de usuario y la clave de la API de packagist.

Una vez hecho esto vamos a instalar nuestro bundle desde composer para ver que todo es correcto. Antes vamos a eliminar el directorio que creamos en vendor, para que se instale limpiamente.

Como no hemos definido ninguna versión en nuestro repositorio, para que composer descargue el paquete, debemos cambiar en el archivo composer.json de symonfy, la estabilidad mínima de los paquetes a descargar, ya que la rama master se considera de desarrollo. Esto se hace cambiando “stable” por “dev” en:

"minimum-stability": "stable"

Para instalarlo ejecutamos la siguiente instruccion:

composer require smsup/smsup-api-bundle master

Hemos incluido “master” para indicar que se descargue la rama master, ya que aún no definimos ninguna versión estable.

Tras esto ya tenemos nuestro bundle instalado correctamente en vendors y si ejecutamos el código que teníamos de prueba veremos de nuevo el mensaje “Su mensaje es: entró funciona”.

Ahora ya solo debemos incluir las funcionalidades que queramos que tenga e ir actualizando el repositorio. Vamos a añadir la funcionalidad y luego veremos como crear la primera versión estable.

Añadimos parámetros obligatorios de configuración

Vamos a añadir dos parámetros de configuración obligatorios, en los que se le indicara al bundle el ID de la Api y la clave secreta de la misma. Para esto debemos crear el archivo DependencyInjection/Configuration.php en el que indicamos, mediante el método getConfigTreeBuilder, el árbol de parámetros que vamos a usar.

namespace smsup\SmsupapiBundle\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
class Configuration implements ConfigurationInterface
{
    public function getConfigTreeBuilder()
    {
        $treeBuilder = new TreeBuilder();
        $rootNode = $treeBuilder->root('smsupapi');
        $rootNode->
          children()
            ->scalarNode('api_id')
                ->isRequired()
                ->cannotBeEmpty()
            ->end()
            ->scalarNode('api_secret')
                ->isRequired()
                ->cannotBeEmpty()
            ->end()
          ->end()
        ;
        return $treeBuilder;
    }
}

Aquí indicamos que en el nodo “smsupapi” debe haber dos parámetros “api_id” y “api_secret” y que son obligatorios y no deben estar vacíos. Según esta configuración, si falta alguno de los parámetros symfony dará un error.

Luego debemos añadir unas líneas al archivo DependencyInjection/SmsupapiExtension.php para que se procese esa configuración, y hacemos que se inyecten los valores de los parámetros al servicio que habíamos creado.

public function load(array $configs, ContainerBuilder $container)
{
    $processor = new Processor();
    $configuration = new Configuration();
    $config = $processor->processConfiguration($configuration, $configs);
    $loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
    $loader->load('services.yml');
    $container->getDefinition('smsup.smsupapi.sender')
                ->addMethodCall('setApiid', array($config['api_id']));
    $container->getDefinition('smsup.smsupapi.sender')
                ->addMethodCall('setApisecret', array($config['api_secret']));
}

Para ello añadimos al servicio los setters correspondientes a la clase del nuestro servicio:

protected $apiId;
protected $apiSecret;
public function setApiid($apiId)
{
  $this->apiId = $apiId;
}
public function setApisecret($apiSecret)
{
  $this->apiSecret = $apiSecret;
}

Inyectamos de esta forma los parámetros para evitar inyectar el container al servicio, ya que no vamos a necesitarlo para ninguna otra cosa.

Añadimos la funcionalidad a nuestro servicio

Ahora vamos a añadir la funcionalidad que queremos que tenga a nuestro servicio. En este caso vamos a exponer 5 métodos públicos, que se corresponden con los métodos de la librería “smsuplib”. Añadiremos algunos cambios para facilitar el paso de parámetros y la gestión del resultado de la petición. SmsupSender.php quedaría así:

  namespace smsup\SmsupapiBundle\Clases;
  use smsup\smsuplib;
class SmsupSender {
  protected $apiId;
  protected $apiSecret;
  public function setApiid($apiId)
  {
    $this->apiId = $apiId;
  }
  public function setApisecret($apiSecret)
  {
    $this->apiSecret = $apiSecret;
  }
  public function getNewSms()
  {
    return new Sms;
  }
  public function enviarSms(Sms $sms)
  {
    $lib = $this->getSmsapilib();
    $respuesta = $lib->NuevoSms($sms->getTexto(), $sms->getNumeros(), $sms->getFechaenvio(), $sms->getReferencia(), $sms->getRemitente());
    return $this->setResult($respuesta);
  }
  public function eliminarSms($idsms)
  {
    $lib = $this->getSmsapilib();
    $respuesta = $lib->EliminarSMS($idsms);
    return $this->setResult($respuesta);
  }
  public function estadoSms($idsms)
  {
    $lib = $this->getSmsapilib();
    $respuesta = $lib->EstadoSMS($idsms);
    return $this->setResult($respuesta);
  }
  public function creditosDisponibles()
  {
    $lib = $this->getSmsapilib();
    $respuesta = $lib->CreditosDisponibles();
    return $this->setResult($respuesta);
  }
  public function resultadoPeticion($referencia)
  {
    $lib = $this->getSmsapilib();
    $respuesta = $lib->ResultadoPeticion($referencia);
    return $this->setResult($respuesta);
  }
  private function getSmsapilib()
  {
    return new smsuplib($this->apiId, $this->apiSecret);
  }
  private function setResult($respuesta)
  {
    return new Result($respuesta['httpcode'], $respuesta['resultado']);
  }
}

Añadimos dos clases como ayuda:

Sms.php

namespace smsup\SmsupapiBundle\Clases;
class Result {
  protected $httpcode;
  protected $result;
  public function __construct ($httpcode, $result)
  {
    $this->httpcode = $httpcode;
    $this->result = $result;
  }
  public function getHttpcode()
  {
    return $this->httpcode;
  }
  public function getResult()
  {
    return $this->result;
  }
}

Result.php

namespace smsup\SmsupapiBundle\Clases;
class Result {
  protected $httpcode;
  protected $result;
  public function __construct ($httpcode, $result)
  {
    $this->httpcode = $httpcode;
    $this->result = $result;
  }
  public function getHttpcode()
  {
    return $this->httpcode;
  }
  public function getResult()
  {
    return $this->result;
  }
}

Ahora ya tenemos completada la primera versión de nuestro bundle, por lo que actualizamos el repositorio y vamos a crear la primera versión estable del mismo.

Primera versión estable

Para definir una versión solo debemos añadir una etiqueta con la versión al repositorio y packagist se encarga del resto. La etiqueta debe tener el formato ‘X.Y.Z’ o ‘vX.Y.Z’ (también puede llevar un sufijo RC, beta, etc). En nuestro caso será la etiqueta “v1.0.0”. Hecho esto, ya está disponible una versión estable de nuestro bundle que puede instalarse de la siguiente forma:

composer require smsup/smsup-api-bundle

Podéis ver como quedan todos los archivos en el repositorio.

Espero que resulte útil esta introducción a la creación de un bundle y quedo abierto a cualquier comentario o mejora que queráis hacer.

Compilar Automáticamente Ficheros en LaTeX Mientras Los Modificamos

28/06/2017
Artículo original

Para los que estéis acostumbrados a escribir vuestros documentos en LaTeX, sin ningún editor específico, sabréis que llega a ser un poco tedioso compilar cada vez que queremos ver el resultado. Hace poco, descubrí un comando, latexmk, que nos facilitará bastante la vida.

Si estás interesado en aprender a usar LaTeX echa un vistazo al mini curso que tenemos.

Cómo usar latexmk

El comando latexmk tiene muchas opciones, pero en mi caso particular, no he necesitado más que estas (La opción -shell-escape la uso porque normalmente utilizo el paquete minted para colorear la sintáxis del código):

Para pdflatex

$ latexmk -shell-escape -pdf -pvc

Para xelatex

$ latexmk -shell-escape -xelatex -pdf -pvc

El comando asume que en el directorio donde se ejecuta solo exite un fichero .tex, de no ser así, deberemos pasarle el nombre del fichero que debe observar para detectar cambios.

Una vez en ejecución, veremos en la consola algo así:

=== Watching for updated files. Use ctrl/C to stop ...

A partir de ahora, cada vez que se modifique el fichero, se compilará y podremos ver el resultado.

Creando alias para los comandos

Ya que el comando es un poco largo, es recomendable crearse un alias para poder ejecutar latexmk escribiendo únicamente una palabra:

alias mlatexmk='latexmk -shell-escape -pdf -pvc ; latexmk -C'
alias mlatexmkx='latexmk -shell-escape -xelatex -pdf -pvc ; latexmk -C'

latexmk -C eliminará todos los ficheros intermedios. Ahora, para ejecutar basta con escribir:

$ mlatexmk # Para compilar con pdflatex
$ mlatexmkx # Para compilar con xelatex

Cómo Configurar Dunst, Un Daemon De Notificaciones Altamente Configurable

28/06/2017
Artículo original

Cómo configurar Dunst. Daemon de notificaciones

Si eres lector habitual del blog, sabrás que me gustan los entornos minimalistas y configurables, como puede comprobarse en los artículos instalar y configurar dwm, y el patch para colorear la barra de estado.

Hoy quiero hablaros de dunst, un demonio de notificaciones que me instalé hace poco, y que se integra muy bien con DWM.

Instalar dunst

Tan simple como ejecutar:

$ sudo apt-get install dunst

Configurar dunst

Dunst es áltamente configurable, mediante su fichero de configuración, situado en ~/.config/dunst/dunstrc, podemos cambiar su aspecto por completo. Aquí dejo un ejemplo de mi configuración actual:

[global] # Configuración global
    font = "Ubuntu Light 12"
    # Permitir etiquetas html
    allow_markup = yes
    # El formato de las notificaciones,
    # %s - sumario
    # %p - progreso
    # %b - cuerpo del mensaje
    format = "<b>%s %p</b>\n%b"
    # Ordenar mensajes por prioridad
    sort = yes
    # Mostrar cuantas not. hay ocultas
    indicate_hidden = true
    idle_threshold = 0
    # Tamaño de  la notificación
    geometry = "300x5-20+20"
    alignment = center
    show_age_threshold = 60
    sticky_history = yes
    follow = mouse
    word_wrap = yes
    separator_height = 2
    padding = 10
    horizontal_padding = 10
    separator_color = frame
    startup_notification = true

# Diseño del borde de la notificación
[frame]
    width = 3
    color = "#6092BE"

# Atajos de teclado
[shortcuts]
    close = ctrl+space
    close_all = ctrl+shift+space
    history = ctrl+grave
    context = ctrl+shift+period

# Estilo para las notificaciones de baja prioridad
[urgency_low]
    background = "#ffffff"
    foreground = "#000000"
    timeout = 5

# Estilo para las notificaciones de prioridad normal
[urgency_normal]
    background = "#94DBFF"
    foreground = "#000000"
    timeout = 10

# Estilo para las notificaciones de alta prioridad
[urgency_critical]
    background = "#ff9999"
    foreground = "#000000"
    timeout = 0

# Se pueden personalizar notificciones en función de su texto
[test]
    summary = "*test*"
    background="#22dd22"

# Y también se personalizan por aplicación
[signed_on]
    appname = Pidgin
    summary = "*signed on*"
    urgency = low

Probar la configuración

Para probar cómo queda nuestra configuración, podemos usar el comando notify-send:

notify-send -u low -t 0 "Low sumary" "Low body"
notify-send -u normal -t 0 "Normal sumary" "Normal body"
notify-send -u critical -t 0 "Critical sumary" "Critical body"
notify-send -u critical -t 0 "test" "Critical body"

Eso es todo, sencillo de configurar, y minimalista.

Cómo Hacer Scroll en Un ListView Que Está Dentro De Un ScrollView en Android

28/06/2017
Artículo original

En Android, cuando se tiene un ListView, dentro de un ScrollView, es posible que el último capture todos los eventos onTouch, y no sea posible utilizar el ListView.

Para solucionar el problema, bastaría con deshabilitar la captura del evento onTouch para el ScrollView, si lo que estamos pulsando es el ListView, es decir:

Al ScrollView, le añadimos un evento onTouch. Dentro, recuperaremos el ListView, para deshabilitar en su padre la intercepción de eventos onTouch. En éste caso, el padre del ListView es el ScrollView.

miScrollView.setOnTouchListener(new View.OnTouchListener() {

    public boolean onTouch(View v, MotionEvent event) {
        findViewById(R.id.miListView).getParent()
                .requestDisallowInterceptTouchEvent(false);
        return false;
    }
});

Al ListView, le añadimos también un onTouch, y haremos el proceso inverso.

miListView.setOnTouchListener(new View.OnTouchListener() {

    public boolean onTouch(View v, MotionEvent event) {
        v.getParent().requestDisallowInterceptTouchEvent(true);
        return false;
    }
});

La documentación oficial del método es:

Called when a child does not want this parent and its ancestors to intercept touch events with onInterceptTouchEvent(MotionEvent). This parent should pass this call onto its parents. This parent must obey this request for the duration of the touch (that is, only clear the flag after this parent has received an up or a cancel. Parameters disallowIntercept True if the child does not want the parent to intercept touch events.

Es decir, le pasaremos true cuando la vista hija no quiera que el padre intercepte eventos onTouch.

Página Anterior Página Siguiente