Más de 12 años en Internet
->No hagas click en esta frase.

30 julio, 2014

Aprendiendo Python, día 2

1.- Objetos (II):

1.1 - Herencia:

    En Python los objetos pueden heredar sus atributos de otra clase padre.

    Ejemplo:
class item():
        # Variables de instancia
        s_name          = None
        s_description   = None
        f_value         = float(0)
        # Constructor de clase
        def __init__(self, s_name, s_description, f_value):
                self.s_name             = s_name
                self.s_description      = s_description
                self.f_value            = float(f_value) 
class potion(item):
        # Variables de instancia
        i_health_point_restores = int(0)
        # Constructor de clase
        def __init__(self, s_name, s_description, f_value, i_health_point_restores):
                self.i_health_point_restores    = int(i_health_point_restores)
                # Llamamos al constructor del padre
                item.__init__(self, s_name, s_description, f_value) 
potion_1 = potion("Pocion", "Bebida", 100, 100)
print "El item es "+ potion_1.s_name + " y recupera", potion_1.i_health_point_restores, "puntos de vida"
     Si nos fijamos, al definir una clase hija definimos quién es el padre y más tarde volvemos a referenciar el padre (otra vez) cuando hacemos llamada a su constructor. Esto se debe a que Python permite herencia múltiple.

    Ejemplo:
class age_old():
        i_age   = int(18)
        def __init__(self, i_age):
                self.i_age      = int(i_age) 
class genre():
        s_genre = "male"
        def __init__(self, s_genre):
                self.s_genre    = s_genre 
class character(age_old, genre):
        s_name  = None
        def __init__(self, s_name, i_age, s_genre):
                self.s_name     = s_name
                age_old.__init__(self, i_age)
                genre.__init__(self, s_genre)
 

character_1 = character("Messi", 24, "male")
print character_1.s_name + " has", character_1.i_age, "years old and is " + character_1.s_genre
    Otra característica de la herencia en Python, es que podemos reescribir métodos de una clase padre sin necesidad de utilizar palabras reservadas para tal efecto.

    Ejemplo:
class a():
        def to_String(self):
                return "Hola"
        pass 
class b(a):
        def to_String(self):
                return "Adios"
        pass 
v_variable = b()
print v_variable.to_String()
    Habrás notado en el ejemplo anterior que he empleado la palabra "pass". Esta palabra reservada puede emplearse en la definición de clases para ahorrarse la definición de constructores. No es recomendado su uso, pero resulta últil a la hora de codificar rápido.

2.- Bases de datos:

    Existe para Python una serie de conectores para bases de datos bastante útiles, las cuales podemos clasificar de tres tipos:

  1. Tradicionales (modelo servidor de base de datos + autenticación + cliente).
  2. Embebidas (base de datos almacenada en un fichero local).
  3. Volátiles (base de datos almacenada únicamente en la memoria RAM).

2.1 - Bases de datos tradicionales.

    Cuando hablamos de un entorno tradicional de bases de datos, nos referimos a que nuestra aplicación ataca contra un servidor o servicio de base de datos. Es decir, necesitamos conocer un usuario con el que autenticarnos, su contraseña y la ip (y/o puerto) del servicio.

    Ejemplo (requiere paquete python-mysqldb):

import MySQLdb 
# Conexion SQL
sql_connection  = MySQLdb.connect('ip_server', 'user_name', 'password', 'bda_name')
sql_cursor      = sql_connection.cursor() 
# Sentencia
sql_cursor.execute("select name from photos where 1 order by date limit 0,10") 
# Listamos los resultados
for v_tupla in sql_cursor.fetchall() :
    print v_tupla[0]

2.2.- Base de datos empotradas y volátiles

    No obstante, es bastante común en las aplicaciones de escritorio emplear bases de datos persistentes en ficheros o hacer uso de bases de datos temporales que existen en su memoria RAM. El primer modelo suele emplearse en aplicaciones que hacen uso de colecciones elevadas de datos (como por ejemplo un reproductor de audio como Amarok que gestiona y clasifica todos los ficheros por autor, género, además de almacenar el número de veces que has escuchado un tema, etcétera) mientras que el segundo suele verse más en juegos (donde se hace uso de distintas tablas y vistas que no requieren ser almacenadas para salvar la partida).

    Es cierto que una aplicación de escritorio puede emplear otro tipo de gestión de datos. Por ejemplo, hay aplicaciones que almacenan sus colecciones en ficheros de texto plano o en ficheros XML, por citar unos ejemplos comunes. No obstante, emplear una base de datos embebida o empotrada nos presenta dos mejoras importantes:
  1. Búsqueda de información más rápida, puesto que se realizan consultas SQL y no una lectura secuencial de datos.
  2. Los gestores de BDA empotradas más comunes generan ficheros cifrados.
    Tanto si queremos hacer una base de datos embebida o una volátil, en Python podemos hacer uso del plugin de SQLite3.

    Ejemplo de base de datos empotrada:

import sqlite3 
# Si el fichero de la base de datos no existe, se crea
sqlite3_connection = sqlite3.connect("mi_fichero_de_BS.db")
sqlite3_cursor = sqlite3_connection.cursor() 
# Si no existe nuestra tabla "photos", la creamos
sqlite3_cursor.execute("create table if not exists photos (id int, content blob)") 
# Leemos una imagen en formato binario
f_picture = open("test.jpg", "rb")
with f_picture:
    picture_data = f_picture.read() 
# Insertamos fotos a la BDA
sqlite3_cursor.execute("INSERT INTO photos (name, content) VALUES (0, ?)", [sqlite3.Binary(picture_data)]) 
# Confirmamos el cambio
sqlite3_connection.commit()
sqlite3_connection.close()
    Ejemplo de base de datos volátil (atención al nombre del archivo, el resto es igual que una base de datos empotrada):
import sqlite3 
# Si el fichero de la base de datos no existe, se crea
sqlite3_connection = sqlite3.connect(':memory:')
sqlite3_cursor = sqlite3_connection.cursor() 
# Si no existe nuestra tabla "empleados", la creamos
sqlite3_cursor.execute("create table if not exists employee (name varchar(200), age int)") 
# Insertamos valores
d_employees = dict()
d_employees["Sebastian Moncho"] = 30
d_employees["Garijo"] = 25
d_employees["Querido lector"] = 21
for v_index, v_value in d_employees.items():
        sqlite3_cursor.execute("INSERT INTO employee (name, age) VALUES ('"+ str(v_index) +"', " + str(v_value) +")") 
# Confirmamos el cambio
sqlite3_connection.commit() 
# Hacemos un select e imprimimos por salida estandar
sqlite3_cursor.execute("select name, age from employee where 1")
for v_tupla in sqlite3_cursor.fetchall() :
    print v_tupla[0] + " tiene", v_tupla[1] 
sqlite3_connection.close()

 

3.- Convertir a C y compilar

    Existen varios compiladores de código para Python (para aquellas ocasiones que no queramos que los demás lean nuestro código). La opción más extendida es la de hacer uso de la aplicación Cython para convertir nuestro código de Python a lenguaje C. Su uso es bien sencillo. Este código puede además compilarse y emplearse en otros sistemas (de la misma arquitectura) siempre que "linkemos" con la librería estática de Python o bien exportemos la dinámica. No voy a entrar en cómo "enlazar" las librerías, sólo me remitiré a deciros que esto existe y os voy a mostrar un ejemplo rápido.

    Convertir un código fuente .py a código fuente de c:
cython --embed sqlite3_volatil.py -o sqlite3_volatil.c
    Crear un objeto de c a partir del código fuente:
gcc -c sqlite3_volatil.c `pkg-config --cflags python` -o sqlite3_volatil.o
    Crear el ejecutable binario:
gcc sqlite3_volatil.o `pkg-config --libs python` -o sqlite3_volatil
    Si hacemos un ldd sobre nuestro nuevo binario, veremos las librerías dinámicas que emplea nuestro binario para posteriormente decidir cuales exportar:
ldd sqlite3_volatil 
linux-vdso.so.1 =>  (0x00007fff642a0000)
libpython2.7.so.1.0 => /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0 (0x00007f0301ae6000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0301720000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f0301501000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f03012e8000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f03010e4000)
libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007f0300ee0000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f0300bda000)
/lib64/ld-linux-x86-64.so.2 (0x00007f030206c000)
    Si ejecutamos nuestro binario, veremos que tendremos el mismo comportamiento que con el intérprete:
./sqlite3_volatil
Garijo tiene 25
Querido lector tiene 21
Sebastian Moncho tiene 30
    Podemos crear un script de bash para hacer uso de las librerías dinámicas que exportemos y así poder ejecutar nuestro binario en máquinas Linux de la misma arquitectura:
#!/bin/bash
declare -r ARCH=`uname -m` 
[ "$ARCH" == "x86_64" ] &&\
        export LD_LIBRARY_PATH="./libs/x86_64" &&\
        ./sqlite3_volatil

24 julio, 2014

Llega a Gog la primera hornada de juegos compatibles con Linux... ¡y lo celebra con descuento!



    Desde hoy está disponible en GOG.com su primera hornada de juegos compatibles con Linux y para celebrarlo dichos títulos se estrenan como oferta del fin de semana, con un 75% de descuento. No destacan mucho por su calidad (salvo honrosas excepciones), pero sí por su cantidad (gran parte porque bastantes de ellos funcionan con un emulador DosBox modificado para la ocasión).



   A diferencia de los intalables de Windows o Mac, las versiones de Linux cuentan con dos posibles descargas: Un paquete .deb optimizado para Ubuntu 14.04 (requiere permisos de administrador) o un sencillo tarball (comprimido tar.gz que deployea la aplicación, puedes ejecutarla a través de un script start.sh) que permite su ejecución en otros sistemas (no garantizado) y sin requerrir permisos de super usuario.

Lista completa de los juegos compatibles con Linux presentados hoy:

  • Anomaly Warzone Earth
  • Ascendant
  • Bionic Dues
  • Blake Stone: Aliens of Gold
  • Blake Stone: Planet Strike
  • Bloodnet
  • Braveland
  • CLARC
  • Darklands
  • Darwinia
  • Defcon
  • Don't Starve + DLC
  • Dragonsphere
  • Duke Nukem 3D: Atomic Edition
  • FlatOut
  • Flatout 2
  • Fragile Allegiance
  • Gemini Rue
  • Gods Will Be Watching
  • Hammerwatch
  • Hocus Pocus
  • Kentucky Route Zero
  • The Last Federation
  • Legend of Grimrock
  • Litil Divil
  • Long Live the Queen
  • MouseCraft
  • Multiwinia
  • Normality
  • Pinball Gold Pack
  • Pinball World
  • Pirates! Gold Plus
  • Realms of the Haunting
  • Rex Nebular and the Cosmic Gender Bender
  • Rise of the Triad: Dark War
  • Shattered Haven
  • The Shivah HD
  • Sid Meier's Colonization
  • Sid Meier's Covert Action
  • Sir, You Are Being Hunted
  • Slipstream 5000
  • Space Pirates and Zombies
  • Spacechem
  • Stargunner
  • SteamWorld Dig
  • Super Hexagon
  • Surgeon Simulator 2013
  • Sword of the Samurai
  • Teslagrad
  • Unrest:Special Edition
  • Uplink
  • VVVVVV

Aprendiendo Python, día 1

1.- ¿Qué es Python?

    Python es un lenguaje de scripting (lenguaje de programación interpretado) con dos objetivos clave: Ser inteligible y ser multiplataforma. Al ser un lenguaje interpretado, significa que cuando se ejecuta un programa escrito en Python no se ejecuta un código binario, si no el código fuente en si, permitiendo que cualquier usuario final pueda editarlo (ahora bien, existen herramientas de terceros que te permiten generar binarios .exe, por ejemplo).

    Por otro lado, al ser multiplataforma significa que todo lo que se tenga que ejecutar tendrá que funcionar de forma parecida (dentro de lo que se pueda) en distintos sistemas operativos. Esto es un punto a favor respecto a otros lenguajes de scripting como Batch (sistemas Windows), Bash o AWK (Unix)... además de contar con otra mejora importante respecto a estos: Python es un lenguaje de scripting con orientación a objetos.

2.- ¿Cómo se instala?

    En entornos Linux suele estar presente en la mayoría de repositorios, pudiendo instalarse fácilmente con programas como yum o apt-get (ejemplo, en Ubuntu bastaría con abrir una shell y teclear: sudo apt-get install python-all).  En entornos Windows basta con instalarse el instalable suministrado en la web oficial de Python.

3.- "Hello World" y  "What's your name?"

    El primer programa que hacemos siempre en cada lenguaje de programación que queremos aprender es el famoso "Hola Mundo"... Una sencilla aplicación de consola que lo único que hace es imprimir por salida estándar (pantalla) el texto de "Hola Mundo". Haciendo uso de nuestro editor de texto preferido vamos a crear un fichero de texto plano llamado helloworld.py y le vamos a poner el siguiente contenido:
print "Hello world!"
Guardamos el archivo, abrimos una terminal y ejecutamos:
python helloworld.py
    Verás que nos sale una nueva línea con el texto Hello world!. Como ves éste ha sido uno de los Hello World más sencillos que has hecho en tu vida: haciendo uso una mera línea de código. Si en Windows no te encuentra el programa "python", dale un vistazo a cómo definir las variables del sistema de Python, serguramente el ejecutable no se encuentra en ninguna ruta de tu Path.

    Ahora vamos con un paso más complicado, vamos a imprimir por salida estándar "Cómo te llamas?", vamos a hacer que se nos pregunte por entrada estándar nuestro nombre y acto seguido imprimiremos "Encantado de conocerte, XXXXX". Para ello crearemos el fichero de texto plano whatsyourname.py y añadiremos las siguientes líneas:
# -*- coding: utf-8 -*-
print "¿Cómo te llamas?"
s_name = raw_input()
print "Encantado de conocerte,", s_name
    La primera línea es necesaria porque estamos utilizando carácteres que no están presentes en la codificación ASCII estándar, como es el símbolo de apertura de interrogación o el acento en la o. Sin esa línea nuestro script no podría ejecutarse "por errores de código". Ahora bien, esta línea sería innecesaria si nuestros literales estuvieran escritos únicamente en inglés o en castellano pero sin carácteres no presentes en la codificación ASCII.

    En la tercera línea pedimos una entrada manual de datos y hacemos que el dato o datos suministrados se guarden en la variable s_name. Si nos fijamos, a diferencia de otros lenguajes de programación no hace falta definir ni inicializar previamente dicha variable. Por último, por defecto Python entiende que todas las variables son strings, pero podemos forzar su uso como float o integers (por ejemplo) haciendo uso de castings. Para demostrar esto (que todas las variables por defecto son cadenas de texto), os presentaré un pequeño cambio en el código:
# -*- coding: utf-8 -*-
print "¿Cómo te llamas?"
s_name = raw_input()
print "Encantado de conocerte, " + s_name
    Si ejecutamos ahora el código veremos que el comportamiento es exáctamente el mismo que antes, pero hemos añadido un espacio en blanco dentro de las comillas y hemos concatenado la cadena s_name haciendo uso del símbolo "+".

    Podemos presentar una tercera variación del código, dado que raw_input permite mostrar una cadena de texto a la vez que pide la entrada de datos:
# -*- coding: utf-8 -*-
s_name = raw_input("¿Cómo te llamas?\n")
print "Encantado de conocerte, " + s_name
    Por último, si eres usuario de Linux, existe una forma con la que puedes ejecutar tus programas de Python sin necesidad de escribir siempre "python " delante:
  1. Desde una terminal ejecuta which python para conocer la ruta donde se encuentra tu intérprete de Python. En mi caso se encuentra en /usr/bin/python.
  2. En la primera línea de tu script escribe lo siguiente: #!/usr/bin/python
  3. Dale permisos de ejecución a tu script: (desde consola) chmod +x script.py
  4. Ejecutalo escribiendo su ruta absoluta o relativa: ./script.py

4.- Conceptos básicos de Python

4.1- If, else if, else, enteros y cadenas.
    Python no usa llaves para separar bloques de código (como son clases, funciones o condiciones). Para delimitar esos bloques se hace uso de sangrías (tabulaciones) o 5 espacios en blanco. Suena raro, pero es práctico y genera código inteligible. Para entender esto os dejo un ejemplo de condiciones:

# -*- coding: utf-8 -*-
v_number = raw_input("Dame un número\n")
v_number = int(v_number) 
if v_number > 10:
        print v_number , "es > 10" 
elif v_number == 10:
        print v_number , "es 10" 
else:
        print v_number , "es < 10"
    Si nos fijamos, en el caso anterior hemos hecho un casting a int para poder realizar una comparación con un valor entero. De no haberlo hecho, Python habría entendido que v_number era una cadena de texto y por consiguiente de no ponerlo no obtendríamos el resultado esperado. Ejemplo de comparación correcta con cadenas de texto:
# -*- coding: utf-8 -*-
v_name = raw_input("Dame un nombre\n") 
if v_name == 'Sebas':
        print v_name + " es Sebas" 
else:
        print v_name + " no es Sebas"

4.2- Bucles
    Python permite dos formas de embuclado de flujos: los famosos while y for. Su funcionamiento es similar al del resto de lenguajes de programación, permitiendo que se ejecute un bloque de código de forma concurrente hasta que deje de cumplirse una condición.

Ejemplo de uso de while:
v_i = int(5) 
while v_i >= 0:
        print v_i
        v_i-=1
Ejemplo con un "while true":
# -*- coding: utf-8 -*-
while True:
        v_number = int(raw_input("Dame un número\n")) 
        if v_number == 0:
                break
    Donde con While True exigimos que el bucle sea infinito, pero con el break indicamos que el bucle morirá cuando insertemos el número 0.

    Por otro lado el bucle for realmente actúa como un bucle "foreach".

Ejemplo 1, contar del 0 al 4:
for v_i in range(5):
        print v_i
Ejemplo 2, contar del 5 al 9:
for v_i in range(5, 10):
        print v_i

Ejemplo 3, leer todas las líneas de un fichero de texto plano:
s_file_name = "mi_fichero.txt"
v_file = open(s_file_name) 
for s_line in v_file:
        print s_line
Ejemplo 4, deletrear una cadena de texto:
for c_char in 'QWERTY':
        print c_char
Ejemplo 5, tratar un array elemento a elemento:
l_nombres = ["sebas", "paula", "joan"] 
for s_nombre in l_nombres:
        print s_nombre

4.3- Colecciones
    Al igual que muchos de los lenguajes modernos, Python permite hacer uso de colecciones, siendo las más famosas de su catálogo las listas y los diccionarios. Una lista puede entenderse como un conjunto de elementos ordenados como una pila FIFO (first in, first out).
l_names = list()
l_names.append("sebas")
l_names.append("paula")
l_names.append("joan") 
for s_name in l_names:
        print s_name
    Por su parte, un diccionario es lo que se conoce como un array referenciado, donde el índice no tiene por qué ser un número entero (algo bastante típico en lenguajes como AWK o Perl). A diferencia de las listas, su orden es LIFO (last in, first out)... pero el orden puede cambiar si jugamos con el método sort.
# -*- coding: utf-8 -*-
l_age = dict() 
l_age["sebas"] = 30
l_age["paula"] = 20
l_age["joan"] = 25 
for v_index, v_value in l_age.items():
        print v_index + " tiene", v_value, "años"

4.4- Funciones
    Para crear una función bastará con escribir delante de su nombre la palabra referenciada "def", pondremos entre paréntesis los parámetros que requiere (si es que requiere alguno) y definiremos todo su contenido haciendo uso de un nivel de sangría.

Ejemplo 1:
# Funcion
def insult_user(s_name):
        if s_name == "Sebas":
                print "Guapo!"
        else:
                print "Feo!" 
# Hilo principal
s_name = raw_input("Dame un nombre\n")
insult_user(s_name)
Ejemplo 2:
# -*- coding: utf-8 -*-
def div_5(v_number):
        return float(v_number)/5 
v_number = raw_input("Dame un número\n")
print "Su división entre 5 da", div_5(v_number)

4.4- Objetos
    A diferencia de otros lenguajes de scripting, Python es un lenguaje orientado a objetos.

Ejemplo:
class footballer():
        #Variables de instancia
        s_name = None
        s_average = 50
        #Constructor de la clase
        def __init__(self, s_name, s_average):
                self.s_name = s_name
                self.s_average = s_average
        def lesionar(self):
                self.s_average = int(self.s_average)/2  
v_footballer_1 = footballer("Cristiano Ronaldo", 89)
v_footballer_2 = footballer("Sofiane Feghouli", 95)
v_footballer_3 = footballer("Lionel Messi", 90) 
v_footballer_2.lesionar() 
l_team = list()
l_team.append(v_footballer_1)
l_team.append(v_footballer_2)
l_team.append(v_footballer_3) 
for v_footballer in l_team:
        print v_footballer.s_name + " tiene una media de", v_footballer.s_average

15 julio, 2014

Jazztel manda estafadores a mi casa

    Hace un par de años recibía muchas llamadas de Jazztel para intentar convencerme de que cambiara de operadora de internet. No es que vea mal que me llamen, pero cansa que lo hagan de forma sistemática y con operadores que desconocen qué es lo que venden. De hecho, puedo asegurar que Jazztel es una de las razones por las que todos mis teléfonos están en la lista Robinson.

    ¿Cómo sabía que sus operadores estaban mal preparados y que no sabían lo que me vendían? Por lo que aseguraban que me vendían:
- Señor, le ofrecemos un router de tecnología alemana con soporte para udpstreaming que le permite una aceleran...
- Tengo un router Cisco.
- Pero nosotros le ofrecemos un router de tecnología alemana, que como sabe es la industria más potente...
- Mi router es Cisco.
- Pero el nuestro tiene teconología upd hiper streaming que entre otras cosas mejora la velocidad de los vídeos en internet y el de los gráficos de los juegos.
- Espera, ¿me estás diciendo que los gráficos de los juegos de ordenador mejoran con su router?
- Sí señor, gracias a nuestra tecnología hiper...
- Hablas en serio, ¿vuestro router mejora los gráficos de los juegos de ordenador?
- Sí, puesto que...
- Oye, que no sigas, te lo agradezco pero me quedo con mi operadora.


#TrueStory

    Como comenté antes, este tipo de problemas los solucioné cuando me di de alta en la lista Robinson. Ahora bien, ahora el acoso llega a otro nivel: Me mandan comerciales a casa. La mecánica es siempre la misma: Cada dos meses se ha acabado la instalación de fibra óptica en tu finca y ellos, amablemente, se pasan para informarte que ya hay fibra óptica en tu casa. Da igual si desde hace años tienes contratada la fibra óptica de Ono, Vodafone o incluso PTV Telecom, ellos te venden que acaban de acabarse las obras de fibra óptica y que por lo tanto vienen a ofrecerte. No son los únicos, también recibo visitas continuas de Vodafone, pero estos últimos se les ve mejor preparados y son mucho más amables.

    Siempre que ha venido a mi casa uno de sus comerciales, mi señora y yo los hemos despachado de buenas formas, haciéndoles comprender que no nos interesa su oferta. Ahora viene lo bueno: Siempre que se despiden te tachan de una lista suya dando a entender que así no volverán a molestarte. Pero la realidad es otra, a los dos meses han vuelto a acabarse las obras de fibra óptica del edificio y se pasan a informarte para ofrecerte una magnifica nueva: te van a instalar la fibra óptica gratis y sólo esta vez... tras otra, tras otra, tras otra...


- ¿Me instalan fibra óptica gratis? ¿Y sólo hoy?

    Siendo esta una rutina del día a día, pues realmente no vale la pena escribir una entrada sobre ello. El problema viene con el último comercial que me mandaron a casa. Eso no era un comercial. Era un puto estafador de mierda (perdón por las palabras). El típico lumbreras que vendería agua haciéndola pasar como cura para el VIH. Siento ser tan duro, pero el espécimen que me mandaron a casa (por llamarlo de alguna forma) no tenía ética ninguna.

    Recapitulemos, un señor de unos 40 años vino a mi casa a informarme que acaba de instalarse la fibra óptica en mi edificio. Cómo no, este informador trabajaba para Jazztel, como todos los anteriores que vienen informándome últimamente. Primero empiezan por lo simple: ¿Qué compañía tienes y cuanto te cobra por internet, televisión y teléfono? Yo le comenté que estaba con la empresa más barata y que era imposible mejorar la oferta: 30 euros al mes. El me respondió que me la mejoraba por 40 euros al mes. Lógicamente, yo no veía una mejor oferta pagar 10 euros más, pero él se excusaba diciendo que la velocidad de internet era mejor.

    Ahora bien, atentos a la jugada maestra: A diferencia de mi operador, el hombre me ofrece un router capaz de ofrecer velocidad simétrica (subida y bajada) para todos los dispositivos de casa de forma simultánea. Es decir que, palabras textuales suyas, si contratas 200 MB de velocidad, todos los dispositivos de casa, ya sea uno o 20, pueden bajar a 200MB al mismo tiempo.

    Yo le comenté que eso no era posible, puesto que con la tecnología actual se ofrece un cuello de botella: El router tiene salida de fibra óptica de 200MB, pero tiene que gestionar las conexiones de todos los dispositivos de casa. Es decir, que si la velocidad de internet es de 200MB, es imposible tener 100 dispositivos bajando al mismo tiempo a 200MB. Hagamos mucho más simple el ejemplo. Imagina que cada minuto tienes 6 manzanas y que tienes 1 hijo. Cada minuto tu hijo tendrá 6 manzanas. Ahora imagina que tienes 3 hijos. Cada minuto cada hijo tendrá 2 manzanas. Así de simple. Podemos empezar a filosofear sobre el sexo de los ángeles y comentar que a lo mejor un hijo recibe 4 manzanas, otro dos y el último se queda mirando a Cuenca... pero el mensaje es claro: Si tienes 6 manzanas por minuto, no puedes repartir 18. Los 200MB no se asignan a cada dispositivo de la casa, se asignan al router, al cachivache ese que "habla" con la operadora.

    Pero el hijoputa (hdp en adelante) me decía que no. Que él sabía que era algo difícil de entender, puesto que la fibra óptica era una tecnología nueva y que "eso funcionaba como los teléfonos", que hoy en día desde una sola línea podía realizar llamadas y recibirlas al mismo tiempo desde diferentes puntos de la casa. Yo le paré el carro diciendo que estaba mezclando peras con manzanas... pero pobre de mi, que me contestó con un "hombre, yo entiendo que es difícil de ver, pero lo que pasa es que para entenderlo pues tienes que hacer cursos sobre el tema, como yo".



CEAC presenta sus cursos de certificación CCNA de Cisco.

    Entonces entré en furia con el hdp, remarcándole que si quiería una red tan perfecta como la que él me describía para eso compraba un router cisco de seis mil euros y lo enracaba con un switch para tener tropecientos servidores a la velocidad de la luz. Pero él, lejos de entender que me quejaba del cuello de botella de un router casero, volvió a la técnica de que yo era un burro que no hacía cursos como él y que él mismo instalaba esos servidores. "Que era lógico, que los servidores se ponían a internet con fibra óptica". Me dieron ganas de cerrarle la boca diciendo que para instalar un servidor no necesitas cursos, necesitas certificaciones.

    Pero no contentos con ser más mentiroso que un cojo, se superó con la segunda jugada: Según el hdp (alias comercial de Jazztel), en 2015 las líneas ADSL van a desaparecer, al igual que el teléfono y la televisión por TDT. Según él, es algo que se lleva planeando y que será una migración similar a cuando en 2005 dejamos de tener televisión analógica y pasamos a tener la famosa Televisión Digital Terrestre. #TrueStory, hablo en serio, no me lo invento.


¿Tienes fibra óptica? ¡No pasa nada! ¡Te vendo fibra óptica!

    Ajam, ahora lo cascas, puesto que en la última declaración de intereses del hdp era imposible soltar tantas mentiras por segundo. Pero no temáis, puesto que el hdp se encargó de destacar una y otra vez que con Jazztel y sólo ahora, podíamos tener una instalación de TV, internet y teléfono que nos ahorre esta migración. También nos remarcó una y otra vez que la oferta sólo podía pedirse ahora, puesto que en el futuro la instalación pasaría a valer unos 300 euros.

    Ahora bien, como yo le respondía que lo que decía no podía ser, volvió a lo mismo de que "sabía que era difícil de entender, pero que era cierto, que iba a pasar como con la TDT". Yo de vez en cuando le cortaba diciéndole que cuando eso pase (cuando se corte el TDT si es que llega a cortarse) ya lo hablaría con mi operadora en el futuro, pero eso sólo daba lugar a que el hdp reaccionara con el mismo monólogo: Que entonces mi operadora me cobraría un ojo de la cara por la migración y que si lo contrataba ahora tendría una instalación de fibra óptica gratis.

    Tras un buen rato con el hdp despotricando mierda y ver que no caíamos en su estafa, el hdp se despidió preguntando de qué trabajaba. Le contesté la verdad: Programador informático. Su reacción, lejos de reconocer su cagada fue decir "claro, yo soy de redes, departamentos distintos". Y él que sabrá a qué me he dedicado yo toda mi vida, si no siempre he sido programador, y puede que yo no sea certificado CCNA, pero el departamento de redes de mi empresa es certificada Cisco y para colmo los soporto (con cariño) todos los días.

En fin.
Resumamos:
  1. Que sepas que las obras para fibra óptica de tu edificio se estropean mucho, cada dos meses las vuelven a instalar.
  2. Que sepas que según el hdp que me mandó Jazztel el TDT se va a acabar, al igual que el teléfono tradicional o el internet por ADSL.
  3. Quiero saber si es posible obtener una orden de alejamiento para que no se me acerquen comerciales de Jazztel nunca más.


----- Bonus track: What does the chameleon say?

14 julio, 2014

Anunciada Raspberry Pi B+

    La Raspberry Pi Fundation ha anunciado hoy el lanzamiento de su nuevo modelo de micro ordenador: La Raspberry Pi B+, el cual se trata de una versión mejorada del modelo B, donde se han añadido los siguientes cambios:
  • Se reduce el consumo en un 30%.
  • Se incrementa a 4 el número de puertos USB 2.0.
  • Se sustituye la ranura SD por otra de MicroSD.
  • Se incrementa a 40 el número de pines de la ranura GPIO.
  • Mejoras en el circuito de audio


Foto del modelo B+ sacada de RS Online.


El modelo B+ se puede comprar desde hoy y al mismo precio que su predecesor.

08 julio, 2014

Un regalito

    Esta semana fue mi cumpleaños, así que para celebrarlo a lo grande y compartir con vosotros mi alegría, he decido crear un NPC de Oblivion con mi nombre. Lo podréis encontrar paseando por el distrito del mercado de la Ciudad Imperial y además, nuestro valiente Sebastián, podrá combatir a vuestro lado puesto que hace uso del mod CM Partners Mod Basic de Blackie (requerido para poder funcionar).




Descarga: Google Drive

---- ---- ---- ----
BONUS TRACK!



"My little Skyrim - SpectraDash"

07 julio, 2014

Mi primera experiencia con una tienda Apple

    A mediados de la semana pasada mi Macbook Pro de 2011 dejó de cargar. Así, como suena, era poner el cargador y no se activaba el led del Magsafe. En ese momento pasé por todas las etapas previas al asesinato: Me entró pánico por poder perder todo el contenido de mi equipo y posteriormente me indigné porque todos mis cachivaches de Apple acaban siendo pisapapeles caros. Mi mujer estuvo dándome ánimos en todo momento, remarcando que podía ser cosa del cargador y no del portátil.

En capítulos anteriores: Mac Mini, el pisapapeles.

    Porque esa es otra, si el portátil no carga la batería pueden ser por miles de cosas, desde el cargador que se ha estropeado, pasando por una falla del contacto en la placa o incluso una batería defectuosa. Me puse a googlear y puse el grito en el cielo al ver que los cargadores oficiales de Apple valen 80 euros. ¡Toma jeroma! ¿Qué los hacen con oro o algo? Vamos, que gástate tú 80 euros para comprobar que si lo que falla es el cargador o el portátil que se ha roto... Visto lo visto me puse a revisar en Amazon y comprobé que también existen cargadores truchos chinos, los cuales están llenos de votos negativos porque se ve que se rompen en menos de tres meses. El escenario para mi no podía ser más caótico, así que el viernes por la tarde cogí mi portátil y el cargador y me fui a la tienda Apple a ver si "con lo enrollados que son" me dejaban probar un cargador antes de comprarlo.

    Entré y me encontré con un modelo de negocio que nunca antes había visto en Valencia. Una planta baja con tropecientas tabletas y portátiles para probar. El sueño de cualquier padre que quiera librarse de sus hijos adolescentes durante toda su tarde, vamos. Ahí me veo con una serie de dependientes, me acerco a una y le comento mi situación. Acto seguido me lleva al fondo de la tienda, saco mi portátil y comparamos el estado con un cargador similar que tienen para esta clase de problemas. Ahí verificamos que lo que está roto es el cargador y me comenta que tengo dos opciones:
  • Comprar el cargador diréctamente por 80€.
  • Pasar el cargador como averiado y que me lo cambien por uno nuevo por 50€.
    Entonces los angelitos revolotearon por mi cabeza con campanas al vuelo cantando canciones de "¡Aleluya, aleluya!"... puesto que pese a que 50 pavos sigue siendo mucho dinero, por lo menos es un infarto menor al que desembolsar 80. Mi meta era primero verificar que era problema del cargador y segundo evitar pagar semejante bestialidad y mi objetivo se estaba cumpliendo. Ahora bien, la dependiente me remarcó que ella no podía realizar ese servicio, que debía de subir a la primera planta y pedir cita con el servicio técnico o bien hacer cola.

    Entonces subo (sí, tiene más de una altura) y me encuentro con lo mismo, un montonazo de tabletas y portátiles para que la gente toque y un ejército de dependientes ocupados: El que no vendía daba clase y el que no estaba en la "Genius Bar" (que cool suena eso) encargándose de los problemas. Así que me dirijo al final y me pongo a hacer cola. Ahí, una señora, muy bien vestida e indignada por la espera, espeta un "¡Si es que tenía que pedir cita! ¡Si pides cita te atienden enseguida!". Y yo en pantalón corto, chanclas, pelo hippie y teléfono Android del jurásico haciendo cola al rededor de gente cheta (rica) donde aparentemente todo el mundo adoraba a un Dios con forma de manzana.

    En fin, una vez es mi turno éste se fue volando, puesto que fue explicar mi problema al mozo y me contestó que al ser un portátil de 2011 éste estaba fuera de garantía, que de hacer el cambio apenas me ahorraba dos o tres euros y que no valía la pena, que fuera al fondo a comprar un cargador nuevo, que sería mejor. Así que voy a hacerle caso y me voy al otro extremo de la tienda a preguntar cual de todos tenía que comprar (puesto que el mozo anterior me dijo que debía ser un Magsafe de menos de 85W y en Google me decían que debía ser sí o sí de 60W) y ahí la respuesta del dependiente de ventas fue la misma que tuve de la primera dependienta: Que con temas de cargadores no hay garantía, que puedo exigir comprarlo por 50€.


    Yo me encontraba flipando, así que me fui otra vez a hacer cola y el chaval que me atendió me repitió lo mismo hasta que le corté con un: "pero es que tus compañeros me dicen que no son dos o tres euros que me ahorro, son treinta." En ese momento pude vislumbrar cómo al chaval se le transformó la cara en blanco pálido, momento en el que me llevó a un compañero para verificar que sí, que el cambio valía 50€, pero sin IVA. Es decir, que lo que quería hacer se podía hacer, pero por 60,50€ (IVA incluído), que la garantía del cambio era de 3 meses (comprarlo nuevo serían dos años) y que no podía hacerlo en el instante, que tenía que irme a la web de Apple, pedir cita con la Genius Bar (¿he dicho ya que mola ese nombre?), volver en la fecha señalada y hacer dicho cambio. Todo me pareció muy rebuscado y exageradamente burocrático, algo que entra en contraste con el modelo de guardería de poner a disposición del consumidor tropecientos iPad y Mac para que trastee "todo quisqui". De todas formas, viendo que aún así supondría un ahorro de 20 euros decidí aceptarlo.

    Así que al llegar a casa arranqué mi flamante Netbook con Fedora (como es lógico, si el portátil no carga, pues no lo puedo encender) y la primera en la frente. La web de Apple no es compatible con el navegador Midori, obligándome a instalar Chrome (o algo similar a Safari) para poder pedir cita. Eso sí, todos los pasos fueron mega fáciles de realizar y me permití el lujo de poner en observaciones que lo que quería era símplemente cambiar un cargador estropeado.

   El sábado llegué con media hora de adelanto a la tienda de Apple, así que decidí ir un momento a Mercadona (hay uno al lado) para comprarme una merienda. Ahí vi una oferta de 6 panecillos por un euro, así que con eso y un café latte "trucho" ya estaba más que servido. En la salida vi un mendigo, me acerqué a él, le di una limosna y mi corazón me obligó a ofrecerle un panecillo.
- "¡Gracias! ¡Me vendrá muy bien!" - Me dijo con una voz de extranjero mientras me cogía la bolsa con los seis panecitos.
- "No, no, te pregunto si quieres uno, no todos."
- "Gracias, sí, a mi gustar" - Me contesta con una sonrisa.
- "Que quería ofrecer sólo uno...".
- "Sí, gracias".
- "A ver, trae 'pacá' la bolsa." - Cojo la bolsa, la rompo, saco un panecillo para mí y le doy el resto. - "Ale, con esto estamos los dos contentos."

   Me levanto con la anécdota del día mientras el mendigo casi llora de alegría por tener cinco panecillos y una limosma, mientras me pregunta si sabía cuando jugaban Argentina y Bélgica. - "Ya deben de estar jugando, creo que empezaba a las seis."

    Llego a la Genius Bar (joder, sí que queda cool ese nombre) y me dan la mano, me preguntan si soy Sebastián, asiento, me preguntan si es por el tema del cargador y vuelvo a asentir. Les muestro mi portátil, se anota el número de serie para verificar el cargador exacto que hace falta... lo prueba... y saca toallitas y se pone a limpiarme el portátil hasta que éste queda como nuevo. Yo ahí ya me encontraba alucinando. Encima el "Genius" te daba conservación amena e incluso te daba consejos sobre cómo limpiar mejor el teclado. Es decir, el sistema estaba totalmente automatizado, se ve que se aprenden cual es tu problema y tu nombre antes de que llegues y además te dejan los equipos niquelados, si los traes.

- "Si te llego a decir que tengo instalado Linux, ¿me lo dejarías tan límpio?"
- "Con Linux no hay problema, ahora bien, si llega a ser Windows...".

    En menos de cinco minutos ya tenía mi cargador cambiado por otro, más barato que comprando uno nuevo y encima me habían dejado el portátil como los chorros del oro. Estos de Apple son de otro planeta.