viernes, 30 de noviembre de 2007

Soy HEAVY

No puede reprimir su origen de heavy metal.

Mark Hamil. Atrapado en el tiempo

Mark Hamil. Atrapado en el tiempo
El actor que interpretaba a Luke Skywalker se enfrenta a su particular "día de la marmota".

miércoles, 28 de noviembre de 2007

El reto de Chuck Norris‏

Un importante proyecto de decodificacion de mensajes para el gobierno que fúe
desarrollado por el mismisimo Chuck Norris (que escribe cualquier programa en una sola linea)
necesita ser puesto en marcha lo antes posible. Lamentablemente, Chuck Norris eliminó del control
de codigo fuente su libreria de utilidades antes de irse de la empresa para probar
nuevos retos
, por lo que el código ya no compila.
Es necesario que alguien reconstruya las partes necesarias de esta libreria para volver a hacer
funcionar el decodificador. Una pista, nadie hace librerias tan simples como Chuck Norris.

Ánimo y gracias por tu interés y tiempo. Espero te diviertas

Console.WriteLine(
new long[]{
292805444303323170,
-4455112766532738942,
579137309091315972,
1207248581508040306,
7033655460037132288 }
.SelectMany(l => 64.DownTo(0)
.Select(i => (l & ((long)1 << i)) != 0))
.Take(285)
.Select((b, i) => new { b, i })
.GroupBy(p => p.i / 3, p => p.b)
.Select(g => g.ToArray())
.Select(a => 0.To(3)
.Sum(i => a[i] ? (1 << (2 - i)) : 0))
.Select((a, i) => new { c = @" _()/'\,"[a], i })
.GroupBy(p => p.i / 19, p => p.c)
.Select(g => new string(g.ToArray()))
.Aggregate((s, t) => s + "\r\n" + t));

public static class ExtensionesChuckNorris
{
public static IEnumerable.int To(this int a, int b)
{
//TODO: Completar código
}
public static IEnumerable.int DownTo(this int a, int b)
{
//TODO: Completar código
}
}

La oferta, original como pocas, recibió sus 15 segundos de fama (estoy seguro de que si Warhol hubiera conocido Internet, la frase hubiera sido en segundos) siendo vinculada por unos cuantos blogs y foros. A mí me interesaba más resolverla, la verdad. Así que llegué a casa el viernes por la noche y me puse a ello. Si le echamos un vistazo por encima (y somos de los que, al menos, leemos blogs) podemos ver que en ese pedazo de bloque de código aparentemente ilegible se declara un array de tipo long, que se rellena con un montón de números aparentemente sin sentido a los que a continuación y sin un pobre punto y coma que llevarse a la boca se le ejecutan un montón de operaciones con nombres como Select, GroupBy, o Aggregate. Esto tiene toda la pinta de ser LINQ. Primer problema: no tengo ni repajolera idea de LINQ.


Don't panic


Bueno, me dije, ignora ese bloque de momento. Sabes que es un array de tipo long al que se le hacen un montón de transformaciones mediante LINQ. Puedes suponer que el resultado no van a ser números sino caracteres, por la presencia de un sospechoso cast a String y un par de cadenas. Bien. ¿Qué pide exactamente el problema? Concretamente, nos piden que implementemos dos de esas transformaciones: To(int a, int b) y DownTo(int a, int b). Mirando en el código principal, vemos que las llamadas a estas funciones son 64.DownTo(0) y 0.To(3). Es una sintaxis un tanto extraña, y aparentemente no tiene nada que ver con la firma de las funciones, pero puedo suponer que 64.DownTo(0) es equivalente a DownTo(64, 0). DownTo se podría traducir por Hasta, y teniendo en cuenta que el tipo que debe devolver la función es un IEnumerable<int>, podemos suponer que DownTo debe devolver un rango de números desde a hasta b en orden descendente, y que la función To debe devolver un rango de números desde a hasta b en orden ascendente. Vale, ya entendemos el problema. Intentemos implementarlo.


Intento y error


LINQ está disponible a partir de la versión 3.5 del .NET Framework, y sinceramente no tengo ganas de ponerme a buscarlas e instalarlas. El problema de las betas, CTPs, RTMs y demás versiones de early-adopters es que suelen ser algo puñeteras en su instalación y configuración, y el problema ahora era de código, no tenía ganas de comerme la cabeza con configuraciones. Virtual PC 2007 con la imagen completa de Windows 2003 Server y la última Beta de VS2008 al rescate. Sí, es una descarga de 11 Gbs, pero para hacer pruebas locas es perfecto. Una vez tenemos las herramientas necesarias (aunque eché bastante de menos a mi ReSharper, a ver cuándo hacen versión para el 2008), nos ponemos a currar.


Intenté primero hacer las cosas a lo sencillo: un simple bucle for que creara un array de integers desde a hasta b, convertirlo a IEnumerable<int> y a tirar. Pero no hubo manera humana de hacerlo, o yo no la encontré... y menos mal, porque aunque hubiera funcionado ésa no era la respuesta. Tenía que haber una manera de hacerlo mediante LINQ.


Después de mucho googlear, me encontré con unos cuantos recursos valiosos, entre ellos esta wiki sobre LINQ, y sobre todo este artículo de MSDN, que me pusieron sobre la pista correcta. Concretamente, conocí la existencia de la clase System.Linq.Enumerable, concretamente de su operador Range que, mira por dónde, devuelve un rango IEnumerable<int>. Parece que la función To estaba resuelta. ¿Y la función DownTo?



Al principio intenté unas cuantas manipulaciones groseras de Range, pero recordé que el reto me pedía soluciones sencillas, pues tal es el estilo de programación de Chuck... cosa que, viendo sus películas, dudo mucho. Pero ésa es otra cuestión. Seguí leyendo e investigando y me encontré con otro operador de System.Linq.Enumerable, el Reverse, que efectivamente era la solución que andaba buscando. Un poquito de intento y error para hacer las cosas lo más limpias posibles y voilá!: el reto de Chuck está solucionado.


Aquí tenéis el código completo:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ilitia
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(
new long[]{
292805444303323170,
-4455112766532738942,
579137309091315972,
1207248581508040306,
7033655460037132288 }
.SelectMany(l => 64.DownTo(0)
.Select(i => (l & ((long)1 << i)) != 0))
.Take(285)
.Select((b, i) => new { b, i })
.GroupBy(p => p.i / 3, p => p.b)
.Select(g => g.ToArray())
.Select(a => 0.To(3)
.Sum(i => a[i] ? (1 << (2 - i)) : 0))
.Select((a, i) => new { c = @" _()/'\,"[a], i })
.GroupBy(p => p.i / 19, p => p.c)
.Select(g => new string(g.ToArray()))
.Aggregate((s, t) => s + "\r\n" + t));

Console.ReadLine();
}
}

public static class ExtensionesChuckNorris
{
/// <summary>
/// Devolvemos un rango enumerable desde inicio a fin.
/// </summary>
/// <param name="a">Valor inicial</param>
/// <param name="b">Valor final</param>
/// <returns>Un rango ascendente</returns>
public static IEnumerable<int> To(this int a, int b)
{
return Enumerable.Range(a, b);
}

/// <summary>
/// Devolvemos un rango inverso enumerable desde fin a inicio.
/// </summary>
/// <param name="a">Valor inicial</param>
/// <param name="b">Valor final</param>
/// <returns>Un rango descendente</returns>
public static IEnumerable<int> DownTo(this int a, int b)
{
//Invocamos To y le damos la vuelta
return Enumerable.Reverse(b.To(a));
}

Y éste es el resultado por pantalla:

Y esto es todo, amigos. Gracias a Fernando Lozano, gerente de Ilitia, que amablemente me ha dado permiso para escribir este post al haber terminado el reto y no aceptar más candidaturas para esa oferta.

Fuente noticia: http://www.picacodigos.com

Enjuto Mojamuto y Explorer

Mira quien se queja:

RMI - Ejemplo


Ejemplo RMI


Un servidor RMI consiste en definir un objeto remoto que va a ser utilizado por los clientes. Para crear un objeto remoto, se define una interfaz, y el objeto remoto será una clase que implemente dicha interfaz. Veamos como crear un servidor de ejemplo mediante 3 pasos:



  • Definir el interfaz remoto. Cuando se crea un interfaz remoto:

    • El interfaz debe ser público.

    • Debe extender (heredar de) el interfaz java.rmi.Remote, para indicar que puede llamarse desde cualquier máquina virtual Java.

    • Cada método remoto debe lanzar la excepción java.rmi.RemoteException en su claúsula throws, además de las excepciones que pueda manejar.






public interface MiInterfazRemoto extends java.rmi.Remote
{
public void miMetodo1() throws java.rmi.RemoteException;
public int miMetodo2() throws java.rmi.RemoteException;
}


  • Implementar el interfaz remoto




public class MiClaseRemota
extends java.rmi.server.UnicastRemoteObject
implements MiInterfazRemoto
{
public MiClaseRemota() throws java.rmi.RemoteException
{
// Código del constructor
}

public void miMetodo1() throws java.rmi.RemoteException
{
// Aquí ponemos el código que queramos
System.out.println("Estoy en miMetodo1()");
}

public int miMetodo2() throws java.rmi.RemoteException
{
return 5; // Aquí ponemos el código que queramos
}

public void otroMetodo()
{
// Si definimos otro método, éste no podría llamarse
// remotamente al no ser del interfaz remoto
}

public static void main(String[] args)
{
try
{
MiInterfazRemoto mir = new MiClaseRemota();
java.rmi.Naming.rebind("//" + java.net.InetAddress.getLocalHost().getHostAddress() +
":" + args[0] + "/PruebaRMI", mir);
}
catch (Exception e)
{
}
}
}


  • Como se puede observar, la clase MiClaseRemota implementa el interfaz MiInterfazRemoto que hemos definido previamente. Además, hereda de UnicastRemoteObject, que es una clase de Java que podemos utilizar como superclase para implementar objetos remotos.

  • Luego, dentro de la clase, definimos un constructor (que lanza la excepción RemoteException porque también la lanza la superclase UnicastRemoteObject), y los métodos de la/las interfaz/interfaces que implemente.

  • Finalmente, en el método main, definimos el código para crear el objeto remoto que se quiere compartir y hacer el objeto remoto visible para los clientes, mediante la clase Naming y su método rebind(...).


Nota: Hemos puesto el método main() dentro de la misma clase por comodidad. Podría definirse otra clase aparte que fuera la encargada de registrar el objeto remoto.



  • Compilar y ejecutar el servidor


Ya tenemos definido el servidor. Ahora tenemos que compilar sus clases mediante los siguientes pasos:





    • Compilamos el interfaz remoto. Además lo agrupamos en un fichero JAR para tenerlo presente tanto en el cliente como en el servidor:





javac MiInterfazRemoto.java
jar cvf objRemotos.jar MiInterfazRemoto.class




    • Luego, compilamos las clases que implementen los interfaces. Y para cada una de ellas generamos los ficheros Stub y Skeleton para mantener la referencia con el objeto remoto, mediante el comando rmic:





set CLASSPATH=%CLASSPATH%;.\objRemotos.jar;.
javac MiClaseRemota.java
rmic -d . MiClaseRemota

Observamos en nuestro directorio de trabajo que se han generado automáticamente dos ficheros .class (MiClaseRemota_Skel.class y MiClaseRemota_Stub.class) correspondientes a la capa stub-skeleton de la arquitectura RMI.



  • Para ejecutar el servidor, seguimos los siguientes pasos:

    • Se arranca el registro de RMI para permitir registrar y buscar objetos remotos. El registro se encarga de gestionar un conjunto de objetos remotos a compartir, y buscarlos ante las peticiones de los clientes. Se ejecuta con la aplicación rmiregistry distribuida con Java, a la que podemos pasarle opcionalmente el puerto por el que conectar (por defecto, el 1099).




En el caso de Windows, se debe ejecutar:



start rmiregistry 1234

Y en el caso de Linux:



rmiregistry &






    • Por último, se lanza el servidor:





java -Djava.rmi.server.hostname=127.0.0.1 MiClaseRemota 1234


  • Crear un cliente RMI


Vamos ahora a definir un cliente que accederá a el/los objeto/s remoto/s que creemos. Para ello seguimos los siguientes pasos:





    • Definir la clase para obtener los objetos remotos necesarios




La siguiente clase obtiene un objeto de tipo MiInterfazRemoto, implementado en nuestro servidor:




public class MiClienteRMI
{
public static void main(String[] args)
{
try
{
MiInterfazRemoto mir = (MiInterfazRemoto)java.rmi.Naming.lookup("//" +
args[0] + ":" + args[1] + "/PruebaRMI");

// Imprimimos miMetodo1() tantas veces como devuelva miMetodo2()
for (int i=1;i<=mir.miMetodo2();i++) mir.miMetodo1();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
}

Como se puede observar, simplemente consiste en buscar el objeto remoto en el registro RMI de la máquina remota. Para ello usamos la clase Naming y su método lookup(...).





    • Compilar y ejecutar el cliente




Una vez que ya tenemos definido el cliente, para compilarlo hacemos:



set CLASSPATH=%CLASSPATH%;.\objRemotos.jar;.
javac MiClienteRMI.java

Luego, para ejecutar el cliente hacemos:



java MiClienteRMI 127.0.0.1 1234

Se debe poder acceder al fichero Stub de la clase remota. Para ello, o bien lo copiamos al cliente y lo incluimos en su CLASSPATH, o lo eliminamos del CLASSPATH del servidor e incluimos su ruta en el java.rmi.codebase del servidor (si no se elimina del CLASSPATH del servidor, se ignorará la opción java.rmi.codebase, y el cliente no podrá acceder al Stub).. Si echamos un vistazo a la ventana donde está ejecutándose el servidor RMI, veremos como se ha encontrado el objeto remoto y ejecutado sus métodos

RMI-Java

RMI (Java Remote Method Invocation) es un mecanismo ofrecido en Java para invocar un método remotamente. Al ser RMI parte estándar del entorno de ejecución Java, usarlo provee un mecanismo simple en una aplicación distribuida que solamente necesita comunicar servidores codificados para Java. Si se requiere comunicarse con otras tecnologías debe usarse CORBA o SOAP en lugar de RMI.

Al estar específicamente diseñado para Java, RMI puede darse el lujo de ser muy amigable para los programadores, proveyendo pasaje por referencia de objetos (cosa que no hace SOAP), "recolección de basura" distribuida y pasaje de tipos arbitrarios (funcionalidad no provista por CORBA).

Por medio de RMI, un programa Java puede exportar un objeto. A partir de esa operación este objeto está disponible en la red, esperando conexiones en un puerto TCP. Un cliente puede entonces conectarse e invocar métodos. La invocación consiste en el "marshaling" de los parámetros (utilizando la funcionalidad de "serialización" que provee Java), luego se sigue con la invocación del método (cosa que sucede en el servidor). Mientras esto sucede el llamador se queda esperando por una respuesta. Una vez que termina la ejecución el valor de retorno (si lo hay) es serializado y enviado al cliente. El código cliente recibe este valor como si la invocación hubiera sido local.

La arquitectura RMI puede verse como un modelo de cuatro capas:

Primera capa
La primera capa es la de aplicación y se corresponde con la implementación real de las aplicaciones cliente y servidor. Aquí tienen lugar las llamadas a alto nivel para acceder y exportar objetos remotos. Cualquier aplicación que quiera que sus métodos estén disponibles para su acceso por clientes remotos debe declarar dichos métodos en una interfaz que extienda java.rmi.Remote. Dicha interfaz se usa básicamente para "marcar" un objeto como remotamente accesible. Una vez que los métodos han sido implementados, el objeto debe ser exportado. Esto puede hacerse de forma implícita si el objeto extiende la clase UnicastRemoteObject (paquete java.rmi.server), o puede hacerse de forma explícita con una llamada al método exportObject() del mismo paquete.

Segunda capa
La capa 2 es la capa proxy, o capa stub-skeleton. Esta capa es la que interactúa directamente con la capa de aplicación. Todas las llamadas a objetos remotos y acciones junto con sus parámetros y retorno de objetos tienen lugar en esta capa.

Tercera capa
La capa 3 es la de referencia remota, y es responsable del manejo de la parte semántica de las invocaciones remotas. También es responsable de la gestión de la replicación de objetos y realización de tareas específicas de la implementación con los objetos remotos, como el establecimiento de las persistencias semánticas y estrategias adecuadas para la recuperación de conexiones perdidas. En esta capa se espera una conexión de tipo stream (stream-oriented connection) desde la capa de transporte.

Cuarta Capa
La capa 4 es la de transporte. Es la responsable de realizar las conexiones necesarias y manejo del transporte de los datos de una máquina a otra. El protocolo de transporte subyacente para RMI es JRMP (Java Remote Method Protocol), que solamente es "comprendido" por programas Java.

Información extraida de wikipedia

El precio de los pisos

"La nómina de mi padre en diciembre de 1979 era de 38.000 pesetas. Él trabajaba como peón en una obra. En ese mismo momento le ofrecieron comprar una casa. Le pedían un total de 500.000 pesetas por ella. Decidió no arriesgar y continuar vivi endo en régimen de alquiler, en unas condiciones muy buenas. Se trataba de una casa modesta pero muy bien ubicada, en pleno centro de un pueblo cercano a Barcelona.

A los pocos meses mi padre y mi madre compraron un terreno en otro pueblo de la misma provincia y en menos de cinco años de esfuerzo ya habían levantado y pagado una vivienda de 120m2. Han pasado 27 años. En 2006 y en el mismo pueblo donde viven, un piso modesto de 75m2 a las afueras no se encuentra por menos de 35 millones de pesetas, y estoy siendo muy generoso.

En el año 1979 el coste de un piso era del orden de 14 mensualidades de un peón de obra
38.000 pts/mes x 14 meses = 532.000pts.
El sueldo en 2006 de un universitario recién titulado en ingeniería informática sin experiencia profesional no llega a las 200.000 pesetas mensuales. En el año 2006 una vivienda modesta cuesta 175 mensualidades (14 anualidades!!!!) de un ingeniero informático
200.000 pts/mes x 175 meses=35.000.000 pts.

Los jóvenes de hoy necesitaríamos cobrar 2,5 millones de pesetas mensuales para estar en igualdad de condiciones con nuestros padres que compraron una vivienda a principios de los años 80. 2.500.000 pts/mes x 14 meses = 35 Mill. de pts.

Los pisos en el año 2006 deberían costar 2,8 millones de pesetas para que los jóvenes de hoy estemos en igualdad de condiciones con nuestros padres en 1979. 200.000 pts/mes x 14 meses = 2.800.000 pts No encuentro adjetivo alguno en el año 2006 para calificar lo que mi padre consideró arriesgado en 1979.

Está claro que los pisos no van a pasar a costar de la noche a la mañana 30 veces menos, de 35 a 3 millones. También está claro que no voy a cobrar 2,5 millones de pesetas mensuales, por muy buen trabajo que encuentre y por muchos estudios que tenga. Lo primero que se le ocurre a uno es seguir viviendo en casa de sus padres y ahorrar el 100% del sueldo durante los próximos 14 años, para el año 2020 (yo rondaré ya los 40 años de edad) tendré el dinero suficiente para comprar una vivienda al coste del año 2006 pero, por supuesto, no al coste del año 2020. Evidentemente esta ocurrencia la desecha uno antes de hacer cualquier cálculo.

Aunque un joven bienintencionado consiga ahorrar 2, 4 o 6 millones con mucho esfuerzo en pocos años, a día de hoy nunca podrán evitar: 1) Pedir un préstamo al banco a 40 o 50 años (si consigues ahorrar 2, 4 o 6 millones puedes reducir el período a 35 - 45 años, pero 5 años no suponen prácticamente nada cuando estamos hablando de medio siglo de pago).

Te darás cuenta de que no vives en una democracia sino en una dictadura. El dictador no se llama Francisco Franco, sino La Caixa, BSCH, Banc de Sabadell o, en general, 'la banca'. Ni siquiera tendrás la libertad de decir lo que piensas a, por ejemplo, tu jefe, no vaya a ser que cierre el grifo y no puedas pagar al dictador. 2) La otra solución es pagar un alquiler de por vida. En este caso el dictador se llamará Juan García, José Pérez o Pablo el arrendador. La situación no es distinta a 1). Después de esta reflexión ten la delicadeza de no decir a un joven que su problema es que no ahorra, eso fue válido para ti en 1979, incluso era valido para algunos jóvenes en 1999, pero no en 2006, en 2006 sólo consigues cargar con más impotencia, si cabe, al muchacho. El esfuerzo de nuestros padres, sin duda alguna admirable, no era estéril (podían obtener una vivienda de propiedad en un período de 5 años).

El mismo esfuerzo realizado por nosotros, los hijos, sólo llega para quizá reducir en 5 años una hipoteca de medio siglo. La vivienda nunca fue un objeto para enriquecerse, sino para vivir y es de lo poco material que sí necesitamos. La ley del libre mercado puede establecer el precio de los televisores de plasma al precio que quiera... yo no los compraré... pero nunca tuvimos que permitir que esa misma ley fijara el precio de la vivienda, porque todos Necesitamos vivir en una y no todos podemos pagarla. Los jóvenes, incluso aquellos que tenemos estudios superiores, no podemos competir."

Forges, EL PAÍS, 2/5/2006

lunes, 26 de noviembre de 2007

Ingenieros de informatica

Hola a todos los informaticos y no informáticos que estais navegando por mi bitácora. Hoy se inicia una nueva era para el estudiante de informática, hoy nace este blog en el que me gustaría subir noticias, código, ejercicios, examenes, prácticas y muchos temas de informática para ayudaros. También subiré algún video de humor para descargar esa tensión acumulado por los examenes y estudios. Espero que os sirva de ayuda o de entretenimiento. Un saludo de un compañero informático.