Primer día sin SC2 Beta

Escribo este post desde el trabajo, ya que es mi primera mañana sin la beta del SC2 que me dio Blizzard el sabado. El mono es impresionante, y encima luego tengo uni, no se si aguantaré … Solo ayer me hecho como 20 partidas, entre 1vs1 o 2vs2.

Es un puto juegazo, ya en beta y lo será mucho más. Estoy de moemnto jugando como Zerg. Mucha gente dice que Zerg es simplón, ya que simplemente es ir a roaches + hydras, pero no siempre es así. Hay muchas estrategias. No veo a los Zerg tan under como dicen.

La gente dice que estan muy over los protoss pero de momento no he tenido problemas en petarlos, excepto uno que me saco 5 colosos y me peto las hydras. Otra gente dicen que los más overs son los humanos, podría ser, los putos segadores me tocan la moral, y me obligan a proteger a los curros con alguna torre.

Los que no tengis la Beta, podeis jugarla en plan pirata vs el PC. Por defecto la IA que viene no llega ni a A, le falta la I xD. Blizzard lo denomina “Muy fácil”, pero es que … como decirlo … ni ataca practicamente. En mediavida leí, que un tipo, ha desarrollado una IA mucho más decente que la de Blizzard.

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

Sony = pWn3d!

Ayer me llama mi novia diciendo, que ha visto en las noticias un bug en la playstation 3 y ha provado su consola (la gorda), y esta afectada. OMG!

El bug consiste en que en el algún momento entre el 28 de febrero y 1 de marzo todas las ps3 del mundo petaron. Es curioso que no importe la región, esto indica que es un bug del reloj interno que va con GMT +0.

Ayer sobre las 23:00 ya salimos del 29 bisiesto virtual en el que estaban todos los relojes internos del mundo y era muy posible que se arreglara el solo, sin parchear nada. Y así ha sido, las consolas han vuelto a funcionar hoy, simplemente corrigiendo el día.

El reloj interno es una marca de tiempo que se utiliza para cuando por ejemplo compras contenido DRM, como peliculas durante 24 horas. Se graba la marca de tiempo del reloj interno y se suma un offset de 24 horas, independientemente de la región. Sino se hiciera asi, podríamos quedarnos la película más de 24 de horas si estuvieramos retrasando el reloj continuamente.

Yo pienso que precisamente por eso, no se ha permitido conectar a PSN, además de por todas las incoherencias en logros, principalmente por evitar comprar contenido DRM en sistemas bugeados.

Le dejo a Sony una mini práctica que hice en primero para mostrar el calendario de cualquier año (>=1) o para para mostrar el mes actual:

program Actividad3;
{
Actividad 3
por Ricardo Marmolejo García
1º Ingienería Técnica Informática de Gestión
}

uses crt,dos;

const
   ANCHO_COL = 4;

var
   eleccion:integer;
   que_ano:integer;
   eleccion_str:string;
   que_ano_str:string;
   error:integer;

{
Funciones utilizadas en actividades anteriores:
pintar_marco()
mostrar_texto_centrado()
pintar_creditos()
}

procedure pintar_marco(x1,y1,ancho,alto:byte);
var
   x,y:byte;
   x2,y2:byte;
const
   DOBLE_BARRA_VERTICAL=186;
   DOBLE_BARRA_HORIZONTAL=205;
   ESQUINA_SUPERIOR_IZQUIERDA=201;
   ESQUINA_SUPERIOR_DERECHA=187;
   ESQUINA_INFERIOR_IZQUIERDA=200;
   ESQUINA_INFERIOR_DERECHA=188;

begin
   x2 := x1 + ancho;
   y2 := y1 + alto;

   for x := (x1+1) to (x2-1) do
   begin
      gotoxy(x,y1);
      write(chr(DOBLE_BARRA_HORIZONTAL));
      gotoxy(x,y2);
      write(chr(DOBLE_BARRA_HORIZONTAL));
   end;

   for y := (y1+1) to (y2-1) do
   begin
      gotoxy(x1,y);
      write(chr(DOBLE_BARRA_VERTICAL));
      gotoxy(x2,y);
      write(chr(DOBLE_BARRA_VERTICAL));
   end;

   gotoxy(x1,y1);
   write(chr(ESQUINA_SUPERIOR_IZQUIERDA));
   gotoxy(x2,y1);
   write(chr(ESQUINA_SUPERIOR_DERECHA));
   gotoxy(x1,y2);
   write(chr(ESQUINA_INFERIOR_IZQUIERDA));
   gotoxy(x2,y2);
   write(chr(ESQUINA_INFERIOR_DERECHA));
end;

procedure mostrar_texto_centrado(texto:string;altura:byte);
var
   centro_pantalla,centro_texto:byte;
const
   ANCHO_PANTALLA = 80;
begin
   centro_pantalla := ANCHO_PANTALLA DIV 2;
   centro_texto := length(texto) DIV 2;

   gotoxy(centro_pantalla - centro_texto , altura);
   write(texto);
end;

procedure pintar_creditos();
begin
   textcolor(8);
   mostrar_texto_centrado('ACTIVIDAD 3',23);
   mostrar_texto_centrado(CONCAT('por Ricardo Marmolejo Garc',chr(161),'a - 2006'),24);
   textcolor(15);
end;

////////////////////////////////////////////////////////////////////////////////

function esBisiesto(ano:integer):boolean;
{
ENTRADA: año que queremos evaluar
SALIDA: booleana
OBJETIVO: Nos dice si un año es bisiesto o no
}
begin
   esBisiesto := (ano MOD 4 = 0) AND ((ano MOD 100 <> 0) OR (ano MOD 400 = 0));
end;

function getLimiteDeEsteMes(mes:byte;ano:integer):byte;
{
ENTRADA: mes y ano
SALIDA: Nos devuelve el número del último dia del mes
OBJETIVO: Nos permite obtener el límite de cada mes
}
begin
   case mes of
      1:getLimiteDeEsteMes := 31;
      2:if(esBisiesto(ano)) then
          getLimiteDeEsteMes := 29
        else
          getLimiteDeEsteMes := 28;
      3:getLimiteDeEsteMes := 31;
      4:getLimiteDeEsteMes := 30;
      5:getLimiteDeEsteMes := 31;
      6:getLimiteDeEsteMes := 30;
      7:getLimiteDeEsteMes := 31;
      8:getLimiteDeEsteMes := 31;
      9:getLimiteDeEsteMes := 30;
      10:getLimiteDeEsteMes := 31;
      11:getLimiteDeEsteMes := 30;
      12:getLimiteDeEsteMes := 31;
   end;
end;

procedure parchear_diasemana(VAR diasemana:WORD);
{
ENTRADA: dia de la semana
OBJETIVO: si es domingo cambia el 0 a 7 quedando definido de 1-7
}
begin
   if(diasemana = 0) then
     diasemana := 7;
end;

function imprimir_un_mes(INICIO,FIN,diasemana,mes:byte):byte;
{
ENTRADA:
INICIO -----> inicio por el que comienza el mes , lo lógico es que sea 1 o el dia actual
FIN --------> fin para el mes , suele venir dado por getLimiteDeEsteMes()
diasemana --> dia de la semana del 1-7 en que comienza el mes
mes --------> del 1-12 mes que se va a imprimir
SALIDA:       dia de la semana del siguiente mes , con esto si llamamos reiteradas veces a esta función
              encadenamos los meses y lo que hacemos es imprimir un calendario
OBJETIVO: imprimir un mes
}
var
     i:byte;
     nombre_mes:string;
     ano_actual,mes_actual,dia_actual,diasemana_actual:word;

   function getNombreMes(mes:byte):string;
   {
   ENTRADA: mes del 1 al 12
   SALIDA: Nombre en String del mes
   OBJETIVO: Crea una relación del número del mes con su nombre
   }
   begin
      case mes of
         1:getNombreMes := 'Enero';
         2:getNombreMes := 'Febrero';
         3:getNombreMes := 'Marzo';
         4:getNombreMes := 'Abril';
         5:getNombreMes := 'Mayo';
         6:getNombreMes := 'Junio';
         7:getNombreMes := 'Julio';
         8:getNombreMes := 'Agosto';
         9:getNombreMes := 'Septiembre';
         10:getNombreMes := 'Octubre';
         11:getNombreMes := 'Noviembre';
         12:getNombreMes := 'Diciembre';
      end;
   end;

   procedure mostrar_cabezera_de_un_mes(titulo_del_mes:string);
   {
   ENTRADA: Entregamos el String del mes
   OBJETIVO: Nos muestra una cabezera del mes
   }
   begin
      writeln;
      writeln;
      textcolor(14);
      writeln(UPCASE(titulo_del_mes):ANCHO_COL*5);
      textcolor(7);
      writeln;
      write('   L   M   X   J   V   S');
      textcolor(12);
      writeln('   D');
      textcolor(15);
      writeln;
   end;

   procedure tabular_en_funcion_del_dia_de_la_semana(diasemana:byte);
   {
   ENTRADA: dia de la semana
   OBJETIVO: Nos tabula los meses para que cuadren los dias de la semana
            si empezamos en 1 (lunes) hay 0 tabulaciones
            si empezamos en 2 (martes) hay 1 tabulaciones
            si empezamos en 3 (miercoles) hay 2 tabulaciones
            si empezamos en 4 (jueves) hay 3 tabulaciones
            ...
            si empezamos en n hay (n-1) tabulaciones
   }
   var
      i:byte;
   begin
      for i:=1 to diasemana-1 do
          write('':ANCHO_COL);
   end;
begin
   GetDate(ano_actual,mes_actual,dia_actual,diasemana_actual);
   parchear_diasemana(diasemana_actual);
   nombre_mes := getNombreMes(mes);
   mostrar_cabezera_de_un_mes(nombre_mes);
   tabular_en_funcion_del_dia_de_la_semana(diasemana);
   for i:=INICIO to FIN do
   begin
      textcolor(15);
      // aqui no miro año , asi que puede ocurrir que coloree el dia de un año que tenga el mismo dia de la semana
      if(i = dia_actual) AND (mes = mes_actual) AND (diasemana = diasemana_actual) then
          textcolor(10)
      else if(diasemana = 7) then
          textcolor(12);

      write(i:ANCHO_COL);

      if(diasemana = 7) then
      begin
           writeln;
           diasemana := 1;
      end
      else
          diasemana := succ(diasemana);
   end;
   imprimir_un_mes := diasemana;
end;

procedure imprimir_calendario(que_ano:integer);
{
ENTRADA: Año del calendario que quieres ver
OBJETIVO: Mostrar el calendario
}
var
   i:byte;
   diasemana:byte;

  function CalcularPrimerDiaDeLaSemanaDeUnAno(ano:integer):byte;
  {
Esta función me ha costado pensarlo y no se si esta bien , he supuesto lo siguiente :
He observado que el 1 de enero del 2005 es Sabado(6) , el 1 de enero del 2006 es domingo (7),
el 1 de enero del 2007 es lunes (1) , el 1 de enero del 2008(bisiesto) es miercoles(3) (se ha saltado el martes)
de aqui deduzco una función recursiva. Supongo que el año 1 empieze en lunes ,(realmente empeze con 2006)
El año 2 se define:
   si el año anterior a 2 es bisiesto entonces
      El año 2 sera el año anterior a 2 + 2
   sino (no es bisiesto)
      El año sera el año anterior + 1
Para reiniciar al llegar a domindo uso MOD 7
Con esto consigo esta sucesión : 1 , 2 , 3 , 4  , 6 , 7 , 1 , 2 , 4  , 5 , 6 , 7 , 2 , 3 ...
Consigo definir todos los dias de la semana de los unos de eneros del año 1 en adelante
  ENTRADA: año
  SALIDA: dia de la semana del año introducido
  OBJETIVO: Al imprimir el calendario de un año , para definir este año solo necesito saber el dia de la semana del 1 de enero
  }
  begin
     if (ano <= 1) then         CalcularPrimerDiaDeLaSemanaDeUnAno := 1      else         if(esBisiesto(ano-1)) then           CalcularPrimerDiaDeLaSemanaDeUnAno := CalcularPrimerDiaDeLaSemanaDeUnAno(ano-1) + 2         else           CalcularPrimerDiaDeLaSemanaDeUnAno := CalcularPrimerDiaDeLaSemanaDeUnAno(ano-1) + 1;       if CalcularPrimerDiaDeLaSemanaDeUnAno > 7 then
          CalcularPrimerDiaDeLaSemanaDeUnAno := CalcularPrimerDiaDeLaSemanaDeUnAno MOD 7;
  end;

   procedure imprimir_cabezera_calendario();
   {
   OBJETIVO : Imprime un Titulo en color , indicando el AÑO
   }
   begin
      writeln;
      textcolor(10);
      writeln('               A',chr(164),'o ',que_ano);
      textcolor(15);
   end;

begin
   diasemana := CalcularPrimerDiaDeLaSemanaDeUnAno(que_ano);
   imprimir_cabezera_calendario();
   for i:= 1 to 12 do
     diasemana := imprimir_un_mes(1,getLimiteDeEsteMes(i,que_ano),diasemana,i);
end;

procedure imprimir_desde_HOY_hasta_el_proximo_mes();
{
OBJETIVO: Imprime un periodo aproximado de un mes , exactamente desde el dia X del mes actual
hasta el dia X del siguiente mes
}
var
   ano,mes,dia,diasemana:word;

   function getProximoMes(mes:integer):byte;
   {
   ENTRADA : Mes de referencia
   SALIDA : Siguiente mes respecto al mes de referencia
   OBJETIVO : Saber el proximo mes
   }
   begin
      if(mes = 12) then getProximoMes := 1
      else if(mes > 12) then getProximoMes := mes MOD 12
      else getProximoMes := mes+1;
   end;
begin
   GetDate(ano,mes,dia,diasemana);
   parchear_diasemana(diasemana);

   // imprimo el actual mes
   diasemana := imprimir_un_mes(dia, getLimiteDeEsteMes(mes,ano) , diasemana , mes               );
   // imprimo el proximo mes , sabiendo el dia de la semana que me devolvio la anterior
                imprimir_un_mes(1  , dia                         , diasemana , getProximoMes(mes));
end;

begin
   repeat
      clrscr;
      textcolor(15);
      pintar_marco(10,5,60,15);
      gotoxy(15,8);   writeln('1 . Imprimir un MES desde hoy hasta el proximo mes');
      gotoxy(15,10);  writeln('2 . Imprimir un calendario');
      gotoxy(15,12);  writeln('3 . Salir');
      pintar_creditos();
      gotoxy(15,16);
      write('Elije una opcion [1-3] : ');
      readln(eleccion_str);
      val(eleccion_str,eleccion,error);
      clrscr;
         case eleccion of
            1:
            begin
                 imprimir_desde_HOY_hasta_el_proximo_mes();
                 readkey;
            end;
            2:
            begin
                 writeln('Calendario del a',chr(164),'o ? (mayor o igual que a',chr(164),'o 1) : ');
                 readln(que_ano_str);
                 val(que_ano_str,que_ano,error);
                 if(error = 1) OR (que_ano < 1) then que_ano := 1;
                 clrscr;
                 imprimir_calendario(que_ano);
                 writeln;writeln;
                 readkey;
            end;
            3://salir
            else
            begin
                 mostrar_texto_centrado('Opcion incorrecta',10);
                 readkey;
            end;
         end;
   until(eleccion = 3);
end.

Ganas de matar aumentando …

Os pongo un par de links, no apto para todos los públicos.

El primero es un video, con titulo “Tefónica le va a tocar los cojones a Google”:
http://www.maceira.es/telefonica-le-va-a-tocar-los-cojones-a-google/

Esta comentado por los periodistas. Las mejor frase del ponente, patrocinado por Sergio:
“LA HINTELIHENSIA EHTA EN LAH REDEH Y LAH REDEH SON NUEHTRASSSSHHHHHHHHHH”

Poco más tarde Teddy Bautista hizo una entrevista a el periodico El País, donde uno de los temas de la conversión fue sobre Google y Telefónica.

http://www.elpais.com/articulo/cultura/logico/Telefonica/cobre/Google/nos/pague/elpepicul/20100301elpepicul_1/Tes

Solo con el titular de la noticia, ya esta todo dicho: “Lo lógico es que Telefónica cobre de Google y nos pague a nosotros”.

Bueno solo dejar mi opinión: el presidente de telefónica me parece un ignorante que cuando se pone hablar de las “TIC” (tecnologías de la información y la comunicación), no sabe ni de lo que habla, parece que esta borracho, y que le han explicado lo que tiene que decir en 5 minutos y malamente.

Pero vamos,  a mi todo esto me parece todo una puta broma para ver la reacción de los ciudadanos.

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

Feliz año 2010 !! La cosa va de Steam

Bueno perdonar por no postear el día 1, he estado estos días algo desconectado. Uno de los motivos son las ofertas del steam, que han sido la ostia. Estas son las ofertas:

Día 1 (23 de diciembre)
Defense Grid: The Awakening – 75% – comprado el ultimo día
Grand Theft Auto – 75% – repiten el ultimo día, pero ya lo tenía
Mirror’s Edge – 75% – No me entere de la oferta, lo quería
Operation Flashpoint: Dragon Rising – 50%
S.T.A.L.K.E.R: Shadow of Chernobyl – 90%- comprado el ultimo día

Día 2
Football Manager™ 2010 – 25%
iD Super Pack – 66%
Left 4 Dead 2 – 33%- repiten el ultimo día, pero ya lo tenía
Need for Speed: Shift – 25%
Serious Sam HD – 50%

Día 3
Red Faction Guerilla – 75%
Battlefield 2: Complete Collection – 75% – No me entere de la oferta, lo quería, MIERDA xD
King’s Bounty: Armored Princess – 75%
Resident Evil 5 – 50% – No me entere de la oferta, lo quería
Cogs – 80%
Elf Bowling: Hawaiian Vacation – 1 dolar

Día 4
Lumines™ and the Lumines™ Base+Advance Pack – 80%
Torchlight – 75% – COMPRADO el último día
Star Wars Premier Pack – 50%
Universe at War: Earth Assault – 75%
Prototype™ – 50% – Lo he jugado en PS3 y no me gusto nada.
Dragon Age: Origins y su versión Digital Deluxe Edition – 25% – mala oferta

Día 5
Hearts of Iron III – 75%
Zombie Driver – 75%
Day of Defeat: Source – 75% – Arrepentido, me lo debí comprar
Dead Space – 66%
Complete PopCap Collection – 50%

Día 6
Space Siege – 75%
Burnout Paradise: The Ultimate Box – 75%- Arrepentido, me lo debí comprar
The Orange Box – 50% – YA LO TENÍA
Prey – 85% – Quería comprarlo pero se agotaron las CDKEYS :(
Killing Floor – 75% – COMPRADO el último día.

Día 7
Stormrise – 75%
Jade Empire – 75%
King Arthur: The Role-playing Wargame – 50%
Company of Heroes: Tales of Valor – 75%f – No era mala oferta, pero no …
Silent Hill Homecoming – 75% – No me entere de la oferta, lo quería
Mr. Robot – 80%

Día 8
FIFA Manager 10 – 33%
Call of Duty: World at War – 50% – Ya lo tenía
Left 4 Dead – 75% – YA LO TENIA
Max Payne – 75% – COMPRADO

Max Payne 2 – 75% – COMPRADO
Sid Meier’s Civilization IV + 3 expansiones – 75% – COMPRADO, ofertaza
Osmos – 80%

Día 9
Medieval II: Total War – 75% – COMPRADO, tambien me pille el Rome: Total War
Crysis Maximum Edition – 66% – Esta a 10€ el 1 …
Half-Life: Source – 75%
Street Fighter IV – 75% – Ya lo tenía
Multiwinia + Darwinia – 80%
Shattered Horizon – 75% – Medio arrepentido, debí comprarlo

Día 10
Todos los DOOM, incluyendo el Complete Pack – 66%
Sam & Max Complete Seasons 1 & 2 – 75%
Mass Effect – 75% – COMPRADO
Portal – 75% – YA LO TENÍA
RedLynx Trials 2: Second Edition – 75% – COMPRADO, No juego a otra cosa, que vicio.
Devil May Cry 4 – 25%

Día 11
Trine – 75% – COMPRADO
The Elder Scrolls III: Morrowind® Game of the Year Edition – 75%
Counter-Strike: Source – 75% – COMPRADO (es un sacrilegio pero no lo tenía en mi cuenta)
Painkiller: Collectors Pack – 75%
Todos los Command & Conquer – 66%

El Último Día (3 de enero)
BioShock – 75% – COMPRADO
Grand Theft Auto IV – 75% – YA LO TENIA
Torchlight – 75% – COMPRADO
Left 4 Dead 2 – 33% – YA LO TENIA
Killing Floor – 75%- COMPRADO
Defense Grid: The Awakening – 75%- COMPRADO
S.T.A.L.K.E.R.: Shadow of Chernobyl – 90% – COMPRADO

Normalmente me puedo gastar en juegos en navidad unos 120€ o incluso más, obteniendo 2 o 3 juegos de nuevo lanzamiento, pero estas navidades todos estos juegos, en formato digital me han costado unos 70€ y tengo unos 20 juegos.

Desde ahora no voy a compar un juego en tienda si vale más de 10€.  De hecho tenía comprado el GTAIV en tienda, y apunto estuve de volver a comprarlo por steam simplemente por el coñazo de que me pide CD al jugar.

En steam ningún juego te pide disco, te puedes hacer tu propio disco backup con un mix de todos tus juegos y así evitarte las futuras descargas, los juegos son más baratos, hay toda una comunidad y otros valores añadidos.

Esta es mi opinión sobre steam ahora, pero en un futuro puede cambiar ya que en el pasado no me convencía mucho, ya que steam surge como una forma de comercializar el counter-strike y yo en ese momento estaba en clanes, no tenía mucho pasta … pero al final a los antiguos usuarios le “regalarón”(ya era gratuito, evidentemente) el counter strike y derivados, algo lógico, pero hay esta la clave de su éxito como para empezar a confiar en ellos.

Ahora los precios han vuelto a subir mucho, así que tendré que esperar a la siguiente navidad o derivados.

Otro motivo por el que he comprado más juegos de lo normales, es que ayer me llego un pedido de 4 frags para montar el resto de piezas que me faltaban.

En “mi tienda” a precio del proveedor ACROSS consegui:
AMD Phenom™ II X4 965 3,4Ghz a 120€
Gigabyte GA-MA790XT-UD4P a 85€
Seagate 1,5 TB por 60€

En el media markt me pille una grabadora LG 22x normalita por 29€, en caja(con software).

Primer pedido a 4 frags:

1 x Alfombrilla SteelSeries QcK+   
14.95EUR
1 x Caja Cooler Master HAF 922   
97.58EUR
1 x Sharkoon SATA Quickport   
26.10EUR
1 x Ratón Razer DeathAdder – Optico   
47.56EUR

Segundo pedido a 4 frags:

1 x Fuente Corsair CMPSU-TX750 – 750W   
111.94EUR
1 x Disipador CPU Noctua NH-U12P SE2 – Socket 1156/1366/AMD   
55.99EUR
1 x ATI XFX Radeon 5870 – XXX Edition – HDMI – 1GB (Dirt 2 Incluido)   
359.60EUR
1 x Pasta Térmica Arctic Cooling MX-2 – 4g   
4.41EUR
1 x OCZ3P1866LV4GK – Memoria OCZ DIMM 4GB (2×2) DDR3-1866 Platinum L   
121.80EUR
1 x Lector DVD LG 16X OEM SATA – Negro (Canón Incluido)   
16.82EUR
1 x Teclado a4tech Gamemaster KB-28G – En español   
9.99EUR
1 x Refrigerador portatil Cooler Master Notepal D1   
16.74EUR
1 x Microfono Zalman ZM-MIC1   
8.95EUR

Además estaba montando 2 ordenas casi clones (edit: uno para mi y otro para mi novia ;* ) asi que 4 frags me debería considerar buen cliente xD.

Asi que me voy a liar todo esto esta tarde, y si os interesa algún hardware concreto os puedo contar que tal va.

Estoy bastante estresado estos días, debería estar estudiando Estadística y/o Gestión , Administración de Empresas, Redes pero con los turrones, polvorones, juegos del steam no soy capaz de abrir un libro, y eso me hace sentir un poco mal. Este año me tengo que sacar Estadísitica como sea, ya que es la única que me queda de segundo, y este año extinguen 2º presencial. Además no quiero dejar de lado Wiithon que es mi primer proyecto de software libre importante y debo dormir bien para rendir en el curro. (programo como LAMP).

Bueno, que os traigan muchas cosas los reyes!

Sistemas de Información Geográfica “paranoyantes”

Aquí pongo algunos sistemas de información para la prevención/detección de catástrofes. Esto se me ha ocurrido a raíz de que hace una hora ha habido un terremoto en el oceano pacífico, al este del estrecho de Gibraltal.

Bueno, os pongo el de los terremotos y alguno que tenía en favoritos:

Terremetos en el mundo en los últimos 7 días (.gov)
Riesgo de meteoritos sobre el planeta en los próximos 100 años.(.gov)
Prevención de Huracanes (.gov)
Volcanes en activo (el dominio no garantiza que sea una fuente fiable)

David Bravo en 59 segundos, sublime

Me imagino que conocereis este famoso abogado especializado en derecho informático y especialmente en derechos de autor. Ya ha sido invitado prácticamente ha todos los debates televisivos sobre derecho a copia privada y derechos en Internet en general.

Os diré que este tipo es en una palabra, un FENÓMENO. Por dando va, reparte ostias par todos, es el foco del debate y deja planchado a cualquiera. Por supuesto por mucha ORATORIA que tenga David (y sea el único en saber como comunicar ideas que otras personas compartimos), esto se consigue debido a que el bando opuesto del debate, sin duda no tiene razón, esta errado, forma parte del lado oscuro, o como queráis llamarlo.

El programa ha terminado hace pocas horas y no he encontrado ningún video para pastearos frases literales y objetivas. Os recomiendo que lo busqueis, no obstante os dejo una imagen con un resumen con una de las conversiones con Enrique Urbizu que mejor lo he pasado. (No tomeis las frases al pie de la letra, son interpretaciones de mi recuerdo).


Todos los miembros invitados son: el compositor y consejero de la SGAE, José Miguel Fernández Sastrón; el director de cine y presidente de DAMA (Derechos de Autor de Medios Audiovisuales), Enrique Urbizu; el periodista y bloggero, Ignacio Escolar; el presidente de AETIC, la patronal de las empresas de comunicación, Jesús Banegas; el escritor, Lorenzo SilvaPOR SUPUESTO el abogado especialista en propiedad intelectual y derecho informático, David Bravo

Enlaces:
Web de 59 segundos
Blog de David Bravo

Pasar secuencia de imagenes a video

En concreto lo estoy utilizando para las animaciones generadas por blender en archivos png:

ffmpeg -y -f image2 -i %4d.png -b 10800k render.avi && gnome-open render.avi

Guía para principiantes en Blender 2.5

Hemos tenido que esperar mucho para poder degustar la delicatessen que la Fundación Blender ha liberado hace unos pocos días. La versión 2.5 es mucho más que un simple paso de las 2.4x a las 2.5x; es el comienzo de una nueva manera de entender Blender. No sólo tenemos que olvidarnos de las eternas críticas a aquella poco amigable interfaz de carácter “in house”  sino que podemos afirmar que la estética de la nueva propuesta es elegante a más no poder. Por no hablar de la organización de las herramientas que es totalmente coherente (aunque debamos hacer un esfuerzo por aprender de nuevo dónde está cada cosa)

Versión Online
Versión PDF

Fuente:
http://www.blendernation.com/blender-2-5-beginners-guide-in-spanish/
http://joaclintistgud.wordpress.com/2009/11/27/blender-guia-de-iniciacion-para-recien-llegados-adaptada-a-la-version-2-5/

Wiithon 1.1 publicado!

Actualizado: sábado, 21 de noviembre de 2009

Bueno por fin publicamos la nueva versión tras casi 5 meses desde el anuncio de la 1.0.
Para mi wiithon me ha aportado mucho en conocimientos, me he acostumbrado tras muchos años de SQL puro, el uso de bases de datos ORM. He aprendido la potencia del combo python + pygtk. He aprendido a crear paquetes deb que siguen las políticas de Debian. Crear manpages, hacerme un repositorio de paquetes, resolver conflictos de bazaar, subir paquetes, comprender los problemas de punteros en 32bits y 64 bits y por último, he aprendido a amar a los Makefiles y esa gran satisfacción de hacer cosas complejas de forma controlada y sencilla.

Sin más rollo os pongo un tutorial mucho más simplificado, si lo comparamos con el de la versión anterior:

  1. Novedades
  2. Características ya existentes
  3. Reporte de bugs
  4. Instalación
  5. Actualización
  6. Uso de Wiithon en Consola (CLI)
  7. Descargar código fuente
  8. Colaborar en Wiithon
  9. Estado de traducción de Wiithon.
  10. Team wiithon
  11. Pantallazos

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

Significado pitidos de la placa base

Me apunto aquí una chuleta con los errores del POST de la BIOS. Como sabeis esto cambio dependiendo del desarrollador de la BIOS, pero más o menos esto es un consenso. No obstante iré actualizando cuando no se cumpla:

No hay pitidos No hay suministro electrico o el parlante de sistema esta desconectado o defectuoso
1 pitido corto Arranque normal.
Pitido constante ininterrumpido Falla en el suministro electrico
Pitidos cortos y constantes placa base defectuosa.
1 pitido largo Error de memoria RAM.
RAM Refresh Failure. Los diferentes componentes encargados del refresco de la memoria RAM fallan o no están presentes.
1 pitido largo, 1 corto Fallo general en la placa madre o ROM básica del sistema
1 pitido largo,2 cortos No se encuentra la tarjeta de video, puede estar mal instalada o bien defectuosa.
1 pitido largo, 3 cortos No se encuentra monitor conectado a la tarjeta gráfica.
1 pitido largo, varios cortos Falla relacionada con el video (depende del tipo de tarjeta de video y del la configuración de la bios)
2 pitidos largos y uno corto Falla en la sincronización de imágenes
2 pitidos cortos Error de paridad de memoria. La paridad no es soportada por la placa base.
3 pitidos cortos Fallo de memoria en los primeros 64 Kbytes de la RAM.
4 pitidos cortos El temporizador o contador de la placa base se encuentra defectuoso. El Timer 1 de la placa no funciona.
5 pitidos cortos La CPU ha generado un error porque el procesador o la memoria de vídeo está bloqueada.
6 pitidos cortos El controlador o procesador del teclado (8042) puede estar en mal estado. La bios no puede conmutar en modo protegido. Este error se suele dar cuando se conecta/desconecta el teclado con el ordenador encendido.
7 pitidos cortos La CPU ha generado una interrupción excepcional o el modo virtual del procesador está activo.
8 pitidos cortos El adaptador de vídeo ( tarjeta gráfica) del sistema no existe o su memoria de vídeo (RAM) está fallando. No es un error fatal. Es un fallo de escritura de la Video RAM.
9 pitidos cortos Error de conteo de la Video RAM. El valor del checksum (conteo de la memoria) de la RAM no coincide con el valor guardado en la bios.
10 pitidos cortos El registro de la CMOS RAM falla a la hora de la desconexión.
11 pitidos cortos La memoria caché externa está fallando. En la bios hay una opción llamada video memory cacheable, que lo que hace es volcar el contenido de la ram de la tarjeta en el disco duro. Ponla en enable, haber si soluciona tu problema.
2 pitidos cortos Se ha detectado un error al realizar uno de los tests de hardware.
Pitidos cortisimos, tenues y constantes Posiblemente el teclado provoca este error o bien una tecla presionada durante el arranque.

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()