Archivo

Archivo para Junio, 2010

Actualizado stermp.h (getch(), getche() y kbhit() en Linux)

Miércoles, 30 de Junio de 2010 Gaspar Fernández 5 comentarios

Hace más de un año publiqué algunas funciones para manejar colores en la terminal de forma fácil. (Ver link). El objetivo era aprender un poco cómo funciona la terminal, y de paso ayudarme con mis alumnos de clases particulares (casi todos utilizan conio.h), yo quería una alternativa; por otra parte, facilitar el uso en proyectos pequeños, ya que si queremos algo más, para eso está ncurses.

Me he decidido sacar una segunda versión, ya que la primera no disponía de sustituto para getch() ni kbhit(), recordemos que estas funciones son para pedir un carácter desde teclado sin echo y sin necesidad de pulsar ENTER, y detectar la pulsación de una tecla sin parar la ejecución del programa respectivamente.

Tengo que avisar también de que este código no funciona con las flechas del teclado (estas teclas no tienen un carácter asociado y lo que hacen es devolver varios códigos de tecla, el primero de ellos ESC (27)), lo dejo para la próxima actualización.

También hay algunas correcciones, y algunas novedades internas.

Para descargar: stermp.h y stermp.c

Para compilar stermp (Simple Terminal Play):

$ gcc -c stermp.c

Para compilar nuestros proyectos:

$ gcc -o proyecto proyecto.c stermp.o

Y ahora un pequeño código de prueba:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <stdio.h>
#include <time.h>
#include "stermp.h"

void update_time()
{
  struct tm *tm;
  time_t _time;
  char texto[50];
  textcolor(YELLOW);
  _time=time(NULL);
  tm = localtime(&_time);
  strftime(texto,50,"%d/%m/%Y %H:%M:%S", tm);
  gotoxy(1,1);
  printf("%s    ", texto);
}

int main()
{
  int x,y;
  int ancho, alto;
  int tecla;
  term_init();
  ancho = screenwidth();
  alto = screenheight();

  /* Rellenamos de verde la pantalla */
  textbackground(GREEN);
  clrscr();

  textbackground(BLUE);
  /* Rellenamos de azul la primera fila */
  for (x=0; x<ancho; x++)
    printf(" ");

  gotoxy(1,alto);
  /* Rellenamos de azul la última fila */
  for (x=0; x<ancho; x++)
    printf(" ");

  gotoxy(2,2);
  while ((tecla=kbhit2())==0)
      update_time();    


  printf("Has pulsado: %d\n", tecla);

  term_defaults();
 
}

Sed… de venganza (1): Sustituyendo cadenas en múltiples archivos

Lunes, 28 de Junio de 2010 Gaspar Fernández 1 comentario

3846929292_60721fb24e

Es uno de los grandes desconocidos y tan temidos comandos de que disponemos. Y es cierto que a veces da pereza mirarse el manual cuando queremos hacer algo que sed podría hacer rápidamente.

Lo que cuento hoy es su uso más popular (porque sed se puede usar para muuuuuchas cosas) y es muy simple, sustituir en un stream un texto por otro (Donde dije digo, digo Diego).

Imaginemos un fichero de texto, para ser originales llamémosle README, y en el texto queremos cambiar la palabra “Ireland” por “Spain”. Podemos hacer lo siguiente:

$ sed ’s/Ireland/Spain/g’ README

y veremos en pantalla el texto. Para guardarlo en el mismo archivo, si buscamos por Internet, veremos cómo la gente se complica la vida (que no digo que sea malo, yo también me la complico un poco más abajo), pero podemos usar el modificador -i (que tiene algunas funciones curiosas).

Si ahora hacemos:

$ sed -i ’s/Ireland/Spain/g’ README

Los cambios se guardarán automáticamente en el fichero README. Pero si investigamos un poco más, y queremos rematar la faena podemos hacer:

$ sed -i~ ’s/Ireland/Spain/g’ README

En este caso, guardaremos el cambio en el fichero README y grabaremos en README~ una copia de seguridad del fichero antiguo. La extensión de la copia de seguridad podemos cambiarla haciendo por ejemplo:

$ sed -i.bak ’s/Ireland/Spain/g’ README

Para que la copia sea README.bak

Pero ahora viene algo interesante, con el parámetro -i podemos modificar todos los archivos que queramos, sed acepta en la entrada múltiples archivos, por lo que si en un directorio con muchos archivos queremos cambiar un texto (imaginad que habéis hecho un proyecto relativamente grande, y hay una función con un nombre un poco ridículo, curiosamente es la que más veces llamáis, y como vamos a enseñar el código fuente, no queremos que nadie lea eso), podremos hacer:

$ sed -i ’s/nombre_ridiculo/nombre_elegante/g’ *

Ahora bien, si el proyecto está en múltiples directorios, siempre podemos usar find para localizar los archivos de la siguiente forma:

find -name ‘*.c’ -exec sed -i ’s/nombre_ridiculo/nombre_elegante/g’ {} \;

Con toda esta línea, buscaremos todos los archivos con extensión .c dentro del directorio actual y subdirectorios y se los pasaremos a sed, con el modificador -exec de find, ejecutaremos el comando que especificamos, donde {} indica el nombre de archivo (que nos lo da find) y con \; indicamos el fin del comando y sus parametros.

Pero esto no termina aquí, sed soporta expresiones regulares, y si por ejemplo queremos coger todas las imágenes de un fichero html, cambiarlas de directorio y añadirles un class (inicialmente encontramos <img src=”foto.jpg” alt=”" /> , y queremos que salga <img class=”imagen” src=”/static/foto.jpg” alt=”" />) podemos hacer lo siguiente:

sed ’s/src=”\(.[a-zA-Z\.\_\/]*\)”/src=”\/static\/\1” class=”imagen”/g’ fichero.html

Lo que hay en negrita, corresponde a la expresión regular que determina el nombre del archivo (caracteres de la a a la z, de la A a la Z, puntos, guiones bajos, y barras (en la cadena de origen), en la cadena de destino escribimos \1 donde queremos que coloque el texto correspondiente a la expresión anterior, es decir donde queremos que coloque el nombre del archivo.

Ni que decir tiene que podemos hacer una mezcla de todo lo dicho en este post ( expresiones regulares, y sustitución en múltiples archivos dentro de múltiples subdirectorios y guardando backups ), y estaremos delante de una potente herramienta.

Lo malo de ejecutar sed, es que tenemos que escapar muchos caracteres,por lo menos ), (, ., \, / y seguro que encontramos alguno más; para ello, siempre que queramos introducir un carácter de esos, debemos poner una contra barra (\) delante.

Foto: albertopveiga (Flickr)

Sorteo: Camisetas geek gratis

Sábado, 26 de Junio de 2010 Gaspar Fernández Sin comentarios

Al principio hice un post copy-paste de la web, pero mira, ahora me lo voy a currar un poco más.

Desde Nosolounix nos presentan un curioso sorteo de camisetas geek. No hay que currar mucho, y podemos aprovechar para ver qué tal es el servicio de Ropageek.com.

Sólo tenemos que entrar aquí y seguir las instrucciones. Básicamente hay que vivir en España, escribir un comentario en ese mismo blog y enviar un mail diciendo tu nombre y qué camiseta quieres (habrá que entrar en la web para ver el catálogo).

p0065-there-s-no-place-like-127001Eso sí, el sorteo tiene una mecánica curiosa, aunque sólo podemos participar una vez (no es plan de hacerse mil cuentas de email y mandar un mensaje con cada una); podemos obtener más participaciones recomendando el concurso (lo que yo estoy haciendo ahora), trayendo amigos, publicándolo en twitter.

Seguro que encontramos la camiseta geek que siempre hemos querido tener, por participar que no quede! :) Por cierto yo he pedido una que dice: “There’s no place like 127.0.0.1″

Editado: a las 21:21 (Reescritura del post, quitando copy-paste)

Editado: 27/06/2010 01:53 (Añado una imagen)

Categories: General Tags: , , ,

Bailando con bits: Trabajando a nivel de bit II

Miércoles, 23 de Junio de 2010 Gaspar Fernández Sin comentarios

Hace unos días empecé con la serie Bailando con Bits (aunque llevaba escrito varios meses) trata de formas para trabajar a nivel de bit desde C.

Hoy voy a proponer otra forma, quizás menos intuitiva que la anterior, pero diferente. Esta vez no utilizaremos un registro enorme ni nada parecido, utilizaremos un mismo número entero para hacer el ejemplo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <stdio.h>

#define PESOBIT(bpos) 1<<bpos
#define COGEBIT(var,bpos) (var & PESOBIT(bpos))?1:0
#define PONE_1(var,bpos) var | PESOBIT(bpos)
#define PONE_0(var,bpos) var & ~(PESOBIT(bpos))
#define CAMBIA(var,bpos) var ^ PESOBIT(bpos)

int main()
{
  int numero;
  int i;

  numero=63;
  printf ("Numero: %d\n", numero);


  for (i=31; i>=0; i--)
    printf("%4d", i);

  printf("\n");

  for (i=31; i>=0; i--)
    printf("%4d",COGEBIT(numero,i));

  printf("\n");

  numero=PONE_1(numero, 17);
  numero=PONE_0(numero, 3);
  numero=CAMBIA(numero, 20);
  numero=CAMBIA(numero, 5);

  for (i=31; i>=0; i--)
    printf("%4d",COGEBIT(numero,i));

  printf("\nNúmero: %d\n", numero);

}

Ahora usamos varias macros que harán operaciones de bit con la variable a analizar (están definidas en la parte de arriba), tenemos PESOBIT, COGEBIT, PONE_1, PONE_0 y CAMBIA:

  • PESOBIT: Nos dice cuánto vale un bit con valor 1 en la posición especificada, por ejemplo en la posición 0 (LSB) vale 1, en la posición 1, vale 2, en la posición 3, vale 4, en la posición 4, vale 8…
  • COGEBIT: Nos dice si el bit en la posición bpos de la variable var vale 0 ó 1
  • PONE_1: Pone un 1 en el bit bpos de la variable var
  • PONE_0: Pone un 0 en el bit bpos de la variable var
  • CAMBIA: Cambia el valor (de 0 a 1 y viceversa) del bit en la posición bpos de la variable var

Como vemos en el ejemplo si queremos poner a 1 el bit 5 de numero, tendremos que hacer numero=PONE_1(numero,5), aunque en el siguiente ejemplo veremos cómo simplificar todo eso.

Con este ejemplo podemos jugar con los bits de números enteros. Pero, y si queremos utilizar otro tipo de variables? (aunque estamos limitados a 32bits) También tenemos este ejemplo con un tipo float:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <stdio.h>

#define PESOBIT(bpos) 1<<bpos
#define COGEBIT(var,bpos) (*(unsigned*)&var & PESOBIT(bpos))?1:0
#define PONE_1(var,bpos) *(unsigned*)&var |= PESOBIT(bpos)
#define PONE_0(var,bpos) *(unsigned*)&var &= ~(PESOBIT(bpos))
#define CAMBIA(var,bpos) *(unsigned*)&var ^= PESOBIT(bpos)

int main()
{
  float numero;

  int i;

  numero=63.2317;
  printf ("Numero: %f\n", numero);


  for (i=31; i>=0; i--)
    printf("%4d", i);

  printf("\n");

  for (i=31; i>=0; i--)
    printf("%4d",COGEBIT(numero,i));

  printf("\n");

  PONE_1(numero, 5);
  PONE_0(numero, 3);
  CAMBIA(numero, 20);
  CAMBIA(numero, 5);
  CAMBIA(numero, 31);

  for (i=31; i>=0; i--)
    printf("%4d",COGEBIT(numero,i));

  printf("\n");

  printf("\nNúmero: %f\n", numero);

}

En este caso no tenemos que hacer una variable igual a PONE_1(variable, 5) para poner su bit a 1; simplemente con PONE_1(variable, 5) nos vale. En este ejemplo podemos ver una variable de tipo float desglosada en bits y podemos modificar a nivel de bit para obtener otros valores. (No le veo mucha utilidad a esto, pero bueno).

Post dedicado a algm, por su comentario en el artículo Bailando con bits anterior.

Fibonacci recursivo en C [ intentemos no repetir operaciones! ]

Lunes, 21 de Junio de 2010 Gaspar Fernández Sin comentarios

fibo
Es un ejercicio muy típico cuando se está aprendiendo con funciones recursivas es la sucesión de Fibonacci, aquella en la que F(n)=F(n-1)+F(n-2).
Aunque esta técnica podemos (y deberíamos) utilizarla para una gran cantidad de algoritmos. A veces es necesario sacrificar un poco la memoria del sistema (sin pasarnos) para agilizar y hacer más rápido el programa. Debemos adoptar una solución que beneficie al usuario, no es plan de dejarlo sin memoria, pero tampoco es plan de que la solución se eternice.

Una primera implementación puede ser la siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int fibonacci_simple(int n)
{
  /* La función normal, recursiva */
  if (n>2)
    return fibonacci_simple(n-1) + fibonacci_simple(n-2);
  /* Este es el caso más común,  */
  else if (n==2)        /* Ponemos esto para agilizar un poco el proceso */
    return 1;
  else if (n==1)       
    return 1;
  else if (n==0)
    return 0;
  else
    return -1;          /* Error */
}

Si creamos un programa de ejemplo como este:

1
2
3
4
5
6
7
8
9
10
int main(int argc, char *argv[])
{
    unsigned int numero;

    /* Generamos Fibonaccis */
    for (numero=0; numero<48; numero++)
      printf("%u\n", fibonacci_simple(numero));

    return 0;
}

Podemos observar que para generar la secuencia de 48 números (he escogido este valor, porque a partir de ahí no tenemos suficiente de 32bits para almacenar el valor obtenido), tardamos varios minutos, en concreto, en mi equipo (Pentium M 1.73MHz), echó algo más de 10 minutos. ¡ 10 minutos ! Es un buen rato para lo que ha hecho.
Si lo estudiamos detenidamente (en negrita pongo las veces que llamamos a fibonacci_simple() sin necesidad):

  • fibonacci_simple(0)
  • fibonacci_simple(1)
  • fibonacci_simple(2)
  • fibonacci_simple(3) (que llama a fibonacci_simple(2) y fibonacci_simple(1) )
  • fibonacci_simple(4) (que llama a fibonacci_simple(3) ( que llama a fibonacci_simple(2) y fibonacci_simple(1) ) y a fibonacci_simple(2) )
  • fibonacci_simple(5) (que llama a fibonacci_simple(4) ( que llama a fibonacci_simple(3) ( que llama a fibonacci_simple(2) y fibonacci_simple(1) ) y a fibonacci_simple(2) ) y a fibonacci_simple(3) ( que llama a fibonacci_simple(2) y fibonacci_simple(1) )

Yo creo que con esto nos hacemos una idea de lo que quiero decir, se repiten demasiadas operaciones, seguro que hay alguna forma de solucionar esto.

Propongo lo siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
int fibonacci_buffer(int n)
{
  static int *fbuffer=NULL; /* Buffer */
  static int bufsize=0; /* Tamaño de buffer */
  int n3;           /* n-2 */
  int i;            /* Recorre buffers */

  if (n>2)
    {
      n3=n-2;
      if (fbuffer==NULL)
    {
      fbuffer = (int*) malloc((n3 * sizeof(int)));
      for (i=0; i<n3; i++)
        fbuffer[i]=0;   /* Ponemos buffer a 0 */

/*    printf("Creo buffer: %d -- %d\n", n3*sizeof(int), errno); */

      bufsize=n3;
    }
      else if (bufsize<n3)
    {
      fbuffer = (int*) realloc(fbuffer, n3 * sizeof(int));
/*    printf("Amplio buffer\n"); */

      for (i=bufsize; i<n3; i++) /* Ponemos a 0 la memoria nueva */
        fbuffer[i]=0;

      bufsize=n3;
    }
/*       printf("-%d--%d\n", n, fbuffer[n3-1]); */
      if (fbuffer[n3-1]!=0) /* Si se encuentra el fibonacci del número que buscamos  */
    return fbuffer[n3-1];   /* en memoria, lo devolvemos directamente */
      else
    {
      /* Si el fibonacci no se encuentra, vamos a generarlo */
      fbuffer[n3-1] = fibonacci_buffer(n-1) + fibonacci_buffer(n-2);
      //      printf("He generado con éxito fbuffer[%d]\n", n3-1);
      return fbuffer[n3-1];
    }

/*       return fibonacci_simple(n-1) + fibonacci_simple(n-2); */
    }
  else if (n==2)        /* Ponemos esto para agilizar un poco el proceso */
    return 1;
  else if (n==1)
    return 1;
  else if (n==0)
    return 0;
  else if (n==-1)       /* Un caso nuevo n==-1 */
    free(fbuffer);      /* Liberamos memoria */

  return -1;            /* Error */
}

Es algo más enrevesado, ya que usamos variables estáticas (podríamos hacer variables globales, con cuidado), así evitamos que la información que vamos almacenando se pierda entre ejecuciones de la función; por otra parte, utilizamos malloc() y realloc() para reservar sólo la memoria que vamos necesitando.
Por otra parte para reducir la memoria utilizada, hacemos que fibonacci(3) se almacene en la posición 0 del buffer (porque el de 2, 1 y 0, ya nos los sabemos); por otra parte… la variable n3 vale n-2; esto es simplemente porque si tenemos que calcular fibonacci(5), y sabemos que fibonacci(3) está almacenado en fbuffer[0], fibonacci(4) estará en fbuffer[1] y fibonacci(5) estará en fbuffer[2]; es decir tenemos que almacenar 3 valores de fibonacci (5-2=3).
Por otra parte, siempre que reservamos memoria ponemos los nuevos espacios a 0, ya que comprobamos que no hay ningún valor almacenado si éstos son 0.

Con el almacén de los números conseguimos que el esquema anterior se quede en:

  • fibonacci_buffer(0)
  • fibonacci_buffer(1)
  • fibonacci_buffer(2)
  • fibonacci_buffer(3) (que llama a fibonacci_buffer(2) y fibonacci_buffer(1)
  • fibonacci_buffer(4) (que llama a fibonacci_buffer(3) ( que saca el valor del buffer ) y a fibonacci_simple(2) )
  • fibonacci_buffer(5) (que llama a fibonacci_buffer(4) (que saca el valor del buffer) y a fibonacci_buffer(3) (que saca el valor del buffer)

Con este algoritmo consigo generar todos los números en 4ms.

¿Será posible simplificarlo un poco más?
Sólo hay que ver cómo se hace la generación de valores de forma recursiva. Si lo pensamos bien, cuando llamamos a fibonacci_buffer(5) la primera vez y lo queremos almacenar en fbuffer[2] llamaremos a fibonacci_buffer(4) (que se almacenará en fbuffer[1], y éste llamará a fibonacci_buffer(3) (que se almacenará en fbuffer[0]); es decir, lo primero que se generará será fbuffer[0], luego fbuffer[1] y por último fbuffer[2]… ¡ vamos por orden ! Sabiendo esto, nos podremos ahorrar el código de poner a 0 los elementos del buffer sabiendo cuál es el último elemento generado.

Para los incrédulos, podemos eliminar el comentario de la línea:

1
//    printf("He generado con éxito fbuffer[%d]\n", n3-1);

y ejecutar… veremos con qué orden se van generando los números.

Bien, intentemos eliminar las puestas a 0 de los elementos del buffer.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
int fibonacci_buffer2(int n)
{
  static int *fbuffer=NULL; /* Buffer */
  static int bufsize=0;         /* Tamaño de buffer */
  static int bpos=0;            /* Recorre buffers */
  int n3;           /* n-2 */

  if (n>2)
    {
      n3=n-2;
      if (fbuffer==NULL)
    {
      fbuffer = (int*) malloc((n3 * sizeof(int)));
      bufsize=n3;   /* Mantenemos bufsize por si redimensionamos el buffer */
    }
      else if (bufsize<n3)
    {
      fbuffer = (int*) realloc(fbuffer, n3 * sizeof(int));
      bufsize=n3;      
    }

      /* Utilizamos bpos para saber cuál es el último elemento del buffer */
      /* que hemos rellenado. */
      if (bpos>=n3)         /* Si se encuentra el fibonacci del número que buscamos  */
    return fbuffer[n3-1];   /* en memoria, lo devolvemos directamente */
      else
    {
      /* Si el fibonacci no se encuentra, vamos a generarlo */
      fbuffer[n3-1] = fibonacci_buffer(n-1) + fibonacci_buffer(n-2);
      bpos=n3;
      return fbuffer[n3-1];
    }

/*       return fibonacci_simple(n-1) + fibonacci_simple(n-2); */
    }
  else if (n==2)        /* Ponemos esto para agilizar un poco el proceso */
    return 1;
  else if (n==1)
    return 1;
  else if (n==0)
    return 0;
  else if (n==-1)       /* Un caso nuevo n==-1 */
    free(fbuffer);      /* Liberamos memoria */

  return -1;            /* Error */
}

Con este algoritmo, consigo generar la secuencia en 2ms. Bastante más rápido que con el primer algoritmo, parece que la puesta a 0 del buffer llevaba su tiempo.

Para concluir, quiero proponer otra solución basada en arrays, supongo que muchos estaréis más familiarizados con estos:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
int fibonacci_buffer3(int n)
{
  static int fbuffer[MAX_FIB];
  static int bufsize=0;         /* Tamaño de buffer */
  int n3;           /* n-3 */

  if (n>2)
    {
      n3=n-3;

      if (bufsize>n3)           /* Si se encuentra el fibonacci del número que buscaos  */
    return fbuffer[n3]; /* en memoria, lo devolvemos directamente */
      else
    {
      /* Si el fibonacci no se encuentra, vamos a generarlo */
      fbuffer[n3] = fibonacci_buffer(n-1) + fibonacci_buffer(n-2); /* y lo guardamos */
      bufsize=n3+1;
      /* Al ser fibonacci recursivo, y asignar el tamaño después de la generación */
      /* el buffer se rellenará por orden, es decir, el primero que se rellenará */
      /* será el [0], luego el [1], luego el [2]... */
      return fbuffer[n3];
    }

    }
  else if (n==2)        /* Ponemos esto para agilizar un poco el proceso */
    return 1;
  else if (n==1)
    return 1;
  else if (n==0)
    return 0;

  return -1;            /* Error, seguramente me hayan pasado un n negativo*/
}

Esta solución es muy parecida a las anteriores, aunque nos quitamos del medio la reserva de memoria, reducimos las líneas de código, ya que no vamos a alojar tantos valores diferentes… para esta secuencia serían unos 48 * 4 (sizeof(int)) = 192 bytes, y bufsize la utilizamos para ver cuál es el último elemento del buffer con información válida (como vimos antes, se rellenarán por orden, así que sólo tendríamos que llevar la cuenta). Las variables estáticas, como dije, podemos hacerlas globales (y quitarles el static, aunque queda más elegante como static).

Con esta solución tardo unos 5ms de media en generar la secuencia de números.

Foto: Eustaquio Santimano (Flickr)

Reproducir vídeos de youtube desde Firefox con mplayer

Viernes, 18 de Junio de 2010 Gaspar Fernández 3 comentarios

flvideoreplacer-logoHace unas horas descubrí esta fantástica extensión para Firefox. Su misión es cambiar los reproductores flash de Vimeo y Youtube entre otros por un reproductor de medios compatible (en mi caso, yo uso el plugin de mplayer). Los vídeos por fin se reproducen de forma fluida y la búsqueda dentro de los mismos es mucho más rápida que desde flash.

Ahora por fin, no se pone el ventilador de mi ordenador a gritar (al menos el ventilador de la CPU) cuando intento reproducir algo a pantalla completa.

La extensión podemos encontrarla aquí: FlashVideoReplacer o en la web de Mozilla Addons

Mientras va imponiéndose HTML5, está bien dejar de depender un poco de Flash…

Descargar álbumes Picasa sin Picasa, sin Java y sin ningún programa extra

Martes, 15 de Junio de 2010 Gaspar Fernández 2 comentarios

fotofotoUn buen sistema para compartir fotos es Picasa, de Google; aunque puede que no seamos usuarios de Google, ni tengamos el programa instalado en nuestro equipo, pero queramos descargar un álbum de fotos por completo.

Presento otro de mis scripts rápidos (no está optimizado, tal vez sea lento, pero hace el apaño) para descargar las fotos de un álbum Picasa. Lo que necesitamos es el RSS del álbum, lo descargamos en algún directorio y ejecutamos el siguiente script:

1
2
3
4
for i in `sed -e 's/\/>/\/>\n/g' archivo.rss | sed -n -e 's/.*<media:content url='"'"'\(.*\)'"'"' height=.*/\1/p'`
do
  wget $i;
done

Donde archivo.rss es el archivo que acabamos de descargarnos. Sólo utilizamos sed para parsear mínimamente el rss y wget para descargar las fotos.

El parseo no es del todo óptimo, primero introducimos saltos de línea y luego, leemos todo lo que empiece por

Foto: dariuszman86 (Flickr)

Curioso e interesante (2): Fragmentación en Linux, WikiUnix, convertir documentos desde la línea de comando, Ubuntu más seguro que Windows by Dell

Domingo, 13 de Junio de 2010 Gaspar Fernández Sin comentarios

Estos días he estado un poco liado, pero he dejado varias pestañas del navegador abiertas con algunas curiosidades que he encontrado estos días y me han llamado la atención:

  • Lo leí en Muy Linux. Hay controversia en este tema… casi todos decimos que no es necesario, y otros dicen que sólo somos geeks talibanes que ocultamos las carencias de nuestro sistema operativo preferido; pero la realidad es que la fragmentación en los sistemas de archivos más populares de Linux es significativamente menor que en Windows. Podemos ver más información en: Why doesn’t Linux need defragmenting?
  • Conversor de documentos de OpenOffice desde la línea de comandos: unoconv. Es un script en python que nos permite hacer conversiones de documentos en cualquier formato soportado por OpenOffice (necesita OpenOffice instalado y pyUno). Esto nos permitirá por ejemplo automatizar la conversión de formatos.
  • WikiUnix: Es una gran wiki de referencia de comandos y características de los sistemas Unix; un proyecto de la Oficina de Software Libre de la Universidad de Cádiz.
  • Dell afirma que: Ubuntu es más seguro que Windows; mientras Dell, sigue recomendando insistentemente en su web Windows 7…
  • Microsoft se mofa del fondo de Google. Vale que Google se pasó, metiendo un fondo automáticamente, a modo de presentación de su nueva característica; a la gente no le suelen gustar los cambios. Pero Microsoft aprovecha la más mínima para meter baza. Ya vale con las cadenas de Televisión que muestran el logotipo de Windows o una imagen de Internet Explorar cada vez que emiten la imagen de un ordenador; o que invierta en product placement en series como Crónicas Vampíricas y en varios episodios, Jericho, Entre Fantasmas, Smallville, El Internado, Los Protegidos… qué pastón para promocionarse, y la verdad, espero que todos los responsables de esas series hayan cobrado bien, porque si no, tontos de ellos…

Saludos

Bailando con bits: Ver y modificar los bits de un número

Jueves, 10 de Junio de 2010 Gaspar Fernández 2 comentarios

Hay muchas formas para hacer esto, pero quizás la más visual (tal vez también útil algunas veces) es la siguiente (se explica más abajo):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#include <stdio.h>

typedef struct {
    unsigned int b1:1;
    unsigned int b2:1;
    unsigned int b3:1;
    unsigned int b4:1;
    unsigned int b5:1;
    unsigned int b6:1;
    unsigned int b7:1;
    unsigned int b8:1;
    unsigned int b9:1;
    unsigned int b10:1;
    unsigned int b11:1;
    unsigned int b12:1;
    unsigned int b13:1;
    unsigned int b14:1;
    unsigned int b15:1;
    unsigned int b16:1;
    unsigned int b17:1;
    unsigned int b18:1;
    unsigned int b19:1;
    unsigned int b20:1;
    unsigned int b21:1;
    unsigned int b22:1;
    unsigned int b23:1;
    unsigned int b24:1;
    unsigned int b25:1;
    unsigned int b26:1;
    unsigned int b27:1;
    unsigned int b28:1;
    unsigned int b29:1;
    unsigned int b30:1;
    unsigned int b31:1;
    unsigned int b32:1;

} Tint_bits;

int main()
{
  int numero;
  Tint_bits *bitpack;

  bitpack=(Tint_bits*)&numero;
  numero=63;
  printf ("Dir cos: %X\nDir paq: %X\n", &numero, bitpack);  // Vemos que las direcciones de memoria son idénticas.
  printf ("Numero: %d\n", numero);
  printf ("Bit 1: %d\n", bitpack->b1);
  printf ("Bit 2: %d\n", bitpack->b2);
  printf ("Bit 3: %d\n", bitpack->b3);
  printf ("Bit 4: %d\n", bitpack->b4);
  printf ("Bit 5: %d\n", bitpack->b5);
  printf ("Bit 6: %d\n", bitpack->b6);
  printf ("Bit 7: %d\n", bitpack->b7);
  printf ("Bit 8: %d\n", bitpack->b8);
  printf ("Bit 9: %d\n", bitpack->b9);
  printf ("Bit10: %d\n", bitpack->b10);
  printf ("Bit11: %d\n", bitpack->b11);
  printf ("Bit12: %d\n", bitpack->b12);
  printf ("Bit13: %d\n", bitpack->b13);
  printf ("Bit14: %d\n", bitpack->b14);
  printf ("Bit15: %d\n", bitpack->b15);
  printf ("Bit16: %d\n", bitpack->b16);
  printf ("Bit17: %d\n", bitpack->b17);
  printf ("Bit18: %d\n", bitpack->b18);
  printf ("Bit19: %d\n", bitpack->b19);
  printf ("Bit20: %d\n", bitpack->b20);
  printf ("Bit21: %d\n", bitpack->b21);
  printf ("Bit22: %d\n", bitpack->b22);
  printf ("Bit23: %d\n", bitpack->b23);
  printf ("Bit24: %d\n", bitpack->b24);
  printf ("Bit25: %d\n", bitpack->b25);
  printf ("Bit26: %d\n", bitpack->b26);
  printf ("Bit27: %d\n", bitpack->b27);
  printf ("Bit28: %d\n", bitpack->b28);
  printf ("Bit29: %d\n", bitpack->b29);
  printf ("Bit30: %d\n", bitpack->b30);
  printf ("Bit31: %d\n", bitpack->b31);
  printf ("Bit32: %d\n", bitpack->b32);
 
  bitpack->b9=1;
  printf("Numero= %d\n", numero);
}

Primero creamos un espacio de bits en nuestro registro Tint_bits, con ello, hacemos 32 variables de tamaño 1 bit (con un espacio en memoria de 32bits (lo que es un entero de 32bits). Lo que hacemos para poder consultar los bits, es crear un puntero de este tipo (Tint_bits) que apunte a la dirección de memoria de nuestro número, con ello podremos leer en memoria, los distintos bits del número accediendo a los diferentes miembros (b1->b32), y lo que es mejor, podemos modificarlos (como hacemos al final del programa).

Lo malo de este método es que no podremos acceder a los bits como si de un array se tratase, y que este método no es muy portable, para enteros de 64 bits habría que hacer otro registro por ejemplo, y tendremos problemas para pasar de un sistema big-endian a un little-endian y viceversa; pero, como yo digo podemos ver la memoria directamente, que a veces es interesante.

Clases abstractas e interfaces en PHP

Viernes, 4 de Junio de 2010 Gaspar Fernández 2 comentarios

objetoLos interfaces son bastante comunes en la programación orientada a objetos, en PHP, son algo así como una declaración de lo que debe implementar una clase. Tendrá información de los métodos (exclusivamente) que se deben implementar.

Las clases abstractas contienen atributos y métodos, algunos pueden estar implementados y otros pueden ser abstractos. Los métodos abstractos son aquellos que no están implementados. Como tienen métodos sin implementar no podemos crear una instancia de este tipo de clases; entonces, ¿ para qué valen ?
Los métodos abstractos, los debemos implementar en las clases derivadas.

Vemos que tanto interfaces como clases abstractas son muy parecidos, los dos muestran declaraciones que debemos implementar más adelante, pero veamos algunas diferencias:

  • Una interfaz no puede contener atributos ni métodos implementados, mientras que una clase abstracta sí que puede contenerlos
  • Una clase sólo puede heredas una clase abstracta, mientras que en una misma clase se pueden implementar varias interfaces.
  • Las clases abstractas pueden declarar los métodos con diferente visibilidad (public, protected, internal, etc; private no, esto indicaría que una clase derivada no podría ver el método, por tanto no tendría sentido; final tampoco, porque no admitiría implementaciones futuras, aunque una clase derivada sí podría contener un método como final), mientras que en los interfaces todos los métodos deben ser públicos (también static)
  • Los métodos que no implementamos en una clase abstracta, deben ser abstract, en un interface, todos los métodos son abstract, y ninguno debe ser implementado.

Por último, aunque no sea un ejemplo demasiado concreto, pondré un fragmento de código en el que se define una clase abstracta (Articulo, como un artículo de una tienda), y varios interfaces de algunos tipos de artículo. (Intentao demostrar todo lo que he contado antes, para nada es un ejemplo real):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
<?php

abstract class Articulo
{
  private $stock;
  private $precio;

  abstract protected function venta($cantidad);

  abstract function calcula_precio_total($cantidad, $descuento);
}

interface En_caja
{
  function idiomas();
  function lectura($idioma);
}

interface Juguete
{
  function puedo_probarlo();
  static function probar();
  function tirar_al_suelo();
}

class HomerSapiens extends Articulo implements En_caja, Juguete
{
  protected function venta($cantidad)
  {
    ...
  }

  final function calcula_precio_total($cantidad, $descuento)
  {
    ...
  }

  function idiomas()
  {
    ...
  }

  function lectura($idioma)
  {
    ...
  }

  function puedo_probarlo()
  {
    ...
  }

  static function probar()
  {
    ...
  }

  function tirar_al_suelo()
  {
    ...
  }
}
?>

Foto: kevindooley (Flickr)

Visita otras webs de la red