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