OSX


13
sep 09

Booh!!

Que miedo mamaaaa… :-) Snow Leopard incluye un nuevo aviso en el comando sudo que reza tal que “asín”

WARNING: Improper use of the sudo command could lead to data loss
or the deletion of important system files. Please double-check your
typing when using sudo. Type "man sudo" for more information.

1
sep 09

Snow Leopard y Apple haciendo cosas raras

Dejemos las cosas claras: Apple no es la mega-super-guay empresa que muchos parece que quieren que sea. Es una empresa, y punto. Si acaso es de las mejores en cuanto a calidad y diseño, que ya es decir mucho.

Acabo de dar el paso definitivo a Mac OS X con un MacBook Pro que me he comprado para reemplazar mi equipo Vista de escritorio. Dicho con otras palabras, es la primera vez en 20 años que tengo un Mac exclusivamente.

Y una vez dicho esto, releo algo que ya sabíamos: OS X Snow Leopard sólo es para máquinas Intel de 64 bits. No va en PowerPC’s.

Esta frase que pasará desapercibida para la gran mayoría de usuarios de Mac (Dirán “Vale, ya lo sabíamos”), en el mundo PC es como si Microsoft decidiera que el próximo Windows 7 sólo funcionara en Intel Core 2 Duo o Xeon. Es decir, que se cargaría el 80% del mercado. No se qué cuota tendrán los Mac con procesador Intel, pero Apple tiene tan férreo control sobre el mercado de máquinas que se permite hacer esto.

Tengo que releer la frase y volver a pensar en ello, míralo con otras palabras: “A partir de aquí, o te compras una nueva máquina Apple o no podrás usar ningún programa!”. Quizás con Paralels o algún tipo de virtualización se podrían ejecutar aplicaciones PowerPC, pero vamos, coincidiréis que “no es lo mismo”.

A ver, no quiero que este post tenga connotaciones negativas exclusivamente, puede parecer que es una crítica. Pero leyendo entre líneas también hay algo de admiración. Ojalá otros pudieran hacer lo mismo. Estoy seguro que Vista o Windows 7 serían mucho mejores si Microsoft decidiera suspender el soporte para tecnologías obsoletas que llevan arrastrándose miles de años (en el universo informático, quiero decir).

Está claro que soy un admirador de Apple, no en vano me acabo de “convertir” ($$$), pero eso no quita para que sea crítico con algunas cosas de las que hace. Fanaticos Maqueros del mundo, os voy a decir como Pablo Motos: “Relaaaajate”. :-)


5
ago 09

MacOS X Snow Leopard compatible con Exchange

Según la página de Apple sobre OS X Snow Leopard, éste es compatible con Microsoft Exchange, literalmente según sus palabras:

“Con Snow Leopard, ahora el Mac ofrece compatibilidad con Exchange Server 2007 de Microsoft nada más sacarlo de la caja, algo que ni siquiera es posible en los PC con Windows.”

¡¡¡Ouch!!! :-)


14
jun 09

Test Driven Development

Test Driven Development (TDD), o como se traduce en Español “Desarrollo Guiado por Pruebas” es una práctica de programación muy usada en la metodología Agile Development. Podeis encontrar más información en la Wikipedia en Español o en Inglés.

Lo que pretendo en este post es “guiar” o “introducir” TDD para aquellos que no comprenden del todo el concepto. Para entender TDD, debes saber que requiere escribir las pruebas PRIMERO, no DESPUES, y enfatiza la refactorización para conseguir todo esto. ¿Cómo se pueden escribir las pruebas primero? Si estás acostumbrado a hacer las pruebas (en caso de que las hagas) después de escribir el código, este concepto te será raro. Si las pruebas se hacen después del código, estás comprobando que el código funciona pero dicho código no está inducido por las pruebas, simplemente has hecho un “test” para comprobar que lo que has hecho es correcto.

Puede parecer una perogrullada, pero esto no es lo mismo. TDD hace posible que tu código esté guiado por las pruebas inciales, que al fin y al cabo es un conjunto de requerimientos. Es decir, en TDD empiezas primero por definir el comportamiento al que debes adherirte y asegurarte de cumplir estos comportamientos. Al hacer primero los tests, se evitan una serie de comportamientos y se aseguran una serie de ventajas: por ejemplo el sobredimensionamiento del código, sólo implementamos lo suficiente para pasar los test (cumplir los requerimientos) y también obliga al programador primero a entender bien el problema a resolver y a pensar como cliente al enfocarse en los interfaces.

Como se que todo esto está muy bien, pero es difícil entenderlo, voy a hacer un pequeño ejercicio de TDD para que lo comprendais mejor.

Números de Fibonacci

Los requerimientos son hacer una clase en C++ con un método que devuelve un número de la serie de Fibonacci. Bueno, tampoco vamos a controlar una central nuclear, así que el ejemplito clásico de la serie de Fibonacci para un ejemplo de TDD es perfecto. He utilizado gcc en OSX, los ejemplos deberían funcionar también en Linux.

Primero tenemos que usar alguna herramienta para hacer los tests. Para este ejemplo yo he creado la mía, que simplemente es una fución “test” que le paso una cadena y un “bool” como resultado de la comprobación de la prueba. En un entorno real se debería usar una librería de tests, aunque como podeis ver tampoco hace falta nada del otro mundo para hacer una batería de tests.

#include <stdio.h>
#include "fibb.h"
 
void test(char *str, bool pass)
{
    printf("%-11s %s\n", pass ? "OK" : "***ERROR***", str);
}
 
int main()
{
    Fibb f;
 
    test("Fibb debe existir.", true);
 
    return 0;
}

Vale, he incluido la cabecera de mi “futura” librería que crea un objeto “Fibb”. Como todabía no la he creado (recordad, los test se hacen ANTES del código) ya tengo mi primer requerimiento: “Fibb debe existir“.

Como era de esperar, esto falla:

Twoixter:pruebas josemiguel$ make
g++    -c -o test.o test.cpp
test.cpp:3:18: error: fibb.h: No such file or directory
test.cpp: In function ‘int main()’:
test.cpp:12: error: ‘Fibb’ was not declared in this scope
test.cpp:12: error: expected `;' before ‘f’
test.cpp:15: error: ‘f’ was not declared in this scope
make: *** [test.o] Error 1
Twoixter:pruebas josemiguel$ _

Se me olvidaba, este es el fichero Makefile:

.SUFFIXES:
.SUFFIXES: .cpp .o
.PHONY: clean
 
all: test
 
test: test.o fibb.o
        $(CXX) -o test $^
 
clean:
        -rm *.o

Y esta es la clase esqueleto para hacer pasar el primer test: Vamos a crear el objeto “Fibb”:

/* Fichero: fibb.h */
class Fibb {
public:
        int dame(int numero);
};
/* Fichero: fibb.cpp */
#include "fibb.h"
 
int Fibb::dame(int no)
{
    return 0;
}

Bueno, ya tenemos todo en su sitio y ahora vamos a ver qué pasa:

Twoixter:pruebas josemiguel$ make
g++    -c -o test.o test.cpp
g++    -c -o fibb.o fibb.cpp
g++ -o test test.o fibb.o
Twoixter:pruebas josemiguel$ ./test
OK          Fibb debe existir.
Twoixter:pruebas josemiguel$ _

Bueno, como suponíamos, ahora pasa el test. Nuestro requerimiento se ha cumplido.

Fijaros que aún no hemos hecho nada para calcular la serie de Fibonacci, estamos haciendo requerimientos y los estamos cumpliendo programando nuestra clase para que pase los test. Esta es la clave del Test Driven Development no hacemos nada aparte de cumplir nuestros tests. Recordad, es Programación Dirigida por Pruebas, son los test los que nos indican qué tenemos que hacer.

Vamos a añadir unos cuantos tests más. Vamos a añadir unos cuantos requerimientos a nuestra “calculadora fibonacci“:

#include <stdio.h>
#include "fibb.h"
 
void test(char *str, bool pass)
{
    printf("%-11s %s\n", pass ? "OK" : "***ERROR***", str);
}
 
int main()
{
    Fibb f;
 
    test("Fibb debe existir.", true);
    test("Fibb.dame(0) debe ser 0.", f.dame(0) == 0);
    test("Fibb.dame(1) debe ser 1.", f.dame(1) == 1);
 
    return 0;
}

Es importante hacer notar aquí que, obviamente aparte de que cumplan con los detalles del problema, tenemos que procurar hacer los test para que fallen. En nuestro caso, la clase Fibb está vacía, sólo devuelve 0. Nuestro primer requerimiento (fibb de 0 == 0) por razones obvias va a cumplirse, pero a partir de aquí, los demás requerimientos SABEMOS que van a fallar, hacemos los test sabiendo que van a fallar y nuestro cometido es hacer que pasen.

Twoixter:pruebas josemiguel$ ./test
OK          Fibb debe existir.
OK          Fibb.dame(0) debe ser 0.
***ERROR*** Fibb.dame(1) debe ser 1.

Como esperábamos, el número 0 de la serie es 0, pero al comprobar el número 1 de la serie no es 1, como debería.

Pues venga, vamos a cumplirlo:

/* fichero: fibb.cpp */
#include "fibb.h"
 
int Fibb::dame(int numero)
{
    if (numero == 1) return 1;
 
    return 0;
}

Ya está. Perfecto. Nuestro programa pasa los tests…

Twoixter:pruebas josemiguel$ make
g++    -c -o fibb.o fibb.cpp
g++ -o test test.o fibb.o
Twoixter:pruebas josemiguel$ ./test
OK          Fibb debe existir.
OK          Fibb.dame(0) debe ser 0.
OK          Fibb.dame(1) debe ser 1.
Twoixter:pruebas josemiguel$

Bueno, aquí el lector avezado empezará a decir: “Espera, espera, no estás programando ninguna serie de Fibonacci, me estás mintiendo“. No, la respuesta es que estamos dando respuesta a nuestros requerimientos.

Si nuestros requerimientos fueran sólamente estos, ya habríamos terminado. No se, por ejemplo para un programa tonto que sólo saque los 2 primeros números de la serie de fibonacci esto bastaría. Las claves son las siguientes:

  • Nuestra clase funciona según los requerimientos indicados.
  • Nuestra clase no tiene ninguna funcionalidad extra, con lo cual no está sobrecargado con código sobrante.
  • Si un futuro programador lee nuestro código, sabe perfectamente (por los requerimientos) lo que hace.

Vamos a seguir ampliando requerimientos porque “parece” que nos falta algo para que sea una serie real de Fibonacci. Vamos a incluir lo siguiente:

  1. Para cualquier número negativo, devuelve -1 (Esto es un poco arbitrario, lo ponemos como requerimiento).
  2. Para el número 2, debe devolver 1.
  3. Para el número 3, debe devolver 2.
  4. Para el número 4, debe devolver 3.
  5. Para el número 5, debe devolver 5.

Venga, manos a la obra. Recordad PRIMERO hacemos los TEST para que FALLEN…

/* fichero: test.cpp */
#include <stdio.h>
#include "fibb.h"
 
void test(char *str, bool pass)
{
    printf("%-11s %s\n", pass ? "OK" : "***ERROR***", str);
}
 
int main()
{
    Fibb f;
 
    test("Fibb debe existir.", true);
    test("Para cualquier negativo, debe ser -1", f.dame(-1) == -1);
    test("Fibb.dame(0) debe ser 0.", f.dame(0) == 0);
    test("Fibb.dame(1) debe ser 1.", f.dame(1) == 1);
    test("Fibb.dame(2) debe ser 1.", f.dame(2) == 1);
    test("Fibb.dame(3) debe ser 2.", f.dame(3) == 2);
    test("Fibb.dame(4) debe ser 3.", f.dame(4) == 3);
    test("Fibb.dame(5) debe ser 5.", f.dame(5) == 5);
 
    return 0;
}

…como era de esperar:

Twoixter:pruebas josemiguel$ make
g++    -c -o test.o test.cpp
g++ -o test test.o fibb.o
Twoixter:pruebas josemiguel$ ./test
OK          Fibb debe existir.
***ERROR*** Para cualquier negativo, debe ser -1
OK          Fibb.dame(0) debe ser 0.
OK          Fibb.dame(1) debe ser 1.
***ERROR*** Fibb.dame(2) debe ser 1.
***ERROR*** Fibb.dame(3) debe ser 2.
***ERROR*** Fibb.dame(4) debe ser 3.
***ERROR*** Fibb.dame(5) debe ser 5.
Twoixter:pruebas josemiguel$ _

Vale, tenemos que hacer cumplir estos tests… así que modificamos el programa principal de esta forma:

/* fichero: fibb.cpp */
#include "fibb.h"
 
int Fibb::dame(int numero)
{
    switch (numero) {
        case -1: return -1;
        case 1: return 1;
        case 2: return 1;
        case 3: return 2;
        case 4: return 3;
        case 5: return 5;
    }
 
    return 0;
}

¡Pero que estafa es esta! ¡Seguimos sin programar un generador de números de Fibonacci!. No, esperad, no funciona así… Estamos cumpliendo los requerimientos, y para los requerimientos que hemos puesto, este programa funciona perfectamente, como lo demuestran los tests:

Twoixter:pruebas josemiguel$ ./test
OK          Fibb debe existir.
OK          Para cualquier negativo, debe ser -1
OK          Fibb.dame(0) debe ser 0.
OK          Fibb.dame(1) debe ser 1.
OK          Fibb.dame(2) debe ser 1.
OK          Fibb.dame(3) debe ser 2.
OK          Fibb.dame(4) debe ser 3.
OK          Fibb.dame(5) debe ser 5.
Twoixter:pruebas josemiguel$ _

Como veis, hemos pasado todos los tests. Nuestro programa es simple, fácil de entender, y pasa los tests.

Moraleja importante: TDD, o Desarrollo Asistido/Guiado por Pruebas, basa todo en los test al contrario que en la forma tradicional de programación. Si no usaramos TDD, empezaríamos por hacer un generador de números de Fibonacci seguramente de forma recursiva. Nos centraríamos en cosas que no tienen que ver con los requerimientos. En este ejemplo de la serie, insisto, es muy básico pero creo que cumple perfectamente con el objetivo de ver cuán diferente puede ser esta metodología de programación con respecto al método “clásico”.

Como veis, los detalles de implementación pasan a un plano secundario y lo importante son los requerimientos, el comportamiento que queremos que tenga nuestro programa. Con una batería de test correcta, con todos los requerimientos bien definidos, la implementación pasa a un segundo plano.

Hablando de requerimientos. Hay un fallo importante en los test, si os fijais, el test de los negativos pone “Para CUALQUIER negativo“, y sin embargo sólo comprobamos con menos uno. Vamos a cumplimentar mejor la batería de tests:

/* fichero: test.cpp */
#include <stdio.h>
#include <stdlib.h> 
#include "fibb.h"
 
void test(char *str, bool pass)
{
    printf("%-11s %s\n", pass ? "OK" : "***ERROR***", str);
}
 
int main()
{
    Fibb f;
 
    test("Fibb debe existir.", true);
    test("Para cualquier negativo, debe ser -1", f.dame(-rand()) == -1);
    test("Fibb.dame(0) debe ser 0.", f.dame(0) == 0);
    test("Fibb.dame(1) debe ser 1.", f.dame(1) == 1);
    test("Fibb.dame(2) debe ser 1.", f.dame(2) == 1);
    test("Fibb.dame(3) debe ser 2.", f.dame(3) == 2);
    test("Fibb.dame(4) debe ser 3.", f.dame(4) == 3);
    test("Fibb.dame(5) debe ser 5.", f.dame(5) == 5);
 
    return 0;
}

Hemos cambiado el test para cualquier negativo incluyendo un número aleatorio. No es estrictamente “científico”, porque en una pasada de test no podemos comprobar TODOS los números negativos. Para la mayoría de propósitos, un número aleatorio en un rango suficientemente grande nos asegurará que en cada ejecución de los test tengamos muchas posibilidades de que falle el test.

Moraleja: Como veis, seguimos enfocados en que los test fallen. Sería una perdida de tiempo en TDD hacer test para cosas que sabemos que funcionan, o cosas redundantes. Al enfocarnos en hacer test que fallen vamos “dirigiendo” nuestros esfuerzos a mejorar el desarrollo.

El test de los números negativos, como suponíamos, falla:

Twoixter:pruebas josemiguel$ ./test
OK          Fibb debe existir.
***ERROR*** Para cualquier negativo, debe ser -1
OK          Fibb.dame(0) debe ser 0.
OK          Fibb.dame(1) debe ser 1.
OK          Fibb.dame(2) debe ser 1.
OK          Fibb.dame(3) debe ser 2.
OK          Fibb.dame(4) debe ser 3.
OK          Fibb.dame(5) debe ser 5.
Twoixter:pruebas josemiguel$ _

Ahora introducimos un concepto importante en TDD, la refactorización. Una vez que nuestro código pasa los test, debemos refactorizar. Refactorizar es cambiar la programación por cualquier motivo, por ejemplo para que sea más eficiente, más rápido, o hacer el código más simple, pero siempre teniendo la seguridad de pasar los tests.

En nuestro caso, hacer que valide el test de los negativos no sería una refactorización en sí, puesto que hay un test que falla y tenemos que enfocarnos en que valide. Sí que hacemos una refactorización para hacer que lo que antes era un “switch”, pase a ser una tabla.

/* fichero: fibb.cpp */
#include "fibb.h"
 
int Fibb::dame(int numero)
{
    int tabla_fibb[6] = { 0, 1, 1, 2, 3, 5 };
 
    if (numero < 0) return -1;
    if (numero > 5) return 0;
    return tabla_fibb[numero];
}

Vale, hemos cumplido el test de los negativos haciendo que cualquier número menor que 0 devuelva -1. Después también ha habido la refactorización importante de pasar de un switch a una tabla. Ahora todos los tests pasan, incluso el de los negativos:

Twoixter:pruebas josemiguel$ ./test
OK          Fibb debe existir.
OK          Para cualquier negativo, debe ser -1
OK          Fibb.dame(0) debe ser 0.
OK          Fibb.dame(1) debe ser 1.
OK          Fibb.dame(2) debe ser 1.
OK          Fibb.dame(3) debe ser 2.
OK          Fibb.dame(4) debe ser 3.
OK          Fibb.dame(5) debe ser 5.
Twoixter:pruebas josemiguel$ _

Bien, como decíamos antes, si nuestros requerimientos fueran estos, ya habríamos terminado. ¡Y sin hacer el algoritmo de Fibonacci!. Merece la pena recapitular lo que hemos visto hasta ahora:

  • Programar usando Test Driven Development significa “dar la vuelta” a la forma de pensar cuando programamos normalmente, ya que PRIMERO se hacen los test (pruebas) en forma de requerimientos.
  • Los requerimientos por tanto deben ser sólidos, y estar bien fundados ya que nuestro programa va a ser una representación literal de esos requerimientos.
  • Los pasos que debemos dar por tanto son: test > implementación > probar test > refactorización. Y así continuamente hasta que todos los requerimientos se cumplan.

Para terminar, y como tengo la sensación de que a esta serie de Fibonacci le falta algo, imaginemos que una vez hecho todo lo anterior y ya estamos contentos (nuestro programa cumple con los requerimientos), viene el “jefe” y nos dice:

  • No, no, hasta 5 no, debe sacar los números de la serie hasta 40 como mínimo.
  • A ver, a ver, entonces cómo se hace eso?
  • Muy fácil, un número “n” de la serie es la suma del número “n-1″ más “n-2″…
  • Ahhhh… Vale.

Entonces, hacemos el siguiente test:

/* fichero: test.cpp */
#include <stdio.h>
#include <stdlib.h>
#include "fibb.h"
 
void test(char *str, bool pass)
{
    printf("%-11s %s\n", pass ? "OK" : "***ERROR***", str);
}
 
int main()
{
    Fibb f;
 
    test("Fibb debe existir.", true);
    test("Para cualquier negativo, debe ser -1", f.dame(-rand()) == -1);
    test("Fibb.dame(0) debe ser 0.", f.dame(0) == 0);
    test("Fibb.dame(1) debe ser 1.", f.dame(1) == 1);
    test("Fibb.dame(2) debe ser 1.", f.dame(2) == 1);
    test("Fibb.dame(3) debe ser 2.", f.dame(3) == 2);
    test("Fibb.dame(4) debe ser 3.", f.dame(4) == 3);
    test("Fibb.dame(5) debe ser 5.", f.dame(5) == 5);
 
    int n = 20;
    test("Fibb de 'n' debe ser fibb(n-1) + fibb(n-2)", f.dame(n) == f.dame(n-1) + f.dame(n-2) );
 
    return 0;
}

Incluimos un último test donde decimos exactamente eso, que el número “n” de la serie es la suma del n-1 más n-2. Si corremos la batería de tests, ocurre esto:

Twoixter:pruebas josemiguel$ ./test
OK          Fibb debe existir.
OK          Para cualquier negativo, debe ser -1
OK          Fibb.dame(0) debe ser 0.
OK          Fibb.dame(1) debe ser 1.
OK          Fibb.dame(2) debe ser 1.
OK          Fibb.dame(3) debe ser 2.
OK          Fibb.dame(4) debe ser 3.
OK          Fibb.dame(5) debe ser 5.
OK          Fibb de 'n' debe ser fibb(n-1) + fibb(n-2)
Twoixter:pruebas josemiguel$ _

¿Comorrrlll? ¿Ha pasado la prueba? Bieennn… Nuestro programa funciona para cualquier número natural positivo con sólo una tabla de 6 números. Bueno, evidentemente, esto está mal. Y está mal porque si recordais, hemos dicho antes que los tests tienen que hacerse PARA QUE FALLEN inicialmente. Si no, pasan estas cosas.

Nota: La explicación de por qué pasa el test debe ser evidente, pero si no, lo que ocurre es que nuestra función devuelve 0 para cualquier número mayor de 5. Entonces, 0 = 0 + 0.

Tenemos MAL el test.

Deberíamos replantear el test de esta forma: “Fibb de ‘n’ debe ser fibb(n-1) + fibb(n-2) y mayor que cero“.

Twoixter:pruebas josemiguel$ ./test
OK          Fibb debe existir.
OK          Para cualquier negativo, debe ser -1
OK          Fibb.dame(0) debe ser 0.
OK          Fibb.dame(1) debe ser 1.
OK          Fibb.dame(2) debe ser 1.
OK          Fibb.dame(3) debe ser 2.
OK          Fibb.dame(4) debe ser 3.
OK          Fibb.dame(5) debe ser 5.
***ERROR*** Fibb de 'n' debe ser igual a fibb(n-1) + fibb(n-2) y >0
Twoixter:pruebas josemiguel$ _

Vale, ahora podemos ponernos manos a la obra:

/* fichero: fibb.cpp */
#include "fibb.h"
 
int Fibb::dame(int numero)
{
    if (numero < 0) return -1;
    if (numero == 0) return 0;
    if (numero == 1) return 1;
 
    return dame(numero-1) + dame(numero-2);
}

Que es un algoritmo de Fibonacci más o menos estandard. (Bueno, no me critiqueis mucho, esto es un post sobre Test Driven Develpment, no sobre cómo hacer un algoritmo de Fibonacci) :-)

De hecho, habiendo refactorizado lo anterior, pasan todos los test. Ahora podríamos hacer un test que comprobara uno a uno todos los números de la serie hasta el 40, que es nuestro tope.

Espero que hayais leido hasta aquí, este ha sido uno de mis posts más largos. La intención ha sido hacer entender de una forma práctica las bases de TDD. En futuros posts, pondré enlaces más interesantes sobre frameworks y librerías que podemos usar para hacer tests y usaré otros lenguajes aparte de C++, lo prometo. :-)


9
ene 09

PS3 y Media Servers

A veces pienso que en tecnología, en lugar de ir para adelante, vamos para atrás. Pensadlo un poco, con máquinas de doble o cuádruple núcleo, cientos, si no miles de veces más rápidas que las de hace unos años seguimos haciendo lo mismo a la misma velocidad. Quizá un poco más “cool” (caso de OSX, en Windows ni eso).

Pues esa es la sensación que tengo con la PlayStation 3 y la compartición de “medios” por la red. Como no me gusta la definición de “medios”, voy a decir simplemente MP3 y Pelis. :-) A lo que vamos, la PS3 es un cliente DLNA y como tal, puede reproducir música, video y fotos desde cualquier Media Server… en teoría.

Y digo en teoría porque lo he conseguido a medias: yo, informático de pro, ingenierotecnicodegestión. No me quiero ni imaginar el ciudadano de a pie. Quizá soy un consumer avanzado, pero vamos, tengo mi coqueta librería de MP3, algunas pelis en DivX y algún que otro DVD (en ISO). He probado varios Media Servers tanto en Windows como en OSX. He de reconocer que no he probado ninguno en Linux, y eso que VortexBox promete (pero no tengo particiones ahora para probar).

Quizá, el que mejor resultado me ha dado hasta hora es Windows Media 11 (en Windows) hasta que dejó de ir. Resulta que una de las actualizaciones de seguridad de Windows tocó la configuración del firewall o algo y la compartición de medios dejó de ir (pero sí la de carpetas). Sospecho que tiene algo que ver con UPnP o algún puerto que usa el DLNA y estoy últimamente muy vago para arreglarlo. Mientras tanto, fué el único que consiguió streamear MP3 a la PS3.

Sin embargo, el que mejor resultado me ha dado hasta ahora es el EyeConnect, de Elgato (pero no con botas) :-) Sólo funciona en Mac OSX (lástima), y he conseguido hacer streming de pelis tanto de DivX como de… (“Tachaaan!!”) imágenes de DVD! (pero sólo en ficheros VOB, nada de imágenes ISO, ojalá). Es el MEJOR para compartir mi librería de MP3 porque yo la mimo mucho y la tengo en una carpeta “Música” ordenadas por carpetas como “Rock”, “Jazz”, etc. Son cosas de haberla ido recopilando durante años, pero no me gusta usar un “gestor” tipo iTunes que me diga cómo tengo que buscar mi música. Yo voy a la carpeta que quiero, hago doble clic y punto. Llámame antiguo que te lo acepto, también programé en COBOL. :-)

El EyeConnect sería perfecto sólo si streameara bien los MP3… Aún no he conseguido oir música en mi PS3 usando el servidor de medios de EyeConnect. Quizá es porque tengo la versión de demostración, pero me temo que algo tan simple debería hacerlo bien incluso así. Seguiré investigando… si a alguien le interesa el tema que me deje un comentario.


22
nov 08

Edición de código en Mac

Odio la edición de código, y texto en general, en Mac.

Si eres un usuario de ordenadores Mac no te preocupes, no estoy criticando el sistema. Esta petición es muy seria. Lo que pasa es lo siguiente: la forma de actuar de las teclas de edición como “Página Arriba” / “Página Abajo”, y sobre todo las teclas “Inicio” / “Fin” es completamente diferente.

Vereis, llevo más de 20 años usando un teclado de PC. Desde el comienzo de los tiempos, la tecla “Home” siempre ha llevado el cursor al principio de la línea, al igual que la tecla “End” ha llevado el cursor al final de la línea. El proceso es muy sencillo, y funciona de maravilla. No se a quién se le ocurrió que pulsando “Home” se tenga que ir al principio del DOCUMENTO, no de la línea actual ni siquiera de la página. Ahora mismo estoy editando este post en el WordPress y me veo a mi mismo una y otra vez usando el ratón para volver la página a donde estaba porque pulso mecánicamente “Home” queriendo volver al principio de la línea.

Lo que me gustaría, y desde aquí pido humildemente a algún usuario de Mac una solución, es que hubiera alguna opción, algo que pudiera cambiar para hacer que el comportamiento de las teclas de edición funcionase como en PC, pero para todo el sistema. Osea, no valen soluciones temporales para un programa como por ejemplo: “En TextMate entra en tal sitio y configura las teclas”. No. Tiene que ser “System Wide”, para todos los programas.

Editado: Bueno, después de leer esta entrada meses después, tengo que deciros que uso habitualmente casi el 100% del tiempo un ordenador Mac. Desde el trabajo hasta casa (me compré un MacBook Pro). La edición de texto en mac la he solucionado con un programa que se llama “Key Fixer”, o algo parecido. Si teneis interés, dejadme un comentario en el blog y publico la dirección donde podeis conseguirlo. (Es que si no, no me dejais ningún comentario, que sois unos perezosos) :-)


21
oct 08

Acceso NTFS de lectura/escritura en OSX

Si tienes en tu Mac (o en tu PC) alguna partición NTFS, verás que no puedes escribir porque OSX sólo tiene acceso de lectura a las particiones NTFS. También puede pasar que te dejen un disco externo USB y que éste esté particionado en NTFS.

Para solucionar esto, puedes utilizar soluciones de pago o bien probar una solución OpenSource llamada NTFS 3G, que usa FUSE para montar las particiones. Cuidadín que es un proceso un poco tedioso, necesitas acceder a varios comandos en la consola. (Si usas linux y estás acostumbrado al proceso de montado de particiones, etc, no tendrás problemas).