Feb 26 2010

Bash completion for symfony (autocomplete)

tatai

I have just pushed into GitHub a bash autocomplete script for symfony.

This script allows to autocomplete your first level option when calling to symfony script. It is easy to install (just copy one and call it manually if you do not have access rights). All steps and working issues are in the wiki. It also accepts custom actions.

This is a working example once script is corretly installed and invoked:

Assuming symfony is in current folder and [tab] y tab key press action, this is an example of how symfony_complete works:

$ ./symfony con[tab]figure:[tab][tab]
author    database
$ ./symfony doctrine:a[tab]uthor

We are pleased to know what you think and any issue you have. You can find us on GitHub.

Related links:


Feb 11 2010

XHP: una extensión para escribir PHP de forma distinta

tatai

Una de las noticias de esta semana en el mundo PHP es sin duda toda la información acerca de HipHop for PHP por parte del equipo de desarrollo de Facebook. Una de las extensiones que ha salido a la luz por parte del equipo de front-end es la que han llamado XHP y, como ellos mismos rezan, “a new way to write PHP” (una nueva forma de escribir PHP).

La explicación de cómo funciona es muy sencilla. Intentan evitar que al desarrollar la parte de frontal, cuando nos “pegamos” con el XHTML, tengamos que unir código XHTML y PHP. En el ejemplo que muestran se ve más claramente.

De un código como:

<?php
if ($_POST['name']) {
?>
    <span>Hello, <?=$_POST['name']?>.</span>
<?php
} else {
?>
    <form method="post">
    What is your name?<br>
    <input type="text" name="name">
    <input type="submit">
    </form>
<?php
}

Nos da como opción generar este otro:

<?php
// note: includes omitted
if ($_POST['name']) {
  echo <span>Hello, {$_POST['name']}</span>;
} else {
  echo
    <form method="post">
      What is your name?<br />
      <input type="text" name="name" />
      <input type="submit" />
    </form>;
}

No voy a negar que, de primeras, XHP parece más sencillo de seguir y de generar. Eliminar los tags de apertura y cierra de PHP aligera el código en gran medida. Además, eliminamos problemas con el XSS así como detectar problemas por malformación de XHTML en tiempo de parsing.

A mi personalmente me sigue gustando bastante más usar un motor de plantillas. Un motor real como XTemplates (sí, he dicho XTemplates, no smarty o similares). Separar el código PHP del HTML me parece bastante importante y necesito verlo con más claridad.

No obstante, hay que seguir el tema de cerca. Si es algo que la gente de Facebook ha visto que es necesario ya que aumenta el rendimiento, es evidente que en este tipo de entornos será uno de los puntos de referencia. Sin embargo, XHP como técnica para el resto de las webs donde no se reciban tantas peticiones como Facebook (si no recuerdo mal, sirven más doscientas mil millones de páginas al mes, sí, sí, 200.000.000.000), es posible que un objetivo que cumpla a primera vista es juntar el PHP con el HTML, algo que, repito, me parece bastante “sucio” si no hay una justificación clara. Pos supuesto, un motor de plantillas tiene sus desventajas, no vamos a negarlo :)

Lo dicho, XHP de momento me parece algo que puede provocar que el código sea más rápido pero a costa de hacerlo más guarro. Habrá que seguirle la pista para ver por dónde avanza, no lo descarto de primeras porque el objetivo de aumentar el rendimiento es muy importante, pero analizando el coste (ni monetario ni de recursos en este caso, jeje).

Enlaces:

Update: Muy muy muy interesante lo que comenta Rasmus en su web. Importante verlo.


Oct 21 2009

Trabajando con eficiencia

tatai

Muchas veces considero que es una obsesión, pero de lo que estoy seguro es que muchas más veces gano tiempo pensando un poco y haciendo las cosas mejor y más rápidas.

El caso que voy a presentar ahora es lo que yo considero “la forma más rápida de descargarnos un dump de una base de datos”. Añadamos como condición que tenemos que usar un protocolo cifrado, en este caso, SSL. Para cualquier de los dos ejemplos que voy a presentar, contamos que tenemos autentificación en el servidor remoto (ahora que sabemos cómo hacerlo).

Empecemos por el final. Cómo se nos ocurriría hacerlo directamente. Básicamente los pasos serían estos:

# Nos conectamos al servidor
ssh user@server.com
# Realizamos el dump de la base de datos
mysqldump -u mysqluser -p mysqldb > dump.sql
# Comprimimos los datos para reducir el tamaño de los datos a trasferir
gzip dump.sql
# Volvemos a nuestro ordenador
exit
# Copiamos el fichero a nuestro ordenador
scp user@server.com:dump.sql.gz .

He hecho una prueba con una base de datos pequeña. Si únicamente contabilizamos el tiempo en realizar cada uno de estos comandos y los sumamos (es decir, no tenemos en cuenta ni el ssh inicial ni los tiempos entre comandos, incluído si nos vamos a tomar un café mientras hace el volcado o lo comprime), salen los siguientes tiempos:

  • mysqldump: 2.2 segundos
  • gzip: 0.5 segundos
  • scp: 12.2 segundos
  • total método 1: 14.9 segundos

Veamos ahora otra forma. ¿Y cómo es? Pues bien sencilla… ¿y si te digo que puedes agrupar todos los comandos en únicamente uno?

¿Cómo? Pues aprovechando que se pueden ejecutar comandos de forma remota con el comando ssh y que lo que devuelva ese comando, se retorna mediante la consola estándar (stdin). Además, teniendo en cuenta que también podemos llamar a gzip en línea mediante una tubería (denominada en inglés pipe, representada por la barra vertical: |). Si unimos todo esto, nuestro comando queda (ejecutado directamente desde nuestra máquina):

ssh user@server.com "mysqldump -u mysqluser -p mysqldb | gzip" > dump.sql.gz

Si medimos el tiempo que le cuesta a este comando obtenemos para el método 2: 12.0 segundos

La diferencia puede parecer muy pequeña vista así, pero estamos hablando que es casi un 20% más rápido. Si este proceso (con el primer método) hubiese durado 4 horas (sí, os aseguro que se puede dar el caso), en algo más de 3 horas lo habríais terminado. Estos datos son muy variables, hay que tener en cuenta muchas cosas, pero que hagáis las pruebas que hagáis, en igualdad de condiciones, este nuevo método es mucho más rápido.

Y os aseguro que si hacéis la prueba con un proceso largo, en el que tendríais que esperar que terminase cada paso para iniciar el siguiente comando, ganaréis mucho tiempo sobre todo entre comando y comando.

La próxima vez que os toque algo como esto, usad este método y tomaros el café (o la comida) que os podréis tomar gracias a no tener que esperar, a mi salud.

Pensad un poco, esto es sólo un ejemplo, ¡hay muchas más opciones!


Oct 5 2009

Cuenta atrás/Countdown para mootools

tatai

Es posible que en la pasada Navarparty 7 participases en el concurso Date El Bit y te encontraras con que este año la primera fase de las preguntas se realizaba pregunta por pregunta y había una cuenta atrás para cada una de ellas.

Pantalla de ejemplo de Date El Bit de la Navarparty 7

Pantalla de ejemplo para Date El Bit de la Navarparty 7

Pues bien, para poder hacerla realicé una pequeña clase en javascript para Mootools que me permitiera poder visualizar la cuenta atrás que se puede ver en la imagen. Como estuve buscando por internet y no encontré nada que me gustase, me lancé a hacerlo, no podían ser muchas líneas.

Y así ha sido. Con tan sólo 98 líneas (incluídos comentarios en inglés), tengo el gusto de presentar la clase Countdown.

Esta clase tiene como objetivo realizar la cuenta atrás visualmente actualizando un elemento DOM que se le indique.

El ejemplo de utilización más sencillo es este, que nos crea una cuenta atrás de 10 a 0 en pasos de hasta 100 milisegundos que actualiza en el elemento con id=”counter”:

new Countdown($('counter')).start();

Podemos completarlo un poco más con el siguiente ejemplo:

new Countdown($('counter'), {
  'decimals' : '3', // para hacer que parezca un tiempo de la fórmula 1 :p
  'onComplete' : function() {alert('finalizado!');}, // muestra un alert cuando acaba la cuenta atrás
  'onStep' : function(target, show) {
    // Si el contador está por debajo de 5, poner en rojo, si no, en negro
    if(show < 5) {
      target.setStyle('color', '#f00');
    }
    else {
      target.setStyle('color', '#000');
    }
  }
});

Oct 2 2009

Una forma sencilla de hacer bien las cosas

tatai

Para romper este “silencio” de casi un mes debido a la Navarparty y al trabajo, volvamos a la carga con un pequeño post.

Quiero tratar el tema de “cómo hacer bien las cosas programando” con un sencillo ejemplo que pasó el otro día por mis manos. Y para ello contaremos con dos actores, un array y un if. Supongamos que tenemos los siguientes datos:

$a = array
  array('from' => 0, 'to' => 100),
  array('from' => 101, 'to' => 250),
  array('from' => 250, 'to' => 1000),
  array('from' => 1001, 'to' => 2000)
);

Nuestro sencillo código va a retornar el índice del array $a en el que se encuentra un número $b. Ahora bien, tenemos dos formas de hacerlo:

Opción a:

function getRange($b) {
  foreach($a AS $index => $actual) {
    if($actual['from'] <= $b && $actual['to'] >= $b) {
      return $index;
    }
  }
}

Opción b:

function getRange($b) {
  foreach($a AS $index => $actual) {
    if($actual['to'] >= $b && $actual['from'] <= $b) {
      return $index;
    }
  }
}

El único cambio es el if que, como se puede ver, cambia el orden de las condiciones.

Entonces, hacemos la pregunta, ¿cuál de las dos opciones es más eficiente? Es posible que no lo veas claro, pero si lo miras un poco veras como en la mayoría de los casos es la opción b. Únicamente son igual de eficientes cuando $b se encuentra entre los valores de la primera posición.

¿Y por qué es más eficiente la opción b? La respuesta es porque dentro del if, al tener un Y lógico (los dos ampersands &&) si la primera condición es falsa, la otra condición ni siquiera se evalúa. Es decir, nos ahorramos que el microprocesador tenga que hacer esa comprobación lógica. Y este caso se da si pensamos que $b = 150. Para la opción a el if tiene que ejecutar ambas condiciones (0 <= 150 && 100 >= 150) para descubrir que es false y pasar a la siguiente iteración, mientras que con la opción b bastaría con la primera comprobación (100 >= 150) para saber que es false y pasar a la siguiente iteración.

Si se hace este if una única vez estamos hablando de una parte muy pequeña de un segundo, pero si esta tarea es muy repetitiva o el array tiene muchas posiciones, el efecto es claramente favorable e incluso se puede notar directamente.

Este sencillo ejemplo demuestra como pensar un poco las cosas y cambios muy pequeños en tu código pueden hacer que tengas un código mucho más optimizado y que te de mayor rendimiento.

Y por si quieres rizar el rizo, la opción a puede ser más eficiente que la b, pero sólo en el caso de que se recorra el array de forma descendente o este ordenado de forma inversa.


Ago 26 2009

TestSwarm. Integración contínua distribuida en Javascript

tatai

Acabo de leer el post de John Resig sobre TestSwarm, un nuevo proyecto, todavía en fase alpha de Mozilla Corporation, que permite realizar test de código Javascript en diversos navegadores y varias plataformas de forma distribuida. Esto quiere decir que cuando se pone un script a evaluar en esta plataforma, se ejecuta en varios navegadores a la vez, permitiendo extraer posteriormente los resultados.

El siguiente dibujo extraído de la web de John Resig se muestra la arquitectura:

Arquitectura de TestSwarm

Arquitectura de TestSwarm

El video la verdad es que impresiona. En él se puede ver cómo ejecuta un test y, poco a poco, van apareciendo resultados.

http://www.vimeo.com/6281121

Hay que seguir este proyecto de cerca. Las posibilidades que puede darnos a la hora de realizar integración contínua en nuestros proyectos también en javascript (sólo jQuery, al menos en lo que se ve de momento), es enorme. Muy muy muy interesante.

John Resig es conocido por ser Javascript Evangelist en Mozilla Corporation aunque actualmente está en el equipos Javascript Tool Developer. Es conocido también por participar como desarrollador en el proyecto One Laptor Per Child.


Ago 22 2009

Mis expresiones regulares favoritas

tatai

A raíz de mi post anterior sobre 5 expresiones regulares que todo programador web debería conocer, me ha parecido interesante añadir unas cuantas más que, aunque quizás no sean nada del otro mundo, me parecen muy útiles y seguro que ayudan a más de uno.

Validar un número entero

Esta es realmente sencilla y muy muy útil, sobre todo si trabajar con cadenas de texto o lenguajes de programación no tipados. En PHP hay por ejemplo funciones como is_number() que hacen una función parecida.

Comprueba si todos caracteres del string son dígitos.

/^\d+$/

O, de forma equivalente:

/^[0-9]+$/

Atentos que la cadena vacía no pasa esta expresión, es necesario que haya al menos un dígito. Si quieres permitir que esté vacío, entonces cambia el + por *.

Validar un número decimal

Esta es una extensión la anterior. Acepta tanto número positivos como negativos y que el separador de decimales sea coma o punto:

/^-?[0-9]+([,\.][0-9]*)?$/

Validar opciones de entrada

Aunque no siempre, viene muy bien cuando tenemos unos cuantos parámetros y no queremos usar if($a == ‘a’ || $a == ‘b’ || $a == ‘c’) y todo lo largo que queráis el if.

La siguiente expresión comprueba si la variable es a,  b, c, otro o mas:

/^(a|b|c|otro|mas)$/

En PHP, con un preg_match, la papeleta está solucionada. Por ejemplo:

if(!preg_match('/^(a|b|c|otro|mas)$/', $a) {
  // Si entra es que no hay coincidencias
  return null;
}

Tras estas líneas, $a es sólo una de las opciones indicada y si no, habrá retornado null.

Extraer cierta parte de un texto

Partiendo de que tenemos una cadena de caracteres en $text y sabemos que en alguna parte suya cumple que tiene una cadena de texto (por ejemplo ‘jugador’) y un número separados por un guión (es decir, por ejemplo ‘jugador-15′) y queremos conocer ese número porque es su identificador. Podemos usar:

preg_match('/player-(\d+)/', $text, $matches);
$id = $matches[1];

Tras estas líneas, en $id tenemos nuestro número.

Esta expresión se puede extender todavía un poco más si el texto a buscar lo tenemos en una variable, por ejemplo $buscar.

En PHP podemos hacer:

preg_match('/' . $buscar . '-(\d+)/', $text, $matches);
$id = $matches[1];

Si estás usando javascript, el equivalente para este último caso es:

var buscar = 'player';
var m = texto.match(new RegExp(buscar + '-(\d+)'));
var id = m[1];

Y hasta aquí da mi memoria de momento. Cuando me acuerde de alguna otra, ya las iremos posteando.


Ago 22 2009

5 expresiones regulares que todo programador web debería conocer

tatai

Extraigo de I’m Mike un artículo bastante interesante 5 expresiones regulares (también llamadas regexp) que deberías conocer si eres programador web.

Bien es sabido por los que me conocen que considero las expresiones regulares como uno de los mejores método que se han inventado para los programadores (y en general, para cualquier persona que quiera comprobar si una cadena de caracteres cumple ciertas características y posibilidades). Como definió @acidonitrix en su momento: en todas las empresas hay algún loco que le encantan las expresiones regulares; pues bien, ¡ese es mi caso! (Ya me lo haré mirar algún día, pero de momento no molesta)

Pues bien, las 5 expresiones que Mike comenta son las siguientes

Comprobar un nombre de usuario

Esta es la más sencilla de todas. Comprueba si el nombre de usuario está compuesto únicamente por letras, mayúsculas o minúsculas, números de 0 a 9 o el guión bajo (underscore) y cuya longitud total sea entre 3 y 16 caracteres.

/^[a-zA-Z0-9_]{3,16}$/

Buscar una etiqueta HTML/XHTML

Partiendo del ejemplo de querer buscar la etiqueta tag aquí coincido con Mike en que la mejor forma (de las varias y farragosas que existen) es usar lo que se denomina un “cuantificador vago” (lazy quantifier) para obtener todo el contenido de la etiqueta.

/<tag[^>]*>(.*?)<\/tag>/

Existen otras soluciones, pero ninguna tan directa como esta. Podríamos buscar el contenido por [^>]*, pero eso nos obligaría a post-procesar el resultado ya que es posible que dentro de esa etiqueta tengamos otra.

Buscar una etiqueta HTML/XHTML con cierto atributo y valor en su interior

Esta expresión es algo más compleja y usa las referencias (matching backreference) que son los \\1 y \\2 para buscar el tag y la comilla o las dobles comillas que cierran el valor del atributo. Este truco también se podía haber usado antes, pero yo creo que queda más claro así.

Para este ejemplo, supongamos que se quiere buscar la etiqueta tag, el atributo attribute y el valor value:

/<tag[^>]*attribute\s*=\s*(["'])value\\2[^>]*>(.*?)<\/\\1>/

Cuando incluyáis esta regexp en PHP, tened cuidado en escapar una de las dos, según el carácter que uséis para crear la cadena de texto. Por ejemplo:

preg_match('/<tag[^>]*attribute\s*=\s*(["\'])value\\2[^>]*>(.*?)<\/\\1>/', $text, $matches)

Tengo que reconocer que esta expresión como esta no la he usado apenas. Las veces que he tenido que buscar algún atributo, solía ser más de uno o más complejo que una simple asignación y, partiendo del ejemplo anterior, el de buscar una etiqueta HTML/XHTML, procesaba el resultado.

Comprobar una dirección de correo electrónico

Esto ya son palabras mayores. La solución que se plantea, dada por Cal Henderson, cumple con la RFC 822 que define cómo son las direcciones de correo electrónico. Poco más se puede añadir, no hay nada más completo:

function is_valid_email_address($email){
  $qtext = '[^\\x0d\\x22\\x5c\\x80-\\xff]';
  $dtext = '[^\\x0d\\x5b-\\x5d\\x80-\\xff]';
  $atom = '[^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c'.
                  '\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+';
  $quoted_pair = '\\x5c[\\x00-\\x7f]';
  $domain_literal = "\\x5b($dtext|$quoted_pair)*\\x5d";
  $quoted_string = "\\x22($qtext|$quoted_pair)*\\x22";
  $domain_ref = $atom;
  $sub_domain = "($domain_ref|$domain_literal)";
  $word = "($atom|$quoted_string)";
  $domain = "$sub_domain(\\x2e$sub_domain)*";
  $local_part = "$word(\\x2e$word)*";
  $addr_spec = "$local_part\\x40$domain";

  return preg_match("!^$addr_spec$!", $email) ? 1 : 0;
}

Comprabando una URL

En mi sincera opinión, crear una regla genérica para comprobar una URL es un berenjenal horrible. Hace falta realizar alguna particularización. Seguidamente os pongo el código de I’m Mike.

{
  \\b
  # Match the leading part (proto://hostname, or just hostname)
  (
    # http://, or https:// leading part
    (https?)://[-\\w]+(\\.\\w[-\\w]*)+
  |
    # or, try to find a hostname with more specific sub-expression
    (?i: [a-z0-9] (?:[-a-z0-9]*[a-z0-9])? \\. )+ # sub domains
    # Now ending .com, etc. For these, require lowercase
    (?-i: com\\b
        | edu\\b
        | biz\\b
        | gov\\b
        | in(?:t|fo)\\b # .int or .info
        | mil\\b
        | net\\b
        | org\\b
        | [a-z][a-z]\\.[a-z][a-z]\\b # two-letter country code
    )
  )

  # Allow an optional port number
  ( : \\d+ )?

  # The rest of the URL is optional, and begins with /
  (
    /
    # The rest are heuristics for what seems to work well
    [^.!,?;"\\'<>()\[\]\{\}\s\x7F-\\xFF]*
    (
      [.!,?]+ [^.!,?;"\\'<>()\\[\\]\{\\}\s\\x7F-\\xFF]+
    )*
  )?
}ix

Como se puede comprobar es realmente una tarea complicada y, aunque esta regexp funciona bastante bien para la amplia mayoría de casos, hay TLD que se deja como por ejemplo .name, .travel, etc.

Y de momento dejo el post aquí, ya que tengo en marcha otro sobre expresiones regulares que llegará en breve.

Update: ya tengo mi propio post sobre expresiones regulares


Ago 13 2009

Euskal Encounter 17

tatai

Ya es bien conocido que del pasado 23 al 26 de julio se celebró la Euskal Encounter 17 en el BEC! de Bilbao. Otro año más, y ya son unos cuantos, tuve la suerte de poder asistir rodeado de buenos colegas. Por un problema u otro no pudieron estar todos los habituales, pero aprovechamos todo lo que se pudo.

Hay poco que decir de la Euskal Encounter a estas alturas. Todo perfecto. Me recuerda a la Navarparty (risa malévola). La red funcionó bien en todo momento, al igual que la conexión a internet, menos un par de cortes puntuales y totalmente perdonables que se solucionaron en cuestión de segundos. Muchas competiciones de todo tipo, de las llamadas oficiales, extraoficiales y un sin fin de pequeñas competiciones que animaban mucho el ambiente. Incluido un ImproveEverywhere basado en una grabación MP3 como ya hemos podido ver unos cuantos por ahí.

Además, este año decidimos ir Garath y yo, junto con la gente de DiarioLinux a jugar a un laser tag! Nos lo pasamos en grande y descargamos un poco de adrenalina. Jugamos dos batallas, en la primera estuvimos 15 personas y 10 en la segunda. En Pamplona hace ya unos años estaba el famoso Qzar que ya desapareció, aunque donde estuvimos tenía que ser de la misma casa. Me esperaba que la partida fuese más cara, pero por 6 euros podías jugar 20 minutos, no estuvo nada mal. Si me dicen de ir el año que viene, repetiré.

Y bueno, este año por fin, tras varios de sequía, hemos conseguido algunos premios con los que nos volvimos contentos para casa. En particular, un tercer puesto en el Hack-it de mano principalmente de Ontza, dueño y señor de la prueba en nuestro grupo al que ayudamos en lo que buenamente pudimos cada uno. La prueba estuvo muy reñida en todo momento y hay que reconocer la gran labor de Ontza que, participando de forma individual, consigió este magnífico tercer puesto (y 150 euros que no vienen nada mal).

Y no puedo dejar pasar (que no quepo de gozo en mi), también logramos un segundo puesto en la prueba de FOSS Coding que me llevé yo personalmente. Se trataba de una prueba de programación rápida (24 horas) al que me presenté de forma individual (se podía también en grupos de 2, 3 ó 4 personas) y tras darle algunas vueltas decidí presentarme y probar suerte ya que no esperaba demasiado ya que apenas estuve programando 6 ó 7 horas. Pero tuve la suerte de no presentar código incompleto, error que cometieron otros grupos y así llevarme una magnífica GP2x Wiz, tarjeta de 4GB y accesorios varios. Estoy esperando a ver si publican los código y así ver qué otros códigos se presentaron, incluyendo el primer premio que tuvieron que repartir entre los dos componentes del grupo.

Y he aquí a los ganadores del FOSS Coding de la Euskal Encounter 17

Y he aquí a los ganadores del FOSS Coding de la Euskal Encounter 17

Y volvimos contentos. Algunos todavía más, jeje. Con la entrada amortizada, unos muy buenos ratos pasados en compañía de buenos colegas, esperaremos a la llegada de la Navarparty.


Jun 20 2009

Teclas rápidas usando mootools

tatai

Hace unos días me plantee la posibilidad de añadir teclas rápidas al funcionamiento de la aplicación. Las teclas rápidas o también llamadas atajos de teclado (o “keyboard shortcuts” en inglés) nos permite realizar acciones pulsando una tecla o una combinación de teclas. Por ejemplo, habremos usado muchas veces Ctrl + g (o la variante inglés Ctrl + s) para grabar un documento, Ctrl + r para recargar la pantalla de nuestro navegador o, por ejemplo, todas las teclas rápidas de GMail. Lo que voy a explicar brevemente en este post es como conseguir algo parecido a lo que usa GMail.

El funcionamiento es realmente sencillo, este sería el código:

document.addEvent('keyup', function(e) {
    var bg = e.target.get('tag');
    if(bg == 'html' || bg == 'body') {
        if(e.key == 'a') {
            accion1();
        }
        else if(e.key == 's') {
            accion2();
        }
    }
});

Lo único que le falta a este código son las funciones accion1() y accion2() que son las que se ejecutarán cuando pulsemos las teclas a y s respectivamente.

Este código añade un evento ‘keyup’, es decir, cuando se detecta que se ha pulsado una tecla y estamos levantando el dedo de la tecla. Este evento indaga a ver qué tecla se ha pulsado y en caso de ser una de las de la lista, ejecutará la función correspondiente.

La comprobación de que el objetivo de nuestra pulsación (e.target) sea ‘html’ o ‘body’ sirve para que no se haga esta comprobación cuando estamos en un elemento como un input, un textarea, etc. Es decir, tenemos que tener el foco en el documento. En la mayoría de los navegadores funcionaría simplemente con indicar ‘html’, pero, como siempre, Internet Explorer tiene que dar la nota y necesita que comprobemos sobre ‘body’.

Por último añadir que podemos obtener más información del evento:

e.code: el código de la tecla pulsada
e.control: true si la tecla Ctrl está pulsada
e.shift: true si la tecla Shift está pulsada
e.alt: true si la tecla Alt está pulsada

Y no sólo esto, también podemos trabajar con la rueda del ratón o el botón derecho del ratón

El resultado es realmente espectacular si tienes que trabajar con una aplicación en la que las teclas rápidas te hacen la vida más sencilla :)