Comparar fechas

09/11/2017
Artículo original

       Un pequeño aporte a Luz Jasso. Mie, 08/02/2017 - 13:26        

        //fechas de ejemplo
        String fecha_ini = "2007-11-08";
        String fecha_fin = null;
        //hojas de ejemplo
        String hr_ini    = "02:00";
        String hr_fin    = "02:30";
        //declaracion de variables
        double diff, min, hrf;
        Date   result1, result2;
       
        SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm");
       
        try {
            result1 = formater.parse(fecha_ini+" "+hr_ini);
            result2 = formater.parse(fecha_fin+" "+hr_fin);
            //
            diff = result2.getTime() - result1.getTime();
            long tiempoMensual =0;
            tiempoMensual += diff;
            min=((diff%3600000)/60000)/60;
            hrf=diff/3600000;            
        } catch (ParseException ex) {
            //Escriba aqui los valores de retorno al ocurrir error
            min=0;hrf=0;
        }

Software de contabilidad electrónica – Herramientas para Pymes

08/11/2017
Artículo original

Espero y este post sea de tu agrado, no olvides compartirlo en su redes sociales y sobre todo.. Gracias por seguirnos!

¿Sabes qué es un software de contabilidad electrónica? ¿Sabes que tomar en cuenta a la hora de elegir un software de contabilidad electrónica para tu negocio? Hoy veremos como un software de contabilidad electrónica puede ayudarnos a gestionar de mejor forma nuestro negocio y es una de las mejores herramientas para pymes que puedes obtener! La contabilidad es una tarea que cualquier empresa tiene sin importar su tamaño, ingresos o giro de la misma. Es un tema de gran importancia en el que siempre es buena idea estar actualizado y con la última tecnología, es por esto que hoy hablaremos

Compartir en Facebook

Comparte en Google Plus

Compartir en Twitter

El post Software de contabilidad electrónica – Herramientas para Pymes aparece en el Blog de Jonathan Melgoza

Angular 5: todo lo que necesitas saber, en 10 minutos o menos

08/11/2017
Artículo original

Logotipo de Angular
Imagen por Tom Bullock, CC BY

Desde finales de la semana pasada está ya disponible Angular 5, la nueva versión del conocido framework de desarrollo web Front-End.

Esta versión entra dentro del plan de Google de lanzar una nueva revisión "grande" cada 6 meses, aunque en ocasiones las novedades sean más bien escasas. No es lo que ocurre en esta ocasión, en la que la versión 5 trae bastantes cosas nuevas y alguna de ellas bastante importante.

Vamos a verlas...

HttpClient

En la versión 4.3 se lanzó HttpClient dentro de @angular/common como una forma más pequeña, sencilla y potente de realizar solicitudes web en Angular. A partir de esta nueva versión Google recomienda utilizar el HttpClient para todas las aplicaciones, y dejar de utilizar la biblioteca "tradicional" @angular/http que queda marcada como obsoleta.

Para actualizar a HttpClient, hay que reemplazar en todos los módulos HttpModule por HttpClientModule (que está en @angular/common/http), inyectar el servicio HttpClient y eliminar todas las llamadas de map(res => res.json()) , que ya no son necesarias.

Este era uno de los grandes cambios ya esperados desde que salió la 4.3 y finalmente hemos visto cómo se ha materializado.

Nuevos eventos del ciclo de vida del enrutador

Se han agregado nuevos eventos de ciclo de vida al router, lo que permite a los desarrolladores rastrear el ciclo del enrutador desde el inicio de la ejecución hasta la finalización de la activación. Estos eventos podrían usarse para cosas tales como mostrar el típico spinner (elemento de progreso) en un enrutador específico cuando un componente hijo se está actualizando, o para medir el rendimiento de la resolución de una ruta.

Los nuevos eventos por orden de lanzamiento son GuardsCheckStart, ChildActivationStart, ActivationStart, GuardsCheckEnd, ResolveStart, ResolveEnd, ActivationEnd y ChildActivationEnd .

Un ejemplo de uso de estos eventos para iniciar/detener un elemento de progreso podría ser:

class MyComponent {
  constructor(public router: Router, spinner: Spinner) {
    router.events.subscribe(e => {
      if (e instanceof ChildActivationStart) {
        spinner.start(e.route);
      } else if (e instanceof ChildActivationEnd) {
        spinner.end(e.route);
      }
    });
  }
}

Mejoras en el compilador

Esta versión mejora el compilador de Angular para admitir la compilación incremental. Esto proporciona re-builds más rápidas de las aplicaciones, especialmente para builds de producción y compilaciones con AOT (Ahead Of Time). También se ha agregado funcionalidad a los decoradores de código, y ahora es posible enviar bundles más pequeños, eliminando espacios en blanco.

Transformaciones de TypeScript

Debajo del capó, el compilador de Angular funciona ahora como una transformación de TypeScript, lo que hace que las reconstrucciones incrementales sean mucho más rápidas. Las transformaciones de TypeScript fueron una nueva característica introducida como parte de TypeScript 2.3 que permite engancharse a la pipeline de compilación estándar de TypeScript.

Puedes aprovechar esto ejecutando ng serve con el flag AOT activado:

ng serve --aot

Deberías probarlo ya que esto se convertirá en la acción predeterminada en una versión futura de la CLI. Existen algunos problemas de velocidad conocidos con proyectos con más de mil componentes. Con esto, los proyectos de todos los tamaños experimentarán estas mejoras.

Al realizar una compilación AOT incremental de https://angular.io, el nuevo proceso de compilación disminuye el tiempo de compilación un 95% (de más de 40 segundos a menos de 2 segundos en las máquinas de desarrollo del equipo de Angular).

El objetivo era convertir la compilación AOT en algo lo suficientemente rápido como para poder usarla en tiempo de desarrollo, eliminando las diferencias que a veces se encuentran cuando se ponen las apps en producción por primera vez. Por eso estará activado de forma predeterminada en una versión futura de la CLI.

Como parte de esta transición a las transformaciones, ya no necesitamos genDir, y outDir ha cambiado: ahora siempre estamos emitiendo archivos generados para paquetes en node_modules.

Preservar los espacios en blanco

Hasta ahora el compilador recreaba fielmente los tabuladores, saltos de línea y espacios de las plantillas y los incluía en su compilación. Ahora podemos elegir si deseamos conservar estos espacios en blanco provenientes de nuestros componentes.

Podemos especificar esto como parte del decorador de cada componente, siendo true por defecto su valor:

@Component({
  templateUrl: 'about.component.html',
  preserveWhitespaces: false
}
export class AboutComponent {}

O podemos especificarlo para toda la aplicación en el archivo tsconfig.json, en donde también está predeterminado como true.

En general, las especificaciones a nivel de componente anulan las especificaciones de toda la aplicación. En el futuro, el equipo de Angular espera establecer el valor predeterminado en false para ahorrarnos esos espacios de forma predeterminada, así que tenlo en cuenta. Eso sí, las etiquetas <pre> se manejan de forma inteligente y no se tocan nunca.

Más información sobre preserveWhitespaces.

Build Optimizer

A partir de esta versión 5.0.0, las compilaciones de producción creadas con la CLI ahora aplicarán el optimizador de compilación de forma predeterminada.

El optimizador de compilación es una herramienta incluida en la herramienta de línea de comandos para reducir los paquetes resultantes, utilizando comprensión semántica de tu aplicación angular. El optimizador de compilación tiene dos trabajos principales. En primer lugar, puede marcar partes de la aplicación como "pure", lo cual mejora el "Tree-Shaking" proporcionado por las herramientas existentes, eliminando partes adicionales de la aplicación que no son necesarias.

Lo segundo que hace el optimizador de compilación es eliminar los decoradores de Angular del código de tiempo de ejecución de su aplicación. Los decoradores son utilizados por el compilador, y no son necesarios en el tiempo de ejecución, y por lo tanto se pueden eliminar.

Cada uno de estos trabajos disminuye el tamaño de los paquetes de JavaScript y aumenta la velocidad de inicio de la aplicación.

CLI v1.5

A partir de la v1.5 de la CLI de Angular, se ha agregado soporte para Angular v5.0.0 y generará proyectos v5 de manera predeterminada.

Además en esta nueva versión se ha activado el optimizador de compilación (ver punto anterior) de forma predeterminada, por lo que los desarrolladores pueden beneficiarse de paquetes finales más pequeños.

API Angular Universal State Transfer y soporte DOM

Ahora puedes compartir más fácilmente el estado de la aplicación entre las versiones del lado del servidor y del lado del cliente de la aplicación.

Angular Universal es un proyecto centrado en ayudar a los desarrolladores a realizar la representación del lado del servidor (SSR: Server Side Rendering) de las aplicaciones de Angular. Al renderizar las aplicaciones en el servidor y luego realizar un bootstrapping sobre el HTML generado, podemos agregar soporte para rastreadores que no admiten JavaScript, y puede aumentar el rendimiento percibido de su aplicación.

En 5.0.0, el equipo de Angular ha agregado ServerTransferStateModule y el BrowserTransferStateModule correspondiente. Este módulo permite generar información como parte de la representación en el servidor, y luego transferirla al lado del cliente para que esta información no necesite ser regenerada. Esto es útil para casos como cuando nuestra aplicación obtiene datos a través de HTTP. Al transferir el estado del servidor, esto significa que los desarrolladores no necesitan realizar una segunda solicitud HTTP una vez que la aplicación llega al cliente.

La documentación para esta funcionalidad todavía no está disponible.

Otro cambio que viene del equipo de Angular Universal es la adición de Domino, un simulador del DOM para lado servidor con Node.js. Domino significa que admitimos más manipulaciones de DOM listas para usar en contextos del lado del servidor, mejorando nuestro soporte para bibliotecas JS y bibliotecas de componentes de terceros que no están al tanto del lado del servidor.

Internacionalización de tuberías para números, fechas y monedas

En esta versión se han introducido unas nuevas tuberías (pipes, en la jerga de Angular) para números, fechas y monedas que aumentan la estandarización del proceso de internacionalización entre navegadores y eliminan la necesidad de usar polyfills para conseguirlo.

En versiones anteriores de Angular se utilizaba cada navegador para obtener el formato apropiado para estos tipos de datos, lo cual hacía que los usuarios vieran resultados inconsistentes entre navegadores y, para corregirlo, se hacía necesario usar polyfills que generaran siempre el mismo resultado.

En Angular 5.0.0 se han actualizado las pipes para usar una implementación propia, confiando en el CLDR para proporcionar soporte amplio de configuraciones locales y las configuraciones regionales que puedas necesitar. Aquí tienes una hoja de cálculo que compara el comportamiento de estos pipes entre las versiones 4 y 5.

Si no quieres usar todavía estas nuevas tuberías, puedes importar el módulo DeprecatedI18NPipesModule para tener acceso al comportamiento anterior.

Puedes obtener más detalles sobre los cambios en el changelog de Angular 5.

Se reemplaza ReflectiveInjector con StaticInjector

Para eliminar aún más polyfills, se ha reemplazado el ReflectiveInjector con el nuevo StaticInjector. Este inyector ya no requiere el polyfill Reflect, lo que reduce el tamaño de la aplicación para la mayoría de los casos.

Antes usabas:

ReflectiveInjector.resolveAndCreate(providers);

Ahora:

Injector.create(providers);

Mejoras de velocidad de zonas

En Angular 5.0.0 las zonas son más rápidas por defecto, e incluso es posible evitar completamente algunas zonas en caso de que nuestra aplicación necesite un gran rendimiento.

Para evitar las zonas, podemos iniciar la aplicación con noop como valor para ngZone:

platformBrowserDynamic().bootstrapModule(AppModule, {ngZone: 'noop'}).then( ref => {} );

Puedes ver un ejemplo completo en el proyecto ng-component-state.

exportAs

Se ha añadido soporte para múltiples nombres para un mismo componente o directiva. Esto puede ser muy útil para ayudar a nuestros usuarios a migrar de componente sin que haya rotura de la aplicación.

Esta funcionalidad ya se ha utilizado como parte del proyecto de Angular Material, cuando se cambiaron los prefijos, y también puede ayudar a otros autores de componentes:

@Component({
  moduleId: module.id,
  selector: 'a[mat-button], a[mat-raised-button], a[mat-icon-button], a[mat-fab], a[mat-mini-fab]',
  exportAs: 'matButton, matAnchor',
  .
  .
  .
}

Formularios

Angular Forms añade updateOn Blur / Submit

Los formularios son una parte muy importante de muchas aplicaciones, y si tienen algún tipo de validación que se realiza en el lado del servidor, o las validaciones desencadenan procesos de servidor pesados que sería recomendable ejecutar menos a menudo. Por ello ahora es posible ejecutar validaciones y actualizaciones de valores en el evento blur o ensubmit, en lugar de en cada evento de entrada. De este modo podemos tomar el control de la emporización de las validaciones y del cambio de valores a nivel de control o un formulario completo.

Además, ahora podemos especificar asyncValidators directamente en el objeto de opciones, en lugar de especificarlo como un tercer parámetro.

Formularios basados en plantillas

Antes escribíamos:

<input name="firstName" ngModel>

Ahora podemos escribir:

<input name="firstName" ngModel [ngModelOptions]="{updateOn: 'blur'}">

o incluso:

<form [ngFormOptions]="{updateOn: 'submit'}">

Formularios reactivos

Antes_

new FormGroup(value); 
new FormControl(value, [], [myValidator])

Ahora:

new FormGroup(value, {updateOn: 'blur'}));
new FormControl(value, {updateOn: 'blur', asyncValidators: [myValidator]})

RxJS 5.5

Angular ahora utiliza RxJS 5.5.2. Esta versión reciente de RxJS permite evitar los efectos secundarios del mecanismo de importación anterior con una nueva manera de utilizar RxJS llamada "lettable operators". Estos nuevos operadores eliminan los efectos secundarios y los problemas de división de código/tree shaking que existían anteriormente con el método para "parchear" la importación de operadores.

En lugar de:

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/filter';
names = allUserData
.map(user => user.name)
.filter(name => name);

Ahora podemos escribir:

import { Observable } from 'rxjs/Observable';
import { map, filter } from 'rxjs/operators';
names = allUserData.pipe(
  map(user => user.name),
  filter(name => name),
);

Además, RxJS ahora distribuye una versión que hace uso de módulos ECMAScript. La nueva CLI angular incluye esta versión de manera predeterminada, lo que supondrá un ahorro considerable en el tamaño del paquete. Pero incluso si no estamos utilizando la CLI de Angular deberemos apuntar a esta nueva distribución.

La documentación se puede encontrar en la sección Build y Tree-shaking de la documentación.

Ayuda a la migración y precauciones

Angular 5.0.0 es una actualización importante dentro de la biblioteca Front-End, e incluye algunas características importantes, mejoras de rendimiento y algunas funcionalidades que se han marcado como obsoletas.

Tal y como prometieron, la gente de Google ha lanzado una pequeña herramienta de migración que te ayuda en el proceso de pasar una app desde Angular 4.x a 5.0.0. No debería ser muy complicado hacer dicha migración.

También existen algunas incidencias sin resolver que se atajarán en próximos parches. La más importante es que en ocasiones se pueden producir mapas de código fuente (source maps) que pueden producir errores. Pero nada importante y la versión 5.0.0 está lista para ser utilizada en producción.

Ya estamos trabajando en actualizar nuestro estupendo curso de Angular a la nueva versión y esperamos tenerlo listo en los próximos días. Iremos informando...

Git: Chuleta de Comandos

07/11/2017
Artículo original

Tutorial git y comandos git

NOTA: Puede que te interese descargar este manual para git. Si rellenas el formulario correctamente nos darán $1.5 de comisión, una buena forma de mostrar tu apoyo al blog ;-)

Una de mis tareas pendientes era aprender GIT decentemente. Así que empecé a leer Pro Git, libro que recomiendo a todo desarrollador, disponible en PDF, EPUB, MOBI y versión en papel. En la página del libro puedes encontrar versiones en distintos idiomas. Conforme he ido leyendolo, he anotado los comandos. Como resultado he creado esta especie de chuleta de comandos git que comparto hoy con vosotros. Espero que os resulte útil.

Chuleta de comandos git

  • git help <command>
  • git clone <uri> namedir # clona usando como nombre de directorio namedir.
  • git add <dir> # añade recursivamente todos los archivos del dir.
  • git diff --staged # compares staged changes with last commit
  • git commit -v # muestra el diff en el editor
  • git commit -a -m "mensaje" # automatically stage tracked files. No hace falta git add
  • git rm --cached <file or regexp> # Git no realiza un seguimiento del archivo, pero los deja en el directorio de trabajo. Útil cuando se olvida añadir archivos al .gitignore y ya hemos agregado dichos archivos al repositorio.
  • git rm <file> # borrarlos con git siempre.
  • git rm -f <file> # si ya está modificado y en el index.
  • git mv <file> <renamed_file>
  • gitk # tcl/tk. Herramienta gráfica para git
  • git commit --amend # Modificar el mensaje del último commit
  • git reset HEAD <file> # to unstage
  • git checkout -- <file> # Descartar cambios en el directorio de trabajo.

AÑADIR ARCHIVOS

  • git add -i # interactive staggin
  • git add -p # crea patch

STASH

  • git stash # guarda el estado en una pila y limpia el directorio para poder cambiar de rama
  • git stash list # muestra la pila
  • git stash apply # vuelve al estado original del dir. Stash{n} especifica uno concreto Y –index reaplica los cambios stagged
  • git stash pop # elimina el primero en la pila. O drop

LOGS

  • git log -p -2 # Muestra 2 últimos commits con diff
  • git log --stat
  • git log --pretty <short|full|fuller>
  • git log --pretty=format:"%h - %an, %ar : %s"
  • git log --pretty=format;"%h %s" --graph
  • git log --since=2.weeks
  • git log <branch> --not master # Muestra commit de <branch> sin incluir los de master
  • git log --abbrev-commit --pretty=oneline
  • git diff master...contrib # Muestra solo el trabajo que la rama contrib actual ha introducido desde su antecesor común con master
  • git log <branch1>..<branch2> # Commits de branch2 que no están en branch1
  • git log origin/master..master # Muestra qué commits se van a enviar al servidor
  • git log origin/master.. # Igual que el anterior. Se asume master o HEAD
  • git log refA refB --not refC # commits en refA y refB que no están en refC
  • git log master...experiment # commits de master o experiment, pero sin ser comunes. Con –left-right indica a qué rama pertenece cada uno

REMOTES # repos en internet

  • git remote -v # lista los repos remotos
  • git remote add [shortname] [url] # crea nuevo remote, es posible descargar el contenido de ese repo con git fetch [shortname]. Master branch en [shortcode]/master
  • git fetch <remote> # descarga trabajo nuevo a máquina local, no sobreescribe nada tuyo. ( git pull sí hace merge automaticamente si se esta realizando un seguimiento de esa branch)
  • git push [remote-name] [branch-name] # sii nadie ha hecho push antes
  • git remote show [remote-name] # inspecciona remote.
  • git remote rename <old-name> <new-name> # también renombra branches: quedaría <new-name>/master
  • git remote rm <remote-name> # p.e si el contribuidor ya no contribuye más

Añadir varios repositorios remotos

  • git remote add bitbucket <url repositorio> # Añadir un nuevo repositorio remoto con el nombre deseado. Por ejemplo si ya tenemos uno en github y queremos añadir otro para bitbucket
  • git push -u bitbucket -all # Subir el proyecto a bitbucket. A partir de ahora se puede seleccionar a qué repo publicar con git push nombre_repo_remoto

TAGGING # marcan puntos importantes en la histtoria del repo ( releases )

  • git tag # muestra las etiquetas actuales
  • git tag -l 'v1.4.2.*' # acepta regex
  • Dos tipos de tag:
    • Lightweight : puntero a commit ( branch que no cambia )
    • Annotated : se almacenan como objetos en la db, con checksum, nombre del creador, email, fecha, mensaje, posibilidad de firmarla con GPG. ( recomendada )
  • git tag -a <tagname> -m 'mensaje' # annotated tag
  • git show <tag-name> # muestra información asociada.
  • git tag -s <tag-name> -m 'message' # la firma con gpg
  • git tag <tag-name> # lightweight tag
  • git tag -v <tag-name> # verifica tags firmadas
  • git tag -a <tag-name> [commit-chksum] # crea tag para commit con dicho chksum
  • Por defecto no se transfieren los tags, para subirlos al servidor:
    • git push origin [tag-name] # una sola
    • git push origin --tags # Enviar todas
  • Para usar GPG y firmar tags, hay que subir la clave pública al repositorio:
    • gpg --list-keys # Coges la id pública
    • gpg -a --export <id> | git hash-object -w --stdin # Copia el SHA-1 devuelto
    • git tag -a maintainer-gpg-pub <SHA-1>
    • git push --tags # Comparte la clave con todos los usuarios
    • git show maintainer-gpg-pub | gpg --import # Cada usuario importa la clave así
    • git show <tag> # Devuelve más información sobre la etiqueta
    • git tag -d nombre_tag # eliminar la etiqueta
    • git push origin :refs/tags/nombre_tag # Eliminar la etiqueta del repositorio remoto.

BRANCH

Las ramas simplememte son punteros a distintos snapshots

  • git branch <nombre-rama> # crea rama. Puntero al commit actual
  • git checkout <nombre-rama> # cambiar a la rama especificada.
  • git checkout -b <nombre-rama> # crea y cambia de rama
  • git merge <rama> # Mezcla la rama actual con <rama>
  • git branch -d <rama> # elimina la rama
  • git push origin --delete <branchName> # Elimina una rama del servidor
  • git mergetool # Herramienta gráfica para resolver conflictos
  • git branch # lista ramas
  • git branch -v # lista ramas mostrando último commit
  • git branch --merged # lista ramas que han sido mezcladas con la actual. Si no tienen un *, pueden borrarse, ya que significa que se han incorporado los cambios en la rama actual.
  • git branch --no-merged # lista ramas que no han sido incorporadas a la actual.

REMOTE BRANCHES

  • git fetch origin # Descarga el contenido del servidor
  • git push <remote> <branch> # Las ramas no se suben por defecto, has de subirlas explícitamente
  • git push <remote> <branch>:<nuevoNombre> # Igual que la de arriba, pero en el servidor se llama a la rama con nuevoNombre en lugar de branch
  • Cuando se hace un git fetch que trae consigo nuevas ramas remotas, no se disponen de ellas localmente, solo se dispone de un puntero a la rama remota que no es editable. Para poder trabajar sobre esa rama, es necesario crearla Por ejemplo:
    • git fetch origin # Tras ejecutarlo, notamos que se ha creado una rama nueva (rama_nueva)
    • git checkout -b rama_nueva origin/rama_nueva # Crea una rama local a partir de la remota
    • git merge origin/nueva_rama # Equivalente a la de arriba, pero sin establecer el tracking a la rama
  • git push [remotename] :[branch] # elimina una rama remota
  • git push [remotename] [localbranch]:[remotebranch] # La rama en el servidor tiene distinto nombre a la local

TRACKING BRANCHES

  • git checkout --track origin/rama # Equivalente a -b rama_nueva origin/rama_nueva
  • git chekout -b <nuevo_nombre> origin/<rama> # Establece un nombre distinto para la rama local

REBASE

Rebase y merge se diferencian en que merge mezcla dos puntos finales de dos snapshots y rebase aplica cada uno de los cambios a la rama en la que se hace el rebase. No lo uses en repos publicos con mas colaboradores, porque todos los demas tendrán que hacer re-merges

  • git checkout <una rama>
  • git rebase master # aplica todos los cambios de <una rama> a master
  • git merge master # hay que hacer un merge de tipo fast forward
  • Tenemos 3 ramas, master, client y server, en server y client tenemos varios commit y queremos mezclar client en master pero dejar server intacta:
    • git rebase --onto master server client # adivina los patches del antecesor común de las ramas server y client y aplica los cambios a master.
    • git checkout master
    • git merge client # fast-forward. Client y master en el mismo snapshot
  • Si se quiere aplicar también los cambios de server, basta con:

    • git rebase master server
    • git checkout master
    • git merge server
  • git rebase [basebranch] [topicbranch] # sintaxis de rebase

  • git rebase -i # Rebase interactivo

SERVIDOR

  • git instawew # Muestra una interfaz web con los commits

GENERAR UN NÚMERO DE COMPILACIÓN (BUILD NUMBER)

  • git describe master # Solo funciona para tags creadas con -s ó -a

PREPARAR UNA RELEASE

  • git archive master --prefix="project/" | gzip > $(git describe master).tar.gz
  • git archive master --prefix="project/" --format=zip | $(git describe master).zip
  • test/ export-ignore # Al crear el tarball no incluye el directorio test/

GENERAR UN CHANGELOG

  • git shortlog --no-merges master --not <tag> # Recopila todos los commits desde <tag> y los agrupa por autor

RECOMENDACIONES

  • Siempre hay que hacer pull antes de push en caso de que alguien haya subido cambios al servidor. Ejemplo:

    • User1 clona el repo y hace cambios, realiza un commit
    • User2 clona el repo, hace cambios, hace commit y sube los cambios con push
    • User1 intenta hacer push, pero será rechazado con: ! [rejected] master -> master (non-fast forward). No puede subir los cambios hasta que no mezcle el trabajo que ha subido User2. Así que debe hacer lo siguiente:
    • git fetch origin
    • git merge origin/master
    • git push origin master
  • Mientras User1 hacía estas operaciones, User2 ha creado una rama issue54 y realizado 3 commits, sin haber descargado los cambios de User1. Para sincronizar el trabajo, User2 debe hacer:

    • git fetch origin
    • git log --no-merges origin/master ^issue54 # Observa qué cambios ha hecho User1
    • git checkout master
    • git merge issue54 && git merge origin/master
    • git push origin master
  • git diff --check # Antes de hacer commit, ejecutar esto para ver si hemos añadido demasiados espacios que puedan causar problemas a los demás.

  • Commits pequeños que se centren en resolver un problema, no commits con grandes cambios.

  • git add --patch # En caso de hacer varios cambios en el mismo archivo

  • El mensaje del commit debe tener la estructura siguiente: Una linea de no más de 50 caracteres, seguida de otra línea en blanco seguida de una descripción completa del commit.

PASOS A SEGUIR PARA CONTRIBUIR A PROYECYOS AJENOS, MEDIANTE FORK

  • git clone <url>
  • git checkout -b featureA
  • git commit
  • git remote add myFork <url>
  • git push myFork featureA
  • git request-pull origin/master myFork # enviar la salida por mail al propietario del proyecto, o hacer click en pull request.
  • Buena practica tener siempre una rama master que apunte a origin/master, para estar siempre actualizado con los ultimos cambios en el proyecto original.
  • Separar cada trabajo realizado en topic branch, que trackeen a origin/master
  • git checkout -b featureB origin/master
  • (Hacer cambios)
  • git commit
  • git push myFork featureB
  • (Contactar con el propietario del proyecto)
  • git fetch origin
  • Otro ejemplo, el propietario del proyecto quiere aceptar un pull tuyo, pero quiere que hagas algunos cambios, aprovechas la oportunidad y mueves tu trabajo para basarlo en el contenido actual de la rama origin/master, aplastas los cambios en featureB, resuelves conflictos, y haces push:
    • git checkout -b featureBv2 origin/master
    • git merge --no-commit --squash featureB
    • (cambiar la implementacion)
    • git commit
    • git push myFork featureBv2
    • --squash coge todo el trabajo de la rama mezclada y la aplasta en un no-merge commit encima de la rama en la que estas. –no-commit no registra el commit automaticamente. Así puedes realizar todos los cambios necesarios y luego hacer el commit

REFLOG

En segundo plano, git crea un log de a donde han estado referenciando HEAD y el resto de ramas en los últimos meses.

  • git reflog
  • git show HEAD@{n} # Muestra información sobre el reflog número n
  • git log -g master # Muestra el log formateado como la salida de reflog
  • git show master@{yesterday} # Muestra los commits de ayer.

UTILIDADES

  • git show <short-SHA-1> # Es posible ver un commit pasando la versión abreviada del SHA-1
  • git rev-parse <branch> # A qué SHA-1 apunta una rama
  • git show HEAD^ # Muestra commit padre
  • git show HEAD^2 # Muestra segundo padre
  • git show HEAD~2 # El primer padre del primer padre
  • git filter-branch --tree-filter 'rm -f <file>' HEAD # elimina el archivo de todos los commits

DEPURACIÓN

  • File anotation

    • git blame -L 12,22 <archivo> # muestra cuando y por quién se modificaron de la linea 12 a la 22
    • git blame -C -L 141,153 <file> # cuando renombras un archivo o lo refactorizas en varios, muestra de donde vino originalmente.
  • Búsqueda Binaria: Cuando hay un bug que no puedes localizar, usas bisect para dererminar en qué commit empezó a producirse el bug.

    • git bisect start
    • git bisect bad # marcas el commit actual como roto
    • git bisect good [commit bueno] # último commit conocido que funcionaba
  • Ahora irá preguntando hasta que encuentres el commit culpable. Si esta bien indicas git bisect good. De lo contrario git bisect bad. Al terminar hay que resetear.

    • git bisect reset

SUBMODULOS

  • git submodule add <url> # crea un directorio que contiene el comtenido de otro proyecto.

  • Clonar un repo con submodulos

    • git clone url
    • git submodule init
    • git submodule update

CONFIGURATION

  • git config --global <opcion> <valor> # global para usuario, system todos y sin nada, especifico para el repo.
  • git config {key} # muestra el valor de key
  • git config --global core.editor <editor> # cambia el editor por defecto
  • git config --global commit.template $HOME/.gitmessage.txt # plantilla para commits
  • git config --global core.pager 'more|less' # paginador por defecto, puedes usar cualquiera
  • git config --global user.signingkey <gpg-key-id> # clave gpg para firmar tags
  • git config --global core.excludesfile <file> # como gitignore
  • git config --global help.autocorrect 1 # autocorrige cuando se escribe un comando incorrecto. Solo en git >= 1.6.1
  • git config --global color.ui true # colorea la salida de git. Valores: true|false|always
  • git config --global core.autocrlf input # para que usuarios linux no tengan problemas con los retornos de carro de windows
  • git config --global core.autocrlf true # para usuarios de windows
  • git config --global core.whitespace trailing-space, space-before-tab, indent-with-non-tab, cr-at-eol # respectivamente: busca espacios al final de línea, busca espacios al inicio de tabulación, busca líneas con 8 o más espacios en lugar de tabulaciones, acepta retornos de carro
  • git apply --whitespace=warn <patch> # advierte de errores de espacios antes de aplicar el patch. Con –whitespace=fix intenta arreglarlos

GIT ATTRIBUTES

Archivo en .gitattributes en el directorio de trabajo o en .git/info/attributes para no committearlo

Identificando archivos binarios Muchos archivos son para uso local y no aportan información al repositorio. Para decirle a git qué archivos son binarios hacer añadir al archivo atributes:

  • <nombre archivo o regexp> -crlf -diff # git no intentará corregir problemas de crlf ni mostrará los cambios con diff. En versiones >= 1.6 se pueden sustituir estos dos valores por la macro binary

Diffing binary files

En ocasiones es útil mostrar diffs de archivos binarios, como una archivo de word:

*.doc diff=word

tras esto hay que definir el filtro word para que git convierta archivos word a texto:

  • git config diff.word.textconv strings

Es posible hacer lo mismo para imágenes jpeg, es necesario instalar exiftool para extraer los metadatos y luego hacer:

$ echo ‘*.jpeg diff=exif’ » .gitattributes
$ git config diff.exif.textconv exiftool

Procesar archivos antes de hacer commit y antes de hacer checkout: Es posible crear tus propios filtros para hacer sustitución. Estos filtros se llaman smudge y clean. Los puedes configurar para distintos directorios y luego escribir un script que procesará cada archivo antes de que sea checkeado (smudge) y commiteado (clean). Para ello,escribe en el .gitattributes: (En caso que quieras procesar código C)

*.c filter=indent Luego:

  • git config --global filter.indent.clean indent
  • git config --global filter.indent.smudge cat

Otro ejemplo interesante es la expansión de la palabra clave $Date$. Para ello hay que escribir un script en ruby que recibe un archivo, encuentra la fecha de su último commit e inserta dicha fecha en el archivo:

#! /usr/bin/env ruby
data = STDIN.read
last_date = `git log --pretty=format:"%ad" -1`
puts data.gsub('$Date$', '$Date: ' + last_date.to_s + '$')

Puedes nombrar este script como expand_date. Crea un filtro en git, llamado dater y dile que use el script anterior:

  • git config filter.dater.smudge expand_date
  • git config filter.dater.clean 'perl -pe "s/\\\$Date[^\\\$]*\\\$/\\\$Date\\\$/"'

Para usar el filtro, simplemente escribe la palabra clave en los archivos que desees:

echo '# $Date$' > date_test.txt
echo 'date.txt filter=dater' » .gitattributes

git add date_test.txt .gitattributes
git commit -m "Testing date expansion in Git"
rm date_test.txt
git checkout date_test.txt
cat date_test.txt
$Date: Tue Apr 21 07:26:52 2009 -0700$

GIT HOOKS

Hay dos tipos”), de lado cliente y servidor, se guardan en el directorio .git/hooks. Para activarlos basta con que sean ejecutables.

CONCEPTOS

Fast forward: cuando se hace un merge y el commit de la rama a mezclar esta justo un commit adelantado, simplemente se hace apuntar la rama en la que se iba a mezclar al commit del merge.

GITIGNORE:

*.a # no .a files
*!lib.a # but do track lib.a, even though you’re ignoring .a files above
/TODO # only ignore the root TODO file, not subdir/TODO*
build/ # ignore all files in the build/ directory*
doc/*.txt # ignore doc/notes.txt, but not doc/server/arch.txt

FRIKADAS: Controla el navegador con tu mente

03/11/2017
Artículo original

Cuando el desarrollador israelí Uri Shaked vio hace unos meses un casco de medición de ondas cerebrales no pudo resistirse a hackearlo para conseguir enlazarlo a su medio preferido: la web.

Estos dispositivos utilizan la Electro-Encefalografía o EEG para medir y monitorizar la actividad eléctrica del cerebro. Básicamente lo que hacen es colocar unos cuantos electrodos lo más pegados posible a tu cuero cabelludo y mediante los mismos miden las débiles señales eléctricas que genera el cerebro al trabajar, que fluctúan en función de lo que estés haciendo.

En concreto, Uri utilizó un modelo comercial de medidor de EEG llamado Muse que se vende por unos 250 dólares y que está enfocado según sus creadores a ayudarte a relajarte y meditar, pero que en realidad es un producto robusto de EEG, para ser dirigido al consumidor final y no a profesionales.

El dispositivo viene con una aplicación para iOS o Android con la cual se comunica mediante Bluetooth, e incluso tiene un kit de desarrollo, aunque solo es válido para aplicaciones móviles nativas. Pero Uri quería aplicarlo a la web, y permitir que sus usuarios pudieran controlar una aplicación con el pensamiento a través del aparato.

Su primera intención fue hacer ingeniería inversa del protocolo (como de hecho ya consiguió con otros dispositivos en el pasado), pero al final encontró una biblioteca Open Source en Python que ya lo había conseguido antes que él, así que esa parte se la ahorró.

Lo primero que hizo fue conectar el dispositivo mediante Bluetooth al navegador y empezar a leer la información de los 8 electrodos que tienen los cascos EEG de Muse, graficando la señal:

Para ello hizo uso de RxJS, la biblioteca JavaScript de RectiveX.io,  especialmente diseñada para la gestión de flujos intensos de datos entre otras muchas cosas de programación asíncrona y funcional.

Aunque como primer paso está muy bien y es muy interesante, es algo de poca utilidad práctica más allá de ver unas gráficas con mediciones que te acabarán aburriendo al cabo de un rato, así que tenía que ir más allá.

El siguiente paso sería utilizar esta información para hacer algo útil con ella, como por ejemplo poder controlar el navegador con la mente a través de los electrodos.

Por suerte su novia es optometrista y le habló de una técnica denominada electro-oculografía.  Esta técnica permite medir la actividad ocular a través de la diferencia de potencial de los ojos, que tienen una carga positiva hacia la parte delantera y una negativa en la trasera. Dado que el Muse tiene dos electrodos muy cercanos a la zona ocular, podría utilizarlos para medir esta actividad y detectar así los pestañeos y guiños de los ojos.

Para hacer una historia larga, corta, esto es lo que consiguió:

Con su aplicación es posible detectar el movimiento de los ojos lo cual, aparte de la frikada en sí, puede tener muchísimas utilidades. Por ejemplo, imagínate lo mucho que puede hacer por personas inmovilizadas que, al menos podrían comunicarse aunque fuese de forma lenta y con un coste muy reducido comparado con las alternativas. Además esto solo ha explorado la superficie de lo que se puede hacer. Seguramente analizando bien los datos de los demás electrodos y adaptándolos a cada caso concreto se podrían conseguir aplicaciones más complejas.

Este tipo de dispositivos eran imposibles de conseguir fuera de los ámbitos profesional hace tan solo unos años, y los precios eran prohibitivos. En la actualidad no solo disponemos de éstos, sino también una gran variedad de dispositivos y sensores que eran impensables a principios de siglo (o sea, hace nada). Y esto abre un mundo de posibilidades para crear proyectos interesantes como este, con mucho potencial de ayudar a las personas.

¿Qué opinas? ¿Se te ocurre alguna otra aplicación práctica de esto? En el artículo original de Uri tienes todos los detalles de cómo lo hizo.

Ganar dinero con Marketing de Afiliados – +100K

01/11/2017
Artículo original

Espero y este post sea de tu agrado, no olvides compartirlo en su redes sociales y sobre todo.. Gracias por seguirnos!

¿Quieres ganar dinero por Internet? ¿Tienes un blog o te gustaría tener uno? Apuesto a que despues de leer este post querrás hacer uno, te mostraré como he ganado más de 100, 000 MXN con este blog y como tu puedes hacer lo mismo.. ganar dinero con marketing de afiliados o afiliación. En este blog suelo monetizar con marketing de afiliados por lo que se de lo que hablo cuando te digo que es una excelente forma de ganar dinero por Internet con un blog. Hace poco llegue a obtener más de 100,000 MXN en ganancias gracias a esta forma

Compartir en Facebook

Comparte en Google Plus

Compartir en Twitter

El post Ganar dinero con Marketing de Afiliados – +100K aparece en el Blog de Jonathan Melgoza

Mostrar artículos similares usando Clustering con sklearn

31/10/2017
Artículo original

Hace un tiempo quería mostrar artículos similares / relacionados al final de cada artículo de este blog. Al momento de plantear este problema, Hugo no tenía soporte para esta característica, hoy día sí. Para ello decidí implementar mi propio sistema usando python, sklearn y Clustering.

Agrupando artículos similares

Diseño del programa

Leer y Parsear los artículos

Ya que escribo tanto en Inglés y Español, necesito entrenar el modelo dos veces, para poder mostrar artículos relacionados en inglés a los lectores ingleses, y en Castellano a los Hispanos. La función readPosts se encarga de esto. Recibe como argumentos el directorio donde se encuentran los artículos, y un booleano indicando si quiero leer los escritos en inglés o castellano.

dfEng = readPosts('blog/content/post',
                  english=True)
dfEs = readPosts('blog/content/post',
                 english=False)

Dentro de esta función (puedes consultarla en mi github), leo los artículos y devuelvo un Data Frame de Pandas. Lo más relevante que hace esta función es seleccionar el parser correcto, para abrir los ficheros usando el parseador de yaml o el de TOML. Una vez leido el frontmatter, readPosts crea el DataFrame usando estos metadatos. En concreto solo se queda con estos:

tags = ('title', 'tags', 'introduction', 'description')

Lo cual significa, que usaremos esta información para clasificar los posts.

Selección del Modelo

Como dije al principio, decidí usar Clustering. Ya que estoy tratando con datos de texto, necesito una forma de convertir esta información a forma numérica. Para conseguirlo se usa una técnica llamada TF-IDF (Term frequency – Inverse document frequency). No entraré en los detalles, pero daré una pequeña introducción.

¿Qué es TF-IDF? (frecuencia de término – frecuencia inversa de documento)

Cuando se trabaja con datos de texto, muchas palabras aparecen muchas veces en distintos ducumentos pertenecientes a distintas clases, dichas palabras no suelen contener información discriminatoria. TF-IDF se encarga de rebajar el peso que tienen estos términos en los datos, para que no influyan en la clasificación.

tf-idf se define como el producto de:

  • Frecuencia del término. Número de veces que aparece el término en el documento.
  • Frecuencia Inversa de Documento. Cuanta información proporciona el término teniendo en cuenta el resto de documentos, es decir, si el término es frecuente o no en el resto de documentos.

Al multiplicar ambos, obtenemos el tf-idf, citando Wikipedia:

Un peso alto en tf-idf se alcanza con una elevada frecuencia de término (en el documento dado) y una pequeña frecuencia de ocurrencia del término en la colección completa de documentos. Como el cociente dentro de la función logaritmo del idf es siempre mayor o igual que 1, el valor del idf (y del tf-idf) es mayor o igual que 0. Cuando un término aparece en muchos documentos, el cociente dentro del logaritmo se acerca a 1, ofreciendo un valor de idf y de tf-idf cercano a 0.

En resumen, conforme más común es un término entre todos los documentos, menor será el valor tf-idf, lo cual indica que esa palabra no es importante para la clasificación.

Hiperparámetros

Para seleccionar los parámetros apropiados para el modelo he usado el método GridSearchCV de sklearn, puedes verlo en la línea 425 del código.

Limpiando los datos

Con el método a usar (clustering) y teniendo los datos de texto en formato numérico (TF-IDF), ahora toca limpiar los datos. Cuando se trabaja con datos de texto, es muy frecuente eliminar lo que se denominan stop words, palabras que no añaden significado alguno (el, la, los, con, a, eso...). Para ello creo la función generateTfIdfVectorizer. Esta misma función se encarga de realizar el stemming. De Wikipedia, Stemming es el proceso de:

reducir una palabra a su raíz o (en inglés) a un stem.

Dependiendo de en qué idioma esté generando los artículos relacionados (inglés o Castellano) uso:

def tokenizer_snowball(text):
    stemmer = SnowballStemmer("spanish")
    return [stemmer.stem(word) for word in text.split()
            if word not in stop]

para Castellano o

def tokenizer_porter(text):
    porter = PorterStemmer()
    return [porter.stem(word) for word in text.split()
            if word not in stop]

para inglés.

Tras este proceso, finalmente tengo todos los datos listos para aplicar clustering.

Clustering

He usado KMeans para realizar el clustering. La mayor carga de trabajo de este proceso era limpiar los datos, así que este paso es sencillo de programar. Solo es necesario saber cuantos clusters debería tener. Para ello he usado un método llamado Elbow Method (El método del codo). Sirve para hacernos una idea del valor óptimo de k (Cuantos clusters). El metodo nos indica cuando la distorsión entre clusters empieza a aumentar rápidamente. Se muestra mejor con una imagen:

Elbow method
En este ejemplo, se aprecia un codo en k=12

Tras ejecutar el modelo, usando 16 características, estas son las seleccionadas para Catellano:

[u'andro', u'comand', u'curs', u'dat', u'desarroll',
u'funcion', u'googl', u'jav', u'libr', u'linux',
u'program', u'python', u'recurs', u'script',
u'segur', u'wordpress']

y para inglés:

[u'blogs', u'chang', u'channels', u'curat', u'error',
u'fil', u'gento',u'howt', u'list', u'lists', u'podcasts',
u'python', u'scal', u'scienc', u'script', u'youtub']

Cómo intregrar el resultado con Hugo

Esta parte me llevó bastante tiempo ya que es necesario leer el resultado del modelo, en formato CSV, y mostrar 10 artículos del mismo cluster. Aunque ya no estoy usando este método (ahora uso el propio de Hugo), lo dejo por aquí como referencia:

{{ $url := string (delimit (slice "static/" "labels." .Lang ".csv" ) "") }}
{{ $sep := "," }}
{{ $file := string .File.LogicalName }}

{{/* First iterate thought csv to get post cluster */}}
{{ range $i, $r := getCSV $sep $url }}
   {{ if in $r (string $file) }}
       {{ $.Scratch.Set "cluster" (index . 1) }}
   {{ end }}
{{ end }}

{{ $cluster := $.Scratch.Get "cluster" }}

{{/* loop csv again to store post in the same cluster */}}
{{ range $i, $r := getCSV $sep $url }}
    {{ if in $r (string $cluster) }}
        {{ $.Scratch.Add "posts" (slice $r) }}
    {{ end }}
{{ end }}

{{ $post := $.Scratch.Get "posts" }}

{{/* Finally, show 5 randomly related posts */}}
{{ if gt (len $post) 1 }}
    <h1>{{T "related" }}</h1>
    <ul>
    {{ range first 5 (shuffle $post) }}
        <li><a id="related-post"  {{ printf "href=%q" ($.Ref (index . 2)) | safeHTMLAttr }} {{ printf "title=%q" (index . 3) | safeHTMLAttr }}>{{ index . 3 }}</a></li>
    {{ end }}
    </ul>
{{ end }}

Si tienes algún comentario, o quiere mejorar algo, comenta abajo.

Referencias

Cómo concatenar subconsultas en un solo campo con SQL Server

31/10/2017
Artículo original

Vamos a ver con un ejemplo de qué modo podemos solucionar una situación común que se da en bases de datos.

Imaginemos que tenemos dos tablas relacionadas entre sí. La primera contiene datos de productos (su nombre, descripción, precio, etc...). La segunda es una tabla de categorías a las que pueden pertenecer los productos. Como un producto puede estar en más de una categoría a la vez, existe una tercera tabla que relaciona a las dos anteriores.

El ejemplo, por supuesto, podría ser con cualquier otro tipo de tablas y datos, pero con este tan sencillo ilustraremos bien nuestro caso.

Para visualizarlo mejor vamos a pintar una representación sencilla de estas tres tablas y sus relaciones:

Relaciones entre las tablas

Y estos son algunos datos de prueba en ellas:

Datos de prueba en las tablas

Como vemos, algunos productos están en más de una categoría. Por ejemplo, el yogur está en lácteos y postres, y la leche está en esos dos y además en bebidas.

Podemos obtener un listado con todos los productos y sus categorías usando una consulta de tipo INNER JOIN entre ambas tablas, por ejemplo esta:

SELECT Productos.Nombre, Categorias.Categoria
FROM Categorias INNER JOIN
  ProductosCategorias ON Categorias.idCategoria = ProductosCategorias.idCategoria INNER JOIN
  Productos ON ProductosCategorias.idProducto = Productos.idProducto

Lo cual nos devuelve el siguiente listado:

Nombre Categoria
Queso Lacteos
Queso Postres
Pan Alimentos básicos
Yogur Lacteos
Yogur Postres
Leche Bebidas
Leche Lacteos
Leche Alimentos básicos


Donde vemos cada producto y sus categorías.

El problema de esta consulta es que es un producto cartesiano, por lo tanto nos devuelve un registro por cada categoría del producto, es decir, si un producto está en tres categorías tenemos tres registros para el mismo producto como resultado de la consulta (mira por ejemplo la leche al final).

Por supuesto podríamos efectuar una agrupación y contar a cuántas categorías pertenece cada producto, pero si queremos ver cuáles son específicamente, entonces necesitamos tener varias veces el mismo producto en los resultados.

Pero ¿qué pasa si necesitamos tener en un solo campo todas las categorías de cada producto agrupadas y listas para usar?...

Es decir, algo como esto:

Nombre Categorias
Queso Lacteos, Postres
Pan Alimentos básicos
Yogur Lacteos, Postres
Leche Bebidas, Lacteos, Alimentos básicos


Donde solo tenemos una fila por cada producto, y un nuevo campo ficticio llamado Categorias que contiene todas las categorías separadas por una simple coma.

Vamos a ver cómo conseguirlo paso a paso...

1.- Subconsulta para obtener las categorías

Lo primero que vamos a ver es cómo podemos obtener, para un producto dado, todas las categorías a las que este pertenece. En realidad ya sabemos hacerlo a partir de la consulta anterior, quedándonos solo con la parte de las tablas de categorías y la intermedia, y metiendo un filtro por el identificador del producto, así:

SELECT Categorias.Categoria
FROM Categorias
INNER JOIN ProductosCategorias ON ProductosCategorias.idCategoria = Categorias.idCategoria
WHERE ProductosCategorias.idProducto = 4

En este caso obtenemos todas las categorías del producto 4, o sea, la leche. Nos devuelve tres líneas de resultados, una por cada categoría.

Pero ¿cómo podemos hacer para que en lugar de 3 líneas como ahora, nos devuelva todas las categorías concatenadas en una sola cadena de texto?

2.- La conversión a XML que nunca lo fue

Desde SQL Server 2005 existe una característica integrada en su lenguaje de consultas T-SQL que sirve para obtener resultados en formato XML. Se trata de la cláusula FOR XML.

Ésta permite obtener un único campo como respuesta de una consulta que contiene una representación en XML de los datos devueltos por ésta. Por ejemplo, si a la consulta anterior le añadimos un FOR XML AUTO, así:

SELECT Categorias.Categoria
FROM Categorias
INNER JOIN ProductosCategorias ON ProductosCategorias.idCategoria = Categorias.idCategoria
WHERE ProductosCategorias.idProducto = 4
FOR XML AUTO

Obtendremos este resultado:

<Categorias Categoria="Bebidas"/>
<Categorias Categoria="Lacteos"/>
<Categorias Categoria="Alimentos básicos"/>

Como vemos devuelve los registros con el nombre de la tabla como nodo XML y un atributo con el nombre del campo para el resultado.

Esta cláusula tiene diversas variantes que cambian la forma del XML devuelto. Una de ellas, la que nos interesa, es FOR XML PATH que permite especificar qué elemento queremos usar para rodear a los resultados anteriores. Es decir, el nodo raíz. Además, tiene otra particularidad: si un campo que devolvamos no tiene nombre, lo devuelve tal cual, como un valor dentro del XML, ya que no tiene forma de ponerle un atributo o un nodo para rodearlo (FOR XML AUTO no permite campos sin nombre en el resultado).

¿Cómo conseguimos un campo sin nombre? Pues simplemente cualquier campo calculado al que no le asignemos uno con AS, será sin nombre. Así, basta por ejemplo con concatenar una cadena vacía a un campo para que deje de tener nombre:

Campo sin nombre

Bien. Entonces, teniendo en cuenta estas dos cosas, ¿cómo conseguimos concatenar el valor del campo, por ejemplo, separándolo con comas?

Pues usando un campo sin nombre y no rodeando al XML con nodo alguno, así:

SELECT ', ' + Categorias.Categoria
FROM Categorias
INNER JOIN ProductosCategorias ON ProductosCategorias.idCategoria = Categorias.idCategoria
WHERE ProductosCategorias.idProducto = 4
FOR XML PATH ('')

Que nos devuelve un resultado XML que en realidad no es XML ya que obtenemos:

, Bebidas, Lacteos, Alimentos básicos

Como vemos esto es casi lo que queríamos: le sobra la coma inicial.

3.- Librarnos de la coma inicial

Vale. Ya tenemos casi lo que necesitamos, pero nos sobra esa coma del principio. Por suerte es muy fácil librarse de ella gracias a una función específica de T-SQL denominada STUFF.

Esta función inserta una cadena dentro de otra. Elimina una longitud determinada de caracteres de la primera cadena a partir de la posición de inicio y, a continuación, inserta la segunda cadena en la primera, en la posición de inicio.

Es decir, en una cadena, a partir de la posición que le digamos, elimina los caracteres que le indiquemos y luego mete en ese lugar la cadena que queramos. Es como quitar e insertar por el medio, o sea, rellenar (que es el significado de la palabra stuff en inglés).

Por ejemplo, esta expresión:

SELECT STUFF('Pericardio', 5, 5, 'pl')

lo que hace es ir a la posición 5 (la "c" de "cardio"), eliminar 5 caracteres (o sea, "cardi"), y luego meter entre esa posición y lo que reste la cadena "pl". Con ello el resultado que obtenemos es la palabra:

Periplo

que aprovecha la "o" final.

En el caso que nos ocupa, por tanto, eliminar la coma y el espacio en blanco inicial es muy sencillo: se eliminan los dos primeros caracteres y se "inserta" una cadena vacía, así:

STUFF(Cadena, 1, 2, '')

Que si lo llevamos a la consulta anterior que devolvía las categorías en una cadena, es:

SELECT STUFF(
    (SELECT ', ' + Categorias.Categoria
    FROM Categorias
    INNER JOIN ProductosCategorias ON ProductosCategorias.idCategoria = Categorias.idCategoria
    WHERE ProductosCategorias.idProducto = 4
    FOR XML PATH ('')),
1,2, '')

Obteniendo:

Bebidas, Lacteos, Alimentos básicos

Ya sin esa coma y espacio en blanco iniciales.

4.- Ahora todo junto

Ahora que ya sabemos cómo obtener los datos concatenados en una cadena solo resta mezclar eso con la consulta original, en la que queríamos obtener las categorías de cada producto. Esto es muy fácil de conseguir ahora simplemente metiendo la consulta que acabamos de crear como sub-consulta de la principal y asignándole un nombre. La cosa quedaría así:

SELECT Productos.Nombre, 
 STUFF(
    (SELECT ', '  + Categorias.Categoria
    FROM Categorias
    INNER JOIN ProductosCategorias ON ProductosCategorias.idCategoria = Categorias.idCategoria
    WHERE ProductosCategorias.idProducto = Productos.idProducto
    FOR XML PATH('')),
    1, 2, '') As Categorias
FROM Productos

Como vemos, es una simple consulta que devuelve dos campos, siendo el segundo de ellos una sub-consulta que genera la lista de categorías de cada producto a partir de su identificador (ahora en el WHERE en lugar de poner un valor constante usamos el valor del campo idProducto de la consulta principal).

Con esto conseguimos exactamente lo que necesitábamos y veremos este resultado:

Nombre Categorias
Queso Lacteos, Postres
Pan Alimentos básicos
Yogur Lacteos, Postres
Leche Bebidas, Lacteos, Alimentos básicos


¡Listo!

En conclusión

Esta técnica tiene multitud de aplicaciones prácticas, que van más allá del ejemplo que acabamos de hacer.

En el rendimiento no tiene demasiado impacto, salvo quizá si concatenamos enormes cantidades de datos para obtener una gran cadena.

Si observamos el plan de ejecución de la primera consulta que hace el producto cartesiano:

Plan ejecución consulta inicial

Y el plan de ejecución de la consulta final:

Plan ejecución consulta final

Vemos que son muy parecidos, y además se sabe que la concatenación con FOR XML PATH tiene un impacto muy pequeño pues está muy optimizada por el motor de datos.

Una cosa importante a tener en cuenta: si el contenido de los textos que concatenamos tiene caracteres propios de etiquetas HTML o XML, básicamente símbolos de menor y mayor (< o >) y el "et" o "ampersand" (&), éstos se devolverán codificados como HTML, es decir, como &lt;, &gt; y &amp;. El motivo es que lo que se está devolviendo es XML (aunque no lo parezca) y los datos deben ir correctamente codificados. Esto de hecho puede ser muy útil si estamos en una aplicación web, ya que no tendremos ni que codificarlos para mostrarlos. Pero si puede suponer un problema debemos tenerlo en cuenta en la aplicación que haga uso de los datos devueltos y volver a codificarlos con los caracteres iniciales.

Si lo deseas te puedes bajar (ZIP, 3KB) la pequeña base de datos de ejemplo que he utilizado para este artículo, junto con un archivo con las diferentes consultas utilizadas de modo que puedas probarlo con más facilidad.

¡Espero que te resulte útil!

Porqué, para qué, cuándo y cómo migrar al Cloud computing

29/10/2017
Artículo original

Camino a la Nube

Tanto entre mis alumnos, como en las conversaciones con otros compañeros del sector, percibo siempre la duda de la necesidad o conveniencia de migrar al Cloud. Y, ciertamente, no es algo sencillo de explicar.

Muchas veces se generan intensos debates sobre si es una moda, una técnica comercial de las multinacionales para “sacarnos los cuartos” o un camino irresistible al que mejor no presentar una excesiva resistencia.

Por ello, en este artículo quiero resumir los orígenes, razones, procesos y características de los diferentes senderos que deberé recorrer para desplegar mis aplicaciones y servicios en la Nube.

El Porqué de migrar a la nube

Porque

Tengo muy claro -al iniciar el camino hacia el Cloud- que el principal motor para abordar los costes y esfuerzos debe ser un modelo de negocio claro, donde la adopción de la Nube se signifique como un mecanismo para incrementar la productividad. Es decir: al Cloud se va a ganar dinero.

No es buena idea que aborde el aprovecharme de las posibilidades de una infraestructura a la que tendré acceso, si el coste por su uso no es cubierto por un incremento de beneficios o la optimización de los costes.

La pregunta no es porqué, realmente es cúando.

Debo tener en cuenta que, desplegando mis servicios en estas plataformas, me hago beneficiario de precios que solamente se pueden alcanzar en Economía a Escala. Es decir, cuando se habla de adquirir millones o centenas de millones de servidores, está claro que el precio unitario de compra, mantenimiento y operación está muy por debajo de lo que yo podría conseguir en el mercado general. Y esa contención de los costes, se revierte en precios de consumo del Cloud cada vez más bajos y competitivos.

La alta disponibilidad, la escalabilidad y la resiliencia, son otras ventajas que emergen de estas plataformas mastodónticas, en donde la disponibilidad de recursos es virtualmente infinita (el límite lo pone mi nivel adquisitivo). Cubriendo las necesidades de la práctica totalidad de los casos de uso, al disponer de la capacidad de replicar cualquier servicio, infraestructura o aplicación que quiera publicar en el Cloud, tantas veces que sea necesario para asegurar niveles de acuerdo de servicio superiores al 99,99%, en cualquier zona geográfica del mundo.

Otra característica que solamente me ofrece este tipo de plataformas es que la inversión en adquisición, puesta en marcha y crecimiento de mis servicios, es muy inferior a la que tendría que enfrentar en el caso de querer hacerlo con mi propio “hierro”.

Aun, incluso, cuando a medio/largo plazo los costes de instalación, administración, mantenimiento y actualización tanto del software como del hardware, puedan llegar a ser similares; a corto plazo (menos de dos años), la Nube es imbatible en los costes de operación, inicio nuevos servicios, o abordar el crecimiento (ya sea imprevisto, constante, puntual, o periódico).

Tampoco son baladí las inversiones asociadas para logar un acceso mundial a mis aplicaciones; lo que implica una formidable complejidad técnica y una barrera de entrada, muchas veces insalvable, a nuevos mercados o al crecimiento empresarial. El Cloud, sin embargo, es por naturaleza de ámbito mundial. Siendo, gracias a la redundancia permanente, la plataforma perfecta para publicaciones geo replicadas con acceso vía Web.

El duopolio de facto existente (Amazon 48% - Azure 10%) produce el recelo de poner "todos los huevos en la misma cesta"

Por último, y no por ello menos importante, las plataformas de Nube liberan de la creciente necesidad de formación, experiencia y conocimiento que se requiere para administrar y evolucionar sistemas informáticos tan complejos como los actuales. Los tiempos del administrador para todo, han quedado atrás. Y el coste de sostener una creciente plantilla que debe estar en formación permanente, no siempre es viable económicamente. Por ello, el delegar estas responsabilidades al Cloud, con los diferentes niveles basados en los tres tipos principales de “sabores” (IaaS, PaaS y SaaS), y el ahorro de costes asociados en personal especializado (sea de plantillas o externo), es otra causa de plantearme la migración de los servicios.

Para qué migrar a la nube

Questions

Aunque me repita, el objetivo último de adoptar el Cloud computing es el incrementar los beneficios de la empresa a corto y medio plazo, por medio de la optimización de los costes:

  • Disponibilidad del servicio. La mayoría de los negocios se apoyan firmemente en servicios publicados en Internet y/o en aplicaciones/herramientas. De hecho, aún demasiado pocos son plenamente conscientes de lo dependientes que somos de las Tecnologías de la Información hasta que falla algún sistema, o deja de estar disponible. Y este es uno de los objetivos más importantes que se buscan al irse a la Nube: la importancia de tener mi “sistema informático” permanentemente disponible; lo cual gana en criticidad según el impacto que genera en el negocio cada vez que se sufre una incidencia. Llegando incluso, a significar el cierre de la empresa, si la interrupción es lo suficientemente prolongada o crítica.
  • Simplificar. Todo lo relacionado con la informática va ganando complejidad según la tecnología y la propia industria va incrementado su madurez (aún es muy joven). El hardware, el software y las herramientas que se crean con ello, son cada vez más numerosas y complejas. Llegando a ser inmantenibles, insostenibles y desconocidas. El concepto de KISS, gana en importancia, y hacer más sencillo las gestiones de los recursos TI se convierte en imprescindible. Así desde el propio concepto de Infraestructura como Servicios, hasta el Software como Servicio, el Cloud ofrece una salida para mitigar la complejidad y su crecimiento.
  • Seguridad. Esa es otra preocupación con la que se debe bregar desde el entorno empresarial, por las consecuencias legales y de negocio que ocasionan. Estamos inmersos en la metáfora de “El cañón contra el escudo”, en una verdadera guerra armamentística en el ciberespacio. Y dónde los conocimientos necesarios, en renovación constante y permanente sobre seguridad informática, están atesorados por un número muy limitado de profesionales. Rara es la empresa que puede tener un departamento o personal dedicado en exclusiva a proteger sus sistemas de los llamado cyber-ataques. Así, delegando en el Cloud obtendré acuerdos de seguridad del servicio, con una fracción de la inversión que implicaría subcontratar estos trabajos a empresas externas, o formar mi propio personal.
  • Pago por uso. Curiosamente el mayor coste de una infraestructura sobre la que publicar mis servicios, nos es tanto la adquisición, mantenimiento y evolución de la misma, si no la amortización de todas las capacidades que no se utilizan y que deben ser adquiridas igualmente. Por ejemplo, capacidades de cálculo (procesadores y placas madre), memoria (RAM), y almacenamiento que adquiero sobre dimensionadas, para poder soportar picos de trabajo o crecimiento previsto, y que no se utilizan durante largos periodos de tiempo. En Cloud se paga por lo que se usa. Si crezco, el coste es mayor porque estoy consumiendo más recursos para generar más negocio, pero la diferencia la marca la capacidad de reducir la escala, consumiendo menos, y dejando de pagar por aquellos recursos que ya no necesito. Siendo esto una operación con un gran impacto en el ahorro de costes de operación.
  • Costes laborales. La simplificación de la plataforma sobre la que funcionan las aplicaciones significa que delego en la Nube la adquisición, instalación, administración, mantenimiento y evolución del hardware y el software – dependiendo del nivel de abstracción de los servicios. Lo que significa una importante reducción de los costes laborales, al liberar ciertos perfiles profesionales de estas tareas. Por ejemplo, no necesitaría tener personal de guardia por si una fuente de alimentación falla.

Cuándo lanzarse a la nube

Calendar

Podría decir que la mejor respuesta es cuanto antes, pero en realidad hay múltiples factores a tomar en cuenta para iniciar el camino hacia el Cloud.

Lo primero que debo de asegurar es que el sistema, infraestructura o aplicaciones que quiero publicar en la Nube, sea un sistema estable. Es decir, es un error pensar que un servicio que sufre errores funciona mal o de forma impredecible, va a estabilizarse por irse al Cloud. No solamente no es así, sino que los problemas se pueden hacer aún más complejos y difíciles de resolver, impactando directamente en la operatividad.

Otra cosa que debo de mitigar al máximo es la resistencia al cambio que toda organización va a presentar. Desde los profesionales que ven peligrar sus funciones, el usuario final que está acostumbrado a hacer las cosas desde dentro de su zona de confort, hasta el directivo que se resiste a que los datos salgan de debajo de su mesa. Mientras esta resistencia no deje de ser un problema bloqueante, el forzar el cambio solamente añade riesgos de fracaso.

Los grandes centros de Cloud atráen el talento y experiencia de los mejores. Hay en marcha una nueva transformación de los puestos de trabajo

El equipo debe estar formado en los procesos de migración, o ser acompañado por consultores con experiencia real y conocimiento profundo del Cloud de destino. El tamaño y número de servicios que ofrecen las Nubes actuales está en continuo incremento, y se necesita “tenerlos por la mano” para poder tomar las decisiones arquitectónicas, de procesos y tecnología sobre las que vamos a construir nuestros servicios.

También las propias circunstancias del negocio me pueden indicar que es el momento del salto. Así podría ser indicio claro el que tenga un bloqueo en el crecimiento (principalmente a causa de los costes de inversión necesarios); o estar por debajo del nivel crítico de disponibilidad y resiliencia en los servicios, que pueda poder en riesgo la viabilidad de la empresa; o que deba abordar complejos y caros procesos de certificación de calidad, seguridad o procesos; o que por fin caiga en cuenta que el sitio más endeble e inseguro para almacenar los datos es debajo de mi mesa.

Aunque, en mi experiencia, casi siempre el pistoletazo de salida proviene de la percepción y conocimiento, por parte del personal técnico, de las ventajas económicas y operativas de la Nube. Transmitiendo a Dirección las ventajas en la relación servicios/costes que ofrece la plataforma.

Cómo hacerlo

Obed Na Mrakodrape Top

Una vez que tenga claro que el Cloud es mi destino, hay que empezar por lo más básico: una valoración del nivel de madurez de nuestra plataforma actual para, en conjunto con negocio y tecnología, definir cuáles serían las aplicaciones y servicios que podríamos desplegar.

La primera clasificación, por cada una de ellas, es el esfuerzo que hay que realizar, y que se podría categorizar así:

  • Migración. Muy orientada a IaaS, o máquinas virtuales, en donde despliego los servicios en un entorno tan similar al original, que no tengo que realizar casi ningún cambio. Esta es la forma más sencilla de irme al Cloud, pero también es la que más coste por servicio soporta.
  • Transformación. Ya sea como Infraestructura o Plataforma, mis servicios van a requerir ser modificados en mayor o menor medida para ajustarse a las características de la Nube. Un ejemplo es tener que cambiar la forma en que trabajo con los ficheros, al adoptar una cuenta de almacenamiento de Blob en vez de una Carpeta en el Sistema de ficheros. Esto requiere transformación a nivel de código, que será más o menos costosa de acuerdo con la deuda técnica con que me encuentre.
  • Reconstrucción. Hay casos en que la transformación exige tantos cambios y tan profundos que puede ser más interesante económicamente y de forma práctica el reconstruir el servicio desde cero o casi. Esto puede suceder si queremos irnos a la versión PaaS o SaaS del Cloud, o aprovecharnos de las capacidades de los servicios serveless, o implantar las arquitecturas de aplicaciones Cloud más correctas (bus de mensajes, cqrs, key Vault, etc.).
  • Por último, y no menos importante, decidir no migrar. Aquellas aplicaciones en donde el coste no compense los beneficios de la adopción del Cloud, no deben ser migradas. Como ejemplo típico, es aquella aplicación que funciona sobre Windows XP utilizando drivers hechos a medida y que reproducirlos en un entorno virtual sería difícil y costoso. O aquella aplicación realizada sobre Excel, que su reconstrucción sería inabordable.

El siguiente paso que realizar, una vez definido si el proyecto de migración tiene sentido y es el momento oportuno para abordarlo, es el realizar pilotos de migración. Esta aproximación tiene un coste muy pequeño (solo se paga por lo que se usa) y permite formarse en los conocimientos necesarios para realizar las transformaciones o reconstrucciones que van a aparecer durante la migración. Tengo que tener muy presente que me voy a enfrentar a las diferencias tanto en la Infraestructura, Sistemas, Telecomunicaciones, Desarrollo de software, Seguridad, etc., en comparación con mi plataforma actual. A lo que he de añadir que, cuanto más alto es el nivel de abstracción, más “específicos” son los cambios y de más calado.

Pero si no mido, no podré saber si la plataforma Cloud está bien configurada o mis servicios y aplicaciones funcionan correctamente. Es más, debo definir qué significa “funciona correctamente” o “mejora”, estableciendo el conjunto de métricas y KPI’s que monitorizar, y cuáles son los valores nominales en donde se deben de mantener.

La paciencia es un requisito imprescindible para llevar a buen puerto un complejo proyecto de migración.

Qué pruebas funcionales, de carga, experiencia de usuario o rendimiento se deben realizar; cuales serán automáticas; cómo se van a reportar; y en que prioridad ejecutar las acciones correctivas. Y cuáles son los valores esperados y aceptables.

Por supuesto hay que definir un marco financiero que limite el gasto a valores sostenibles. Pero evitando caer en la falacia de obtener un presupuesto basado en una estimación de las horas y costes previstos; porque en este tipo de migraciones los riesgos, mutabilidad y volatibilidad de las operaciones fuerzan un rango de incertidumbre demasiado amplío para ser útil.

Por ello, es crítico saber el volumen de inversión que estoy dispuesto a asumir; cuales son los puntos de fallo, retorno y no retorno; y las acciones de refinanciación o mitigación de los costes extraordinarios, si los hubiera. Es decir, realizar una gestión de riesgos económicos.

Por último, hay que tener paciencia. Son operaciones técnicas con ramificaciones e implicaciones en todo el negocio. Por lo cual el dicho de “las prisas nunca son buenas consejeras” hay que aplicarlo a rajatabla, e ir cubriendo todos los pasos de forma confiable para llevar a buen término el piloto (primero), y luego las migraciones a producción.

Desventajas

No

Sin duda no existe ninguna tecnología que no tenga desventajas; y la Nube no iba a ser diferente.

Una de las mayores resistencias aparece cuando nos damos cuenta de que nos convertimos en un cliente cautivo, en donde tenemos una dependencia bastante alta con el proveedor. Es decir, si nos decidimos por los servicios de Amazon, no es transparente ni sencillo el irnos el día de mañana a Azure, o volverlos a traer a nuestra infraestructura privada.

Han cambiado las reglas del juego. Ahora, cualquier pequeña empresa puede posicionar sus servicios en Cloud con una inversión inicial mínima

Al revés, cuanto más abstracta es nuestra plataforma (PaaS o SaaS) más encadenados estamos al proveedor y a su tecnología. Llevándolo a su límite en servicios como Lambdas o Serveless, o las plataformas de publicación de arquitecturas de microservicios. Añadiendo que el límite de nuestros servicios lo impondrá el límite de lo que puede hacerse con el Cloud elegido.

Y aquí tenemos otra desventaja: de facto en la actualidad vivimos un duopolio com Amazon AWS y Microsoft Azure. Es cierto que existen Google y otras Cloud, pero realmente la voz cantante la lleva AWS con casi el 48% del mercado, seguido por Azure con poco más del 10%, y Google con apenas un 3%.

También, como transmito durante todo el artículo, hay que asumir importantes costes monetarios, pero también en horas/hombre, en esfuerzo, en formación y en transformación de la propia empresa. No es el proceso más crítico y complejo al que se enfrentan las empresas, pero no es un proceso sencillo, transparente y barato.

Aquí habría que incluir el impacto en la paz laboral de la empresa. Cloud genera recelos y rechazo en los perfiles técnicos orientados a la administración de sistemas; siendo la decisión de migrar al Cloud causas de conflictos, resistencias al cambio, o transformaciones en la fuerza laboral.

Conclusión

Conclusion

No hay otro camino, ya sea de forma privada, híbrida o en Cloud pública, las ventajas de adoptar la Nube como plataforma sobre la que construir servicios son irrefutables. Y soy de la opinión de que no tiene vuelta atrás.

Creamos en ello o no, vivimos en un mundo hiperconectado, global y público. En dónde el concepto de ventaja competitiva hace emerger grandes corporaciones y destruye a otras, en ciclos tan cortos que ningún economista hubiera creído posible hace unas pocas décadas.

Y donde la Nube es casi una obligación a causa del cambio en profundidad las reglas del juego que significa el dar acceso universal a servicios del mayor nivel y calidad, anteriormente reservados a las empresas con abultados presupuestos económicos.

Hoy en día, basado en Cloud, montar una Startup o un negocio clásico con unos costes mínimos de TI ya no es una entelequia, es una realidad que se observa en el día a día.

Lo cual me lleva a la conclusión de que la pregunta realmente a contestar es: ¿Cuándo?

También te recomendamos

¿Quieres llevarte un LG G6? Haz clic para saber cómo participar

Cloud9 Un IDE en la nube

Google lanza PerfKit ¿Cómo evaluar el rendimiento real de las plataformas en la nube?

-
La noticia Porqué, para qué, cuándo y cómo migrar al Cloud computing fue publicada originalmente en Genbeta Dev por Juan Quijano .

Criptografía 101: Fundamentos matemáticos (I)

28/10/2017
Artículo original

Aritmética modular

Antes de profundizar en los temas sobre criptografía, es necesario tener una base matemática, ya que al fin y al cabo, la criptografía se basa en ellas.

Nos centraremos en la aritmética modular, y cómo operar con ella. La aritmética modular se define del siguiente modo:

\[a \equiv b\pmod n,\]

si \(b - a\) es múltiplo de \(n\) o, dicho de otro modo, \(a\) y \(b\) tienen el mismo resto cuando se dividen por \(n\).

Así, por ejemplo, \(3 \equiv 8 \pmod 5\), ya que \(8 - 3 = 5\), que es un multiplo de 5. También podemos comprobarlo sabiendo que el resto de dividir 3 entre 5 es 3 y el resto de 8 entre 5, también. A partir de ahora expresaremos el resto de dividir un número entre otro como sigue:

\[a\bmod n = r,\]

donde \(r\) es el resto de dividir \(a\) entre \(n\).

Modular Arithmetics

Cálculo de inversos

Sea \(a \in \mathbb Z_n\), se dice que \(a\) tiene inverso, o que es una unidad, si \(\exists b \in \mathbb Z_n\ :\ ba = 1\), y se denota por \(a^{-1}\).

Al conjunto de todas las unidades de \(\mathbb Z_n\) lo llamaremos \(\mathcal{U}(\mathbb Z_n)\) y se define como:

\[\mathcal{U}(\mathbb Z_n) = \{ a \in \mathbb Z_n : \exists a^{-1}\} = \{ a \in \mathbb Z_n : gcd(a, n) = 1\},\]

donde gcd es el máximo común divisor.

Particularmente, si \(p\) es un número primo, todo elemento de \(\mathbb Z_p\), salvo el cero, tiene inverso, y por tanto \(\mathbb Z_p\) es un cuerpo. En criptografía, trabajaremos en cuerpos \(\mathbb Z_p\) con un \(p\) primo.

El número de unidades de \(\mathbb Z_n\), se puede calcular con la función de Euler \(\phi(n)\), y vale lo siguiente:

  • Si \(p\) es un número primo, \(\phi(p) = p - 1\), ya que todos los elementos salvo el 0, son unidades.
  • Sean a, b, dos números enteros \( \phi(ab) = \phi(a)\phi(b)\ sii\ gcd(a, b) = 1\).
  • Sea \(p\) un primo, \(\phi(p^n) = p^n - p^{n-1}\).

Por ejemplo, \(\#\mathcal{U}(\mathbb Z_5) = 4\), ya que todos sus elementos tienen inverso (el 1,2,3,4), y \(\phi(5) = 4\), y por tanto, \(\mathbb Z_5\) es un cuerpo. Sin embargo, \(\#\mathcal{U}(\mathbb Z_{15}) = 8\), ya que \(\phi(15) = \phi(3)\phi(5) = 2\cdot 4 = 8\). Las unidades de \(\mathbb Z_{15}\) son 1,2,4,7,8,11,13,14.

Un ejemplo práctico

Veamos ahora cómo calcular el inverso de un número en \(\mathbb Z_n\) mediante el algoritmo Extendido de Euclides implementado en python, el código fuente está disponible en github:

def extGcd(a,b):
    """
    Compute the Greatest Common Divisor d of a and b, and integers x and
    y satisfying ax + by = d.

    :returns: a tuple (d,x,y)
    """

    if b == 0:
        return a,1,0
    x2 = 1
    x1 = 0
    y2 = 0
    y1 = 1

    while b != 0:
        q = a//b
        r = a - q * b
        x = x2 - q * x1
        y = y2 - q * y1
        a = b
        b = r
        x2 = x1
        x1 = x
        y2 = y1
        y1 = y

    if a < 0:
        return map(int, (-a, -x2, -y2))
    return map(int, (a, x2, y2))

Este algoritmo, devuelve una tupla (d, x, y), donde d es el máximo común divisor de los números a,b y x es el inverso de a mod b. Por ejemplo, si ejecutamos gcd(2, 5), nos devolverá [1, -2, 1], donde 1 es el gcd(2, 5), y \(-2\) su inverso, si lo queremos en positivo, basta con sumar 5 a \(-2\), que es 3, luego el inverso de 2 mod 5 es 3, ya que \(2 \cdot 3 = 6\), y 6 mod 5 = 1.

Para facilitar la tarea de calcular el inverso de un número, definiremos el siguiente método, el código fuente está disponible en github:

def moduloInverse(a,n):
    """:returns: the inverse of a modulo b, if it exists"""
    d,x,y = extGcd(a,n)

    if d > 1:
        return u' a inverse does not exist'
    else:
        return x % n

Si lo ejecutamos con los mismos números de antes, 2 y 5, nos devolverá \(2^{-1}\), es decir, 3.

Agradecimientos

Gracias a josealberto4444 por ayudarme con correcciones.

Referencias

Todo el código mostrado en los artículos está disponible en github

Apuntes de la asignatura criptografía del profesor Jesús García Miranda, Escuela Técnica Superior de Ingenierías Informática y de Telecomunicación (ETSIIT), Granada.

Más información

Página Anterior Página Siguiente