2010-10-28

Presentación en Hack.lu

Hace unas horas presenté en Hack.lu mi charla sobre aureliax. Aureliax es un software que sirve para mostrar diferencias entre diferentes versiones de una misma función, que es mostrada mediante un grafo de basic blocks. En cuanto pueda voy a poner on-line el white paper que explica cómo funciona y cuál es la base teórica que lo sustenta.
Por ahora estoy contento y cansado (acá en Luxemburgo son las 2 menos 20), y mañana tengo un largo día por delante.

Happy hacking,
Aureliano.

2010-09-21

Bajo el farol


Les recomiendo que vayan a ver esto. Yo fui la vez anterior, en abril, estuvo buenísimo y voy a ir de nuevo.

2010-09-04

Cómo trato de bailar a Pugliese

  • Escuchando el fraseo y siguiendo su intensidad.
  • Escuchando el compás, que aunque no siempre se note siempre está ahí.
  • Variando estilo y distancia del abrazo, pasando desde un tango milonguero, al tango salón y a veces hasta con abrazos típicos del tango nuevo. Todo dentro de un mismo tema.
  • Dando tiempo a la mujer para que también pueda hacer su propia interpretación y lucirse. Generalmente esos tiempos se dan en las partes más piano, que generalmente son a cargo del violín y/o en el final de la frase musical.
  • Es muy raro que haga paradas y el sanguchito, aunque si me parece que mi pareja lo quiere puedo llegar a marcar uno.
  • Giro en la parte ligada y camino usando contratiempos en la parte marcada.
  • En las pausas no hay cambios de peso, pero trato de mantener un dejo del movimiento que veníamos haciendo justo antes.
  • La elección del paso y la intensidad depende de la música, la pareja y la pista.
  • El final generalmente incluye una corrida de 5 o 7 pasos hasta el acorde dominante y quitar toda la tensión cuando suena la tónica suavemente en el piano.
Happy dancing,
Aureliano.

2010-07-30

Arte efímero


Marcador al agua sobre pizarrón blanco

2010-07-12

Una pequeña delicia del JavaScript

Qué valor debería dar el siguiente código:

"aDb".replace("D","$$")

Si pensaron "a$$b" se equivocaron. Da "a$b" (con un solo $).
Para que de el valor que esperaba ("a$$b") hay que hacer este hack:
"aDb".replace("D",function() { return "$$" })

¿Por qué?
Ni idea, pero anda así en rhino y V8, así que debe estar en la especificación.

Happy hacking,
Aureliano

2010-06-01

Flechas con RaphaelJS

Me encontré con que no hay ningún método para dibujar flechas en raphaelJS, así que me puse las pilas y programé uno:

 /**
* Returns a path in form of an arrow
* @param arrowSize is the size of the arrow end. Defaults to 10 pixels.
*/
Raphael.fn.arrow = function(x1, y1, x2, y2, arrowSize) {
var arrowSize = arrowSize || 10
var l = Math.sqrt( Math.pow( x2 - x1, 2 ) + Math.pow( y2 - y1, 2 ) )
var xStep = (x2 - x1) / l
var yStep = (y2 - y1) / l

// arrow point ends
var arrX1 = x2 + arrowSize * (yStep - xStep) / 2
var arrY1 = y2 + arrowSize * (-xStep - yStep) / 2
var arrX2 = x2 + arrowSize * (-yStep - xStep) / 2
var arrY2 = y2 + arrowSize * (xStep - yStep) / 2

var path = ["M", x1, y1, "L", x2, y2, //main line
"M", arrX1, arrY1, "L", x2, y2, "L", arrX2, arrY2] //arrow end

return this.path(path.join(" "))
}

Para usarlo hay que hacer:

var r = Raphael(....)
.....
var arrow = r.arrow(150,100,250,300)

2010-05-19

Cambiando el context-root

Esto es lo que tuve que hacer para que la webapp en java que estoy desarrollando con eclipse 3.5 y web tools platform ande en el context-path root:

  • Abrir el archivo .settings/org.eclipse.wst.common.component
  • Cambiar la entrada <property name="context-root" value="risky"> por <property name="context-root" value="/">
Happy hacking,
Aureliano

2010-04-27

Ahora tengo twitter

Saqué cuenta en twitter y voy a empezar a twittear (¿se escribe así?). Si quieren seguirme mi usuario es aurelianito.

En cuanto tenga alguna idea de lo que opino de twitter la mando por acá.

Happy hacking,
Aureliano

2010-04-06

Bajo el farol

Update: si quieren pueden escuchar algunas canciones del show en su página de myspace

Este sábado 10 de abril a las 23:30 hs mi amiga y gran cantante Natalia Iñón presenta su espectáculo "Bajo el farol" en la Casona del Teatro, que queda en Corrientes 1975 (Ciudad de Buenos Aires). El repertorio está compuesto por canciones de Edith Piaf, Marlene Dietrich y algunos tangos. Les sugiero que vayan a escucharla ya que es una cantante exquisita.

Nos vemos allá,
Aureliano

2010-03-08

Pequeñas cosas que me molestan

Un compañero de laburo dice que las personas que nos dedicamos a la programación y aledaños generalmente tenemos alguna tendencia al desorden obsesivo-compulsivo. Yo hice mi mea-culpa y acá escribo una lista de pequeñas cosas que creo que me molestan por tener algo de esa tendencia:
  • Salir a comer y que algunos pidan postre y otros no.
  • Salir a comer y que algunos pidan entrada y otros no.
  • Jugar fútbol en cantidades impares (ej: 5 contra 4)
  • Que los platos colocados en el escurridor no estén cada uno en una rendija y ocupando rendijas consecutivas desde el extremo más lejano del mismo.
¿Qué cosas equivalentes les molestan a ustedes?,
Aureliano

2010-03-03

Configurando lyx para escribir proceedings de ACM

Hoy configuré el lyx para que use la clase de LaTeX que piden para los proceedings de ACM y fue bastante más molesto de lo que esperaba. Esto lo hice en un ubuntu 9.10 casi pelado (con lyx y no mucho más). Acá les cuento los pasos:

  1. Copiá acm_proc_article-sp.cls a $HOME/texmf/tex/latex
  2. Corré "texhash ." en $HOME/texmf/tex/latex
  3. Poné en ./lyx/layouts el archivo acm_proc_article-sp.layout
  4. Arrancá lyx, andá a Tools->Reconfigure y volvé a arrancar lyx.
  5. Ahora en Document->Settings->Document Class está disponible la clase de los proceedings de ACM bajo el nombre "ACM Sig Proceedings".
Happy hacking,
Aureliano.

2010-02-22

Una reflexión sobre facebook

El otro día estaba cenando con unos amigos y estabamos hablando de como me echaron de FB. Y un amigo hizo una analogía re-buena.
¿Qué pasa si te ponés a bailar en los pasillos de un shopping? Lo más probable es que venga alguien de seguridad y te pida "amablemente" que te retires del lugar. En cambio si te ponés a bailar en el medio de una plaza, más allá de algunas miradas raras no debería pasarte nada.
¿Y por qué? El asunto es que nos olvidamos que el shopping no es un espacio público sino un espacio privado al que te dejan entrar cuando quieren, como quieren y en el que pueden aplicar toda clase de reglas arbitrarias. En cambio, una plaza es un lugar mucho más público.
Y con facebook pasa lo mismo. Es un espacio que nos olvidamos que es privado, pero lo es. Entonces nos molesta que nos apliquen reglas raras.
Ojalá estas cosas que me pasaron a mi (y a otros) sirvan para que entendamos la diferencia.

Happy hacking,
Aureliano.

2010-02-09

Exportando gráficos en dia a pdflatex

  1. Hacé tu gráfico en dia
  2. Exportarlo como "LaTeX PGF macros"
  3. En el principio de tu .tex poné:
  4. \usepackage{tikz}
  5. En el lugar donde quieras poner tu caption poné
    \begin{figure}
    \centering
    \input{archivo_exportado_de_dia.tex}
    \caption{Acá va el caption}
    \label{aca_va_la_label}
    \end{figure}
  6. Compilá el .tex principal con pdflatex
  7. Miralo con tu visor de pdfs favorito
Happy hacking,
Aureliano.

2010-02-07

Como ven los fanas de un lenguaje a los otros

Mirar lambda the ultimate es siempre interesante. Y esta vez me crucé con una perlita que quiero compartir con ustedes:

2010-02-05

Segundo advisory

Ayer salió mi segundo advisory. Lo que encontramos con Manuk es que parte administrativa de la aplicación LanDesk Manager tiene un cross-site request forgery que hace que si enganchás a un administrador se pueda hacer un cross-site scripting no persistente y, aún más divertido, hacer un OS command injection.
Aún más divertido, es que se puede usar modprobe y cargar módulos de kernel de linux que uplodee usando el command injection.
Más detalles en la página de Core.
Happy hacking,
Aureliano

2010-01-27

Simplificando

Ayer me di cuenta que no necesito rehacer los classloaders de java para cargar scripts de JavaScript, ya que puedo usarlos y son todo lo flexibles que necesito (y más). Inclusive, si por una de esas casualidades llegara a hace falta, creo que puedo hacer uno en rhino y todo. Por lo tanto decidí que mi lógica para cargar módulos tenía una indirección de más (la lista de loaders) y lo cambié para que use el classloader y listo. Fíjense en la nueva implementación de loadMod y como se simplificó el uso de los loaders.
En la versión del código que estoy usando ahora, también hice que los módulos se carguen un toque distintos para que haya mejores stack-traces (ese cambio está en la función require). Bueno, abajo pongo el código:


/*
* Does not support relative paths (yet?).
* Can be invoked by several threads.
*
* Uses the classloader to fetch js modules.
*/
var require = function (id) {

try {

require.lock.lock() // Avoid threading issues while loading modules.

if (!require.modules[id]) {

var modCode = require.loadMod(id)

var exports = {}
require.modules[id] = exports
var module = {
id : id
}

var context = {
exports: exports,
module: module,
}

if(!modCode) {
throw new require.RequireError(id, "module not found")
}

org.mozilla.javascript.Context.getCurrentContext().evaluateString(
context,
modCode,
id,
1,
null
)
/*
Old style invocation, should work in the browser but has worst error messages.

var f = new Function("require", "exports", "module", modCode)
f.call(context, require, exports, module) */
}

return require.modules[id]
} catch (x) {
if (x instanceof require.RequireError) {
throw x
} else {
throw new require.RequireError(id, x)
}
} finally {
require.lock.unlock()
}
}

require.loaders = []
require.modules = {}
require.lock = new java.util.concurrent.locks.ReentrantLock()

var RequireErrorProto = {}

require.RequireError = function(moduleId, cause) {
this.moduleId = moduleId
this.cause = cause

}
require.RequireError.prototype = RequireErrorProto
require.RequireError.prototype.toString = function() {
return "Error loading " + this.moduleId + ( this.cause ? ". Cause: " + this.cause : "" )
}
require.RequireError.prototype.name = "RequireError"

require.load = function(path) {
return java.lang.Class.forName("java.lang.String").getResourceAsStream(path)
}

require.loadMod = function(id) {
function path(id) {
return "/" + id + ".js"
}

function readFromStream(stream) {
var io = java.io
var reader = new io.BufferedReader( new io.InputStreamReader(stream) )
try {
var stringBuffer = new java.lang.StringBuffer()

var line = ""
while( line = reader.readLine()) {
stringBuffer.append(line)
stringBuffer.append("\n")
}

return stringBuffer.toString()
} finally {
reader.close()
}
}

var stream = require.load(path(id))
if (!stream) { return null }

return readFromStream(stream)
}

/**
* Resets the module cache.
*
* It will reload all the modules. Old modules referenced will still be working.
*/
require.reset = function() {
try {
require.lock.lock()
require.modules = {}
} finally {
require.lock.unlock()
}

}

Este cambio también simplifico el RhinoServlet, y ahora toma sus scripts del classpath también.

Happy hacking,
Aureliano

2010-01-25

Parseando CSVs con una expresión de JavaScript

Para parsear un CSV con datos numéricos hay que hacer esto:


text.split("\n").map( function(r){
return r.split(",").map( function(d) {
return parseFloat(d)
} )
} )

Esto solo anda si tu intérprete de JavaScript tiene Array.prototype.map definido. Sino antes de eso tenés que definirlo así:

Array.prototype.map = Array.prototype.map || function( f ) {
var r = []
for (var i=0; i<this.length; i++) {
r[i] = f(this[i])
}
return r
}

2010-01-18

Aure x 8


By Futo & Albinoni.

2010-01-17

Generando xhtml con e4x

Primero hay que setear el namespace por default:

default xml namespace = "http://www.w3.org/1999/xhtml"


Para generar elementos, uso esta función:
function elem(name) { return <{name} /> }


Para setear un attributo cualquiera esta función:
function attr(elem, key, value) { elem["@"+key] = value }


Y puedo usar elem.appendChild para agregar como hijo de un elemento otro o un texto como string que es escapado.

Happy hacking,
Aureliano.

2010-01-12

Entrada de BibTeX en Google Scholar

Si estás logueado en Google, podés setear Google Scholar para que te muestre las entradas de bibtex.
Para eso tenés que ir a Scholar Preferences -> Bibliography Manager y elegir Show links to import citations into BibTeX.

Happy hacking,
Aureliano

(Sacado de acá)

2010-01-10

Implementación de require en Rhino

Hoy estuve hackeando un toque y modifiqué el RhinoServlet que les mostré en este post para poder tener módulos en Javascript. El API que hice es un subset de lo definido en CommonJS. En particular, soporta require pero no los paths relativos de módulos (o sea, los que empiezan con . o ..). También le puse a todo un lock para que pueda usarse en un entorno concurrente, pero si un módulo tarda mucho en cargarse puede llegar a ser un problema.
Lo que me parece más interesante de mi prototipo es que se pueden agregar fácilmente nuevos loaders de módulos de JavasScript. Ya vienen por defecto loaders para cargar desde el classpath y desde la webapp, pero si quieren poder poner sus módulos en /WEB-INF/example, alcanza con agregar una línea en init.js:

require.loaders.push( require.stdLoader(servlet.servletContext, "/WEB-INF/example/"))

Bueno, basta de cháchara, acá está la versión modificada del RhinoServlet:
package aure.jslib;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;

public class RhinoServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private Scriptable initialScope = null;

public void runJs(Context cx, String scriptLocation, Scriptable scope) throws IOException {

InputStream is = this.getClass().getResourceAsStream(scriptLocation);
if( is == null) {
is = this.getServletContext().getResourceAsStream("/WEB-INF/js/" + scriptLocation);
}
Reader jsReader = new InputStreamReader(is);

cx.evaluateReader(scope, jsReader, scriptLocation, 1, null);
}

public static void addJavaObjectToScope(Scriptable scope, String name, Object obj) {
ScriptableObject.putProperty(scope, name, Context.javaToJS(obj, scope) );
}

@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
Context cx = Context.enter();
try {
Scriptable scope = cx.initStandardObjects();
addJavaObjectToScope(scope, "servlet", this);
addJavaObjectToScope(scope, "config", config);

this.runJs(cx, "initRequire.js", scope);
this.runJs(cx, "init.js", scope);

this.initialScope = scope;
} catch (IOException e) {
throw new ServletException(e);
} finally {
Context.exit();
}
}

@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Context cx = Context.enter();
try {
Scriptable scope = cx.initStandardObjects();
scope.setParentScope(this.initialScope);

addJavaObjectToScope(scope, "request", request);
addJavaObjectToScope(scope, "response", response);

this.runJs(cx, "start.js", scope);
} finally {
Context.exit();
}
}
}

Noten que toqué el init para que agregue el require y cambié la forma de levantar javascript. Por otro lado este es el javascript en initRequire.js, que tiene la implementación del require:

/* Based on http://www.davidflanagan.com/demos/require.js
* but heavily modified.
*
* Does not support relative paths (yet?).
* Can be invoked by several threads.
*
* Uses the servletContext and the classloader to fetch js modules.
*/
var logger = java.util.logging.Logger.getLogger("sarasa")

var require = function (id) {

try {

require.lock.lock() // Avoid threading issues while loading modules.

if (!require.modules[id]) {

var modText = require.loadMod(id)

var context = {}
var exports = {}
require.modules[id] = exports
var module = {
id : id
}

var f = new Function("require", "exports", "module", modText)
f.call(context, require, exports, module)
}

return require.modules[id]
} catch (x) {
throw new Error("Can't load module: " + id + ": " + x)
} finally {
require.lock.unlock()
}
}

require.loaders = []
require.modules = {}
require.lock = new java.util.concurrent.locks.ReentrantLock()
require.loadMod = function(id) {
var modText = null
var i = 0
while (modText == null && i < require.loaders.length) {
modText = require.loaders[i](id)
i++
}
return modText
}

// Setup loaders for files in the classpath, files in WEB-INF and files in the
// web-app (usually served to the client)
require.stdLoader = function(source, prepend) {
// Support functions
function readFromStream(stream) {
var io = java.io
var reader = new io.BufferedReader( new io.InputStreamReader(stream) )
var stringBuffer = new java.lang.StringBuffer()

var line = ""
while( line = reader.readLine()) {
stringBuffer.append(line)
stringBuffer.append("\n")
}

return stringBuffer.toString()
}

function path(id) {
return prepend + id + ".js"
}

var f = function(id) {
var stream = source.getResourceAsStream(path(id))
return stream ? readFromStream(stream) : null
}

return f

}

require.initStdLoaders = function() {
// classpath loader
require.loaders.push( this.stdLoader(servlet["class"], "/") )

// web-app context loader
require.loaders.push( this.stdLoader(servlet.servletContext, "/") )
}

require.initStdLoaders()

Empecé a hacer esto mirando el código en http://www.davidflanagan.com/demos/require.js pero al final quedó bastante distinto, sobre todo porque tiene la opción de tener muchos loaders.
Las cosas que me quedan para hacer son hacer que acepte paths relativos (que para que sea thread-safe hace falta que haga algunos truquitos) y hacer que en vez de usar
   var f = new Function("require", "exports", "module", modText)
f.call(context, require, exports, module)

para invocar el módulo haga algo usando el API de rhino para poder tener errores donde aparezca el nombre del módulo y el número de línea si hubo algún problema.

Escucho comentarios y sugerencias.

Happy hacking,
Aureliano.

Eclipse plug-in para app-engine

¿Por qué te negás a usar dependencias de otros proyectos de eclipse?
¿Por qué no recompilás bien cuando está corriendo el web-server en modo debug y uso resources de adentro del classpath?

Bueno, por ahora son 2 problemas que creo poder "workarroundear".

Happy hacking,
Aureliano.

2010-01-08

2 placas y default gateway

Hoy estuve configurando una VM con ubuntu que tiene una placa en modo bridged por DHCP y otra host-only estática. El problema que tuve fue que no encontraba la forma que la ruta por default sea la ruta por default que informa el dhcp. La solución que encontré fue hacer que la métrica de la ruta por default de la ip estática sea más grande.

Este es el archivo /etc/network/interfaces que terminé usando:

auto lo eth1 eth0
iface lo inet loopback

iface eth0 inet dhcp

iface eth1 inet static
address 172.17.17.16
netmask 255.255.255.0
network 172.17.17.0
broadcast 172.17.17.255
gateway 172.17.17.1
metric 200

Y la posta está en la última línea.

Probé sacar la entrada de gateway y agregar una entrada borrando la ruta que me sobraba (up route del default gw 172.17.17.1) y no funcionó.

Se les ocurre alguna otra forma de arreglar esto?

Happy hacking,
Aureliano.

2010-01-05

2 servlets para correr javascript

Estuve con algo de tiempo y me puse a probar como hacer para ejecutar JavaScript en el server. E hice 2 implementaciones (o sea, 2 servlets programados en Java). La primera que hice usa javax.script (que viene por defecto en Java 6) y me parece que el API es más cómoda pero tiene 2 limitaciones que no me gustaron, no se puede heredar de clases Java en JavaScript y no encontré cómo hacer para bindear un método de Java a JavaScript. Este es el código:

package aure;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;

import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class JsServlet extends HttpServlet {
private static final long serialVersionUID = 1L;

private ScriptEngine jsEng = new ScriptEngineManager()
.getEngineByName("js");
private Bindings initBindings = this.jsEng
.getBindings(ScriptContext.ENGINE_SCOPE);

public JsServlet() {
super();
}

@Override
public void init(ServletConfig config) throws ServletException {
try {
super.init(config);

this.initBindings.put("config", config);
this.initBindings.put("servlet", this);

this.runJs("init.js", this.initBindings);
} catch (ScriptException e) {
throw new ServletException("Error running init.js", e);
}
}

public void runJs(String scriptLocation, Bindings bindings)
throws ScriptException {
Reader jsReader = new InputStreamReader(this.getServletContext()
.getResourceAsStream(scriptLocation));

this.jsEng.eval(jsReader, bindings);
}

protected void service(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {

try {
Bindings bindings = jsEng.createBindings();
bindings.putAll(this.initBindings);
bindings.put("request", request);
bindings.put("response", response);

this.runJs("start.js", bindings);
} catch (ScriptException e) {
throw new ServletException("Error running javascript", e);
}
}

}

La segunda usa rhino bajado desde mozilla y por lo tanto no tiene esas limitaciones, pero el API para embeber JavaScript en Java es más fea. Acá está el código de la segunda versión:
package aure;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.mozilla.javascript.Context;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;

public class RhinoServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private Scriptable initialScope = null;

public void runJs(Context cx, String scriptLocation, Scriptable scope) throws IOException {
Reader jsReader = new InputStreamReader(this.getServletContext()
.getResourceAsStream("/WEB-INF/js" + scriptLocation));

cx.evaluateReader(scope, jsReader, scriptLocation, 1, null);
}

public static void addJavaObjectToScope(Scriptable scope, String name, Object obj) {
ScriptableObject.putProperty(scope, name, Context.javaToJS(obj, scope) );
}

@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
Context cx = Context.enter();
try {
Scriptable scope = cx.initStandardObjects();
addJavaObjectToScope(scope, "servlet", this);
addJavaObjectToScope(scope, "config", config);

this.runJs(cx, "/init.js", scope);

this.initialScope = scope;
} catch (IOException e) {
throw new ServletException(e);
} finally {
Context.exit();
}
}

@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Context cx = Context.enter();
try {
Scriptable scope = cx.initStandardObjects();
scope.setParentScope(this.initialScope);

addJavaObjectToScope(scope, "request", request);
addJavaObjectToScope(scope, "response", response);

this.runJs(cx, "/start.js", scope);
} finally {
Context.exit();
}
}
}

Ambas versiones ejecutan WEB-INF/js/init.js cuando se carga el servlet (tiene bindeados el servlet y la configuración del servlet) y WEB-INF/js/start.js cuando se atiende un pedido (agrega a los bindings lo que se haya puesto en init.js, el servlet, la configuración, el request y el response.

La idea de todo esto es ponerme las pilas e implementar las cosas que dije en este post hace casi 3 años, ya que ahora parece que se está poniendo de moda usar JavaScript.

Espero que les parezca interesante, me voy a dormir.

Happy hacking,
Aureliano.

2010-01-04

En el Burj Dubai, arriba de todo


Este video es increíble.