Bertrand Meyer en Argentina

Hoy me reenviaron el siguiente anuncio :

Tenemos el honor de presentar, nada más ni nada menos que, a Bertrand Meyer.
Meyer es el creador del lenguaje Eiffel, es docente de la Universidad de California, del Swiss Federal Institute of Technology. Su libro «Object-Oriented Software Construction» es material de referencia obligatorio para cualquier profesional del mundo de la Programación Orientada a Objetos.

El titulo del seminario es Touch of Class: How we teach introductory programming. Y será dado el día miércoles 11 de febrero. El lugar, el aula magna de Medrano 951, a las 19.00 hs.

Como es habitual en nuestros seminarios no es necesaria inscripción previa ni conocimientos de alguna tecnología en particular.

Se recuerda que el seminario es gratuito.

Murió el creador de los Playmobil

Día triste para el niño interior. Tantos recuerdos, tantas cajas que aún tengo en el desván de la casa de mis viejos, bajo el comando de «no, no se los dono a Santino» (mi sobrino :D). Los Playmobil son intransferibles e inmortales … la grua, la lancha, el transbordador, el barco pirata que siempre quise y nunca tuve, los miles de kits que dan vuelta por ahí … en fin, uno de mis grande recuerdos de mi no-tan-cercana niñes :).

Pensar que solo 4 años antes de que yo naciera, Hans Beck ya preparaba todo para mi feliz infancia!, un groso.

Edit In Place con Prototype

Una de las cosas que me venían pidiendo en ¡Falta Uno! era que se le pudieran asignar nombre a los equipos de un partido. En un principio pensé solo en poner los campos en el formulario de «crear partido» pero después me pareció que quedaba piola que se puedan editar directamente desde el resumen, usando un «Edit in place». Me puse a buscar si había algo hecho con Proptotype (que es lo que uso en este proyecto) y encontré esto que viene con varios ejemplos.

La biblioteca es muy fácil de usar y bastante flexible en cómo queremos que se comporte el edit (puede ser un input, un textarea, un combo). Suponiendo que los nombres de equipos estén siendo mostrados de la siguiente manera :

Para poder editar los títulos simplemente basta con ejecutar el siguiente código cuando se carga la página :

$('team_name_1').editInPlace({
  auto_adjust: true,
  select_text: true,
  save_url: ' 1) %>'
});
$('team_name_2').editInPlace({
  auto_adjust: true,
  select_text: true,
  save_url: ' 2) %>'
});

Es recomendable poner este código dentro de un método y usar un Observer para ejecutarlo, así mantenemos separada la lógica JS del HTML. Bastaría con un simple Event.observe(window, 'load', initEIP);.

Por el lado del servidor, el método que atiende el request (el definido el save_url) tiene que devolver el nuevo valor que va a tomar el campo. Por ejemplo, si el nombre no se pudo cambiar, deberíamos devolver el anterior. En este caso que es simple el template a devolver es el siguiente :


Para terminar, en caso de que el navegador del usuario no tenga JS queda el formulario de «Editar/Crear Partido» donde se pueden poner los nombres de manera tradicional.

Instalá tus Gemas con apt-get

Finalmente y pese a todas la quejas de los debianista de que era «dificil» o «imposible» ya hay una solución (o al menos eso parece, todavía no la probé :D).

La gente que hizo Passenger (a.k.a mod_rails) creó DebGem, que permite instalar prácticamente cualquier gema usando apt-get. El servicio no va a ser gratuito según parece una vez que pase la fase Beta, pero de todos modos demuestra que las gemas son empaquetables ;).

¿El precio? No lo dicen, pero aclaran que «subscription probably only costs about 1-2 hours of your time per month». Veremos si tiene éxito y si motiva a terceros a crear algo similar :D.

Cipolletti, Ciudad Borracha

Hace ya varios días que tengo el blog abandonado ya que estoy en el sur de pseudo-vacaciones, y entre tanto lechón, cordero, lago, pileta, joda nocturna, sacar a pasear a los sobrinos y visitar amigos se me olvidó que existe esto llamado Internet :).

Simplemente busqué un AP para poder comentar esto que leí en el diario local el otro día : Cipolletti tiene un ingreso de alcohol per-cápita de 6 litros diarios (contra 4 litros de leche diarios) siendo así la provincia patagónica más «alcoholizada», superando el promedio mundial de 5.4 litros/día per-cápita … un dato más que interesante (??).

Según el artículo el promedio de sudamérica es de 9 y pico!, por lo que tampoco somo tan borrachos por esta zona :).

Felicidades para todos y que arranquen el 2009 con todo! (yo calculo que me tomaré mis 6 litros diarios mientras siga por acá :D)

Puppet y not trusted hosts

Hoy estaba terminando de configurar Puppet y me empezó a saltar el siguiente error en los clientes :

Certificates were not trusted: hostname was not match with the server certificate

Buscando un poco llegué a esta página donde explican el motivo y es que al no tener un FQDN para mi puppetmaster la biblioteca de Ruby lanza una excepción que hace que falle.

Por default el puppetmaster pone el nombre del certificado como «puppetmaster » (Debian Etch) y claro, el cliente tiene configurado server=192.168.x.y por lo que no coincide.

La solución que hizo que todo ande fue editar el /etc/puppet/puppet.conf en el servidor maestro y dentro de la sección [puppetmasterd] agregar certname=192.168.x.y de amanera que ahora sí ambos hablan de lo mismo :).

No se que tan lindo/feo es tener una IP como nombre de certificado, pero anda.

Los Fabulosos Cadillacs

Creo que lo puedo resumir en tres simples palabras : una fiesta increíble :). Fue por el ’94 cuando me regalaron el primer CD de esta banda (El León específicamente) y nunca había tenido la oportunidad de verlos en vivo. Cuando se anunciaron los recitales casi casi que salgo corriendo a comprar una entrada, pero entre idas y vueltas no fuí nunca. Por suerte la gente de Speedy nos mandó el jueves entradas de regalo así que finalmente fui anoche!.

Un estadio repleto. Mucha energía de la banda y la gente a pleno. Tocaron todo lo que iba a escuchar y solo no sabía que hacer con los temas nuevos, que nunca los había escuchado (o no los identificaba al menos).

La perlita de la noche fue cuando con Emi estábamos y se dió un diálogo similar al siguiente :

  • Yo : Si esto es una fiesta, imaginate si una banda de cumbia hace un River
  • Emi : jajaja, no para más
  • Yo : va, pero mirá si Damas Gratis va a hacer un River!, es impensable.

Un rato después, no más de una hora anuncian a Pablo Lescano para tocar un tema. Para los cumbia-analfabetos o los que no se lo imaginaron todavía, si, este señor es el líder de Damas Gratis y estuvo en otras joyitas como Amar Azul … antes de que acoten algo, es un tipo como uno, de San Fernando, vió ;).

Desafortunadamente pese a gran fiesta yo tuve que mirar todo el show desde un no-tan-cómodo aciento, ya que el sábado por la mañana me clave un vidrio en el talón (unos 6 mm) y no puedo pisar (casi ni calsarme) y mucho menos estar saltando como un delirante :).

Sobreviviendo ataques

Está terminando un día largo, de esos que uno espera que no le toquen, pero que tarde o temprano llegan. Ayer a la noche en 3DG fuimos víctimas de un pequeño ataque. Por suerte los atacantes super buena onda. Luego de que apagamos el primer incendio estuvimos chateando con ellos y nos dieron la data de por donde entraron, cómo, qué cosas modificaron y lo mejor de todo, donde nos habían dejado los backups que habían hecho :).

El ataque consistió en hacer que nuestros sitios (el target era el foro que es el que tiene más tráfico, pero afectó a otros sitios también) sean redirigidos a una página muy graciosa que no pienso linkear porque no es ATP. Para lograrlo (ya que el foro está aislado y no pudieron entrar por ahí) nos crackearon el sistema de publicidad e insertaron un banner javascript que hacía el redirect. Simple y efectivo.

Para lograr el acceso al server de ads fue más fácil, simplemente explotaron un SQL Injection que por la fecha de última modificación del script, estaba desde el 2001 :). Con eso consiguieron el password de admin para poder poner su publicidad. Nuestro segundo problema fue obvio, el usuario que usa ese script para acceder a la DB tenía demasiados privilegios y pudo leer y modificar una otra base de datos.

Más allá del trabajo que tuvimos que hacer para recuperar de nuestros backups cosas por las dudas (aunque nos hicieron backups tampoco confiar a ciegas :P) tuvimos que empezar a auditar cosas que teníamos pendiente hace rato. Para empezar necesitamos bajar los servicios completamente y la forma más linda que encontré fue usando un rewrite rule de apache, como sigue :

RewriteEngine on
RewriteCond %{REQUEST_URI} !^/imagenes
RewriteCond %{DOCUMENT_ROOT}/maintenance.html -f
RewriteCond %{REQUEST_URI} !/maintenance.html$

RewriteRule $ /maintenance.html [R=302,L] 

De esta manera cuando terminamos de hacer el mantenimiento simplemente borramos el maintenance.html y el sitio vuelve solo a la vida. De paso ya lo dejamos para cuando hagamos futuros updates.

Lo otro que nos entró en duda cuando arreglamos el problema fue : ¿lo arreglamos realmente? ¿tendremos otro agujero en algún lado?. Para poder revisar esto comencé a buscar herramientas para auditar SQL Injections y me encontré con un post donde habían varias soluciones. La que usamos finalmente fue sqlmap porque fue la que mejor nos pareció que andaba.

Fue una tarde divertida viendo que podíamos romper de nuestro viejo sitio. Para escanearlo simplemente corríamos :

#$ sqlmap -dbs -u "http://127.0.0.1/scriptbuggeado.php?Id=1"

El programa primero trata de ver si el parámetro Id es vulnerable a diferentes formas de hacer injection y si descubre alguna trata de obtener la lista de DBs. Es lindo ver cuando aparecen todas tus DBs en la consola :). Si le agregamos «-v 2» es más gracioso aún, porque los nombres van apareciendo letra a letra (parece que las va adivinando o algo, no me fijé en el código para ver como lo hace).

A esta hora cerramos ya el agujero del ataque y dos más que detectamos.

El último problema que encontramos fue que habían subido un shell. Para esto crackearon el password de programa para enviar newsletters y subieron un archivo php que tiene un shell re lindo que tiene funciones para escanear vulnerabilidades localmente. Acá el problema fue que el sysadmin anterior dejó permiso para ejecutar script en el directorio donde el programa guarda attachments que después se usan en el email (como imágenes en esos emails molestos HTML que nos llegan todos los días). Sacando los permisos para ejecutar cualquier tipo de script el shell ya no funciona.

Como sysadmin «temporal» fue una experiencia divertida, sobre todo porque no hubo pérdida de datos y la buena onda de los atacantes 🙂 (¿tendré el Síndrome de Estocolmo?).

State Machine

Varios días atrás tuve que hacer un juego simple, un memotest para ser exacto, para correr en unos «kioskos» para un cliente. Ya que tenía pendiente aprender a usar RubyGame, lo hicimos con este framework para ver que onda, ya que hasta ahora veníamos usando pyGame.

El juego salió super rápido, sin mayores problemas, pero la lógica de juego no me gustaba porque teníamos que andar trackeando el estado actual a mano, muchos ifs y comprobaciones que hacían del loop de juego un choclo de código.

Es por eso que me puse a ver un poco como aprovechar el tener bloques de código para encapsular la lógica del juego un poco más prolijo. Antes de comenzar encontré la gema Statemachine pero a primera vista no la entendí mirando los ejemplos 🙂 y luego de jugar un rato no me terminó de convencer ya que parece mucho más de lo que yo necesitaba.

El resultado de un par de horas de tirar «magia» fue poder definir la lógica de la siguiente manera (el ejemplo está simplificado, omitiendo los efectos y parte de la lógica) :

class Logic
  include StateMachine
  # Esperando interacción del usuario
  state :user_input do
    @events.each { |event|
      case event
      when MouseDownEvent
        selected event.pos
      when QuitEvent
        end_game
      end
    }
  end

  # Oculta las piezas seleccionadas cuando no hubo match
  state :clear do
    @selected.each {|f| f.hide }
    @selected = []
  end

  # Cambio de estado
  transition :user_input, :clear do
    @selected.size == 2
  end

  # Cambio de estado
  transition :clear, :user_input do
    true
  end
end

Cada declaración de state tiene el código que se debe ejecutar cuando estamos en dicho estado, mientras que las transition son usadas automáticamente para saber a qué estado nos debemos mover. La primer transition que retorne true, se toma el estado destino y se asigna como el actual.

Por el lado del game loop, lo único que se debe hacer es llamar a un método que se encarga de ejecutar el estado actual y luego verificar si alguna transición retorna «true» y se cambia al nuevo estado.

class Game
  include Rubygame
  include Logic

  def event_loop
    loop do
      current_state

      return if game_ended?

      draw
      @clock.tick
      @screen.update
    end
  end
end

En Game hay otros métodos auxiliares como game_ended, draw y selected, que no vienen mucho al caso en este momento.

El próximo paso ahora es limpiar un poco esto, ver si no hay una forma mejor de hacerla y publicar el esqueleto completo (la idea a futuro es tener un generator) para poder tener un mini framework para hacer juegos simples.

Si buscan un framework interesante les recomiendo Shattered Ruby (git repo), aunque al momento de escribir este post el sitio principal no responde.

state_machine.rb

MovieClip Factory en Flash

Para un videojuego que nos pidió un cliente tuve que solucionar un problema que me costó bastante y es por eso que lo comparto. Si bien no me gusta mucho escribir por acá sobre software privativo, en este caso encontré tan poca información que me pareció bueno compartirlo.

El juego en cuestión es un scroller horizontal, en donde van entrando chimeneas (mas bien techos con sus chimeneas) y Papá Noel tiene que hacer el delivery de regalos :). El problema apareció cuando empecé a agregar más y más techos al escenario.

La forma en que inicialmente lo manejaba era con un gran MovieClip que tenía adentro los techos en sus respectivas posiciones y luego moviendo el gran MovieClip movía todo. Simple, pero inefectivo. Según parece (aunque no hay nadie que lo confirme) Flash se lleva mal con las técnicas de clipping básicas y por eso el mover un MovieClip enorme (estamos hablando de 4000 o 5000px de ancho) le es costoso (algo así como consumir el 95% del CPU). Otra cosa que incrementaba el problema es que el juego tiene 3 layers para hacer un efecto de Parallax scrolling.

Esto hizo que empezara a investigar opciones, y la solución que mejor se adapta es crear los objetos antes de que entren en pantalla (unos pixels antes) y destruirlos al salir. Ahora bien, crear y destruir objetos on-the-fly es aún peor en muchos casos que el problema inicial :). La solución real al problema es reutilizar las instancias en lugar de eliminarlas. ¿Cómo?. Seguí leyendo.

La idea básica es que cuando un MovieClip sale de pantalla, en lugar de eliminarlo lo ocultamos. De esta forma Flash lo ignora al hacer el render. Si en algún momento necesitamos crear un objeto del mismo tipo, en lugar de crear uno nuevo, reutilizamos el que teníamos oculto y lo hacemos visible (previo acomodarlo donde corresponde). Ahora multipliquen esta idea por 10 tipos de objetos diferentes, y que además son generados al azar antes de empezar cada nivel (no puedo predecir cuantos de cada tipo necesito).

Esto hace que en lugar de tener una lista de MovieClips tengamos una lista de puntos, y solo movemos los puntos. En cada frame nos fijamos que puntos están por entrar a la pantalla y creamos el nuevo objeto y lo ponemos en la posición del punto. Mi código luce más o menos así :

// Crea los objetos que deben estar visibles
// en un momento dado.
while (i  (Stage.width+10)) {
    // Este punto está muy afuera y como
    // están ordenados, el resto también.
    break;
  }

  // Si estoy a 10 pixels de entrar lo creo
  var t:Techo = factory.create(o.techo, "techo"+last_id, 9000+last_id);
  // Acomodo el nuevo objeto, ya sea nuevo nuevo u obtenido del cache
  t._x = o.x;
  t._y = Stage.height - 125;
  // Esta lista tiene los Techos reales que estan visibles en pantalla
  techos.push(t);
  last_id++;
  ++i;
}
// Elimino los puntos que ya use
chimeneas = chimeneas.splice(i);

La solución que implementé fue esto que llamo «MovieClip Factory» que adjunto al final del post para quien quiera descargarla. La idea es que en lugar de crear un nuevo MovieClip con attachMovie, lo hago con la factory. Esta clase se encarga de manejar al lógica de caching de manera transparente.

Cuando no necesitamos más un objeto simplemente lo devolvemos a la fábrica y así esta lo deja a la espera de ser reusado. Un ejemplo de uso sería algo como sigue :

/* mc sería el MovieClip que queremos usar como padre */
factory = new Factory(mc);
factory.registerCode(1, "Techo01");

var t:MovieClip = factory.create(1, "un_id", 1);
// Devuelvo el objeto al factory.
factory.push(t);

/* A este punto t y u son el mismo objeto */
var u:MovieClip = factory.create(1, "un_id", 1);

Haciendo las cuentas, si en promedio mis techos miden 250px cada uno, de hacerlo de la manera inicial tendría que crear unos 16 techos para un escenario de 4000px de ancho. Usando el factory, suponiendo que más de 4 techos a la vez no puedo ver (por el ancho del área visible) en el peor de los casos tengo 4 de cada tipo de techo (2 completos y 2 mitades, una que entra y una que sale), es decir 20 objetos en memoria siendo el consumo mayor.

Sin embargo al generar el escenario en forma aleatoria yo valido que no toquen 2 iguales seguidos porque quedaban feos, por lo que la cuenta en realidad da 2 objetos simultáneos máximo de cada tipo, siendo 10 en total en memoria.

La otra ventaja es que puedo hacer el escenario infinitamente largo a costo constante de uso de memoria 🙂

Descargar MovieClip Factory