Delicias del JavaScript
Conclusión, no usar == nunca más
Blog de Aureliano Calvo. Aureliano Calvo's blog.
Etiquetas:
javascript
Mi amigo frandibar estrena su blog sobre sus experiencias jugando al go. ¡En una de esas hasta vean partidas mías por ahí!
Éxitos Fran!!!!!
Hace un tiempito que descubrí una fabulosa biblioteca que sirve para hacer visualizaciones y muchas más cosas, que se llama d3. Les recomiendo fuertemente que si quieren hacer cosas para browsers modernos le den una ojeada. Y buscando ejemplos y documentación sobre la misma encontré un libro on-line que me gustó, llamado D3 tips and tricks. En particular, me llamó la atención lo grosas que quedan las tablas cuando las hacés usando d3.
Happy hacking,
Aureliano.
Etiquetas:
d3,
d3js,
javascript
Las últimas 2 semanas estuve haciendo en el laburo el curso de diseño orientado a objetos que da Hernán Wilkinson de 10 Pines. Dentro del curso, hay un ejercicio para hacer single dispatch que consiste en modelar números enteros y fracciones.
Como usar los números que me da el lenguaje para modelar los números me pareció choto, hice una implementación de los números de Peano y con eso hice las fracciones.
Abajo les dejo la primera versión que pasa los tests, pero que es media fea porque tiene ifs de la forma if isinstance(sumando, Enteros): #código. Si miran al final, van a ver los tests de unidad que tiene que pasar el código. Antes está la implementación.
import unittest
class Numero:
DESCRIPCION_DE_ERROR_DE_DIVISION_POR_CERO = 'No se puede dividir por 0'
def esCero(self):
self.shouldBeImplementedBySubclass()
def esUno(self):
self.shouldBeImplementedBySubclass()
def __add__(self,sumando):
self.shouldBeImplementedBySubclass()
def __mul__(self,factor):
self.shouldBeImplementedBySubclass()
def __div__(self,divisor):
self.shouldBeImplementedBySubclass()
def shouldBeImplementedBySubclass(self):
raise NotImplementedError('Should be implemented by the subclass')
def __le__(self, other):
return self < other or self == other
class Entero(Numero):
pass
class Zero(Entero):
def esCero(self): return True
def esUno(self): return False
def __eq__(self, other):
return self.__class__ == other.__class__
def __add__(self,sumando):
return sumando
def __mul__(self, factor):
return self
def __repr__(self): return "0"
def __lt__(self, other): return not self == other
class Next(Entero):
def __init__(self, before):
self.before = before
def esCero(self): return False
def esUno(self): return self.before.esCero()
def __add__(self,sumando):
if isinstance(sumando, Entero):
return Next(self.before + sumando)
return sumando + self
def __mul__(self, factor):
return factor + self.before * factor
def __repr__(self): return "N" + repr(self.before)
def __eq__(self, other):
if isinstance(other, Fraccion):
return other == self
if self.__class__ != other.__class__: return False
return self.before == other.before
def __lt__(self, other):
if self.__class__ != other.__class__: return False
return self.before < other.before
def __div__(self, other):
if isinstance(other, self.__class__):
return Fraccion(self, other)
if isinstance(other, Fraccion):
return Fraccion(other.d * self, other.n)
raise Exception("No se puede dividir por %r" % other)
class Fraccion(Numero):
def __init__(self, n, d):
if (d.esCero()):
raise Exception(Numero.DESCRIPCION_DE_ERROR_DE_DIVISION_POR_CERO)
self.n = n
self.d = d
def __add__(self, other):
#a/b + c/d = (a.d + c.b) / (b.d)
if isinstance(other, self.__class__):
return Fraccion((self.n * other.d + other.n * self.d), self.d * other.d)
if isinstance(other, Entero):
return Fraccion(self.n + other * self.d, self.d)
raise Exception("No se sumar %r" % other)
def __mul__(self, other):
# (a/b) * (c/d) = (a.c) / (b.d)
if isinstance(other, self.__class__):
return Fraccion(self.n * other.n, self.d * other.d)
if isinstance(other, Entero):
return Fraccion(self.n * other, self.d)
def __div__(self, other):
# (a/b) / (c/d) = (a.d) / (b.c)
if isinstance(other, self.__class__):
return Fraccion(self.n * other.d, other.n * self.d)
if isinstance(other, Entero):
return Fraccion(self.n, self.d * other)
raise Exception("No se dividir %r" % other)
def __eq__(self, other):
if isinstance(other, self.__class__):
return self.n * other.d == self.d * other.n
if isinstance(other, Entero):
return self.n == self.d * other
return False
def __repr__(self): return repr(self.n) + "/" + repr(self.d)
class NumeroTest(unittest.TestCase):
def createCero(self):
return Zero()
def createUno(self):
return Next(self.createCero())
def createDos(self):
return Next(self.createUno())
def createTres(self):
return Next(self.createDos())
def createCuatro(self):
return Next(self.createTres())
def createCinco(self):
return Next(self.createCuatro())
def createSeis(self):
return Next(self.createCinco())
def createSiete(self):
return Next(self.createSeis())
def createUnQuinto(self):
return Fraccion(self.uno, self.cinco)
def createDosQuintos(self):
return Fraccion(self.dos, self.cinco)
def createDosVeinticincoavos(self):
return Fraccion(self.dos, self.cinco * self.cinco)
def createUnMedio(self):
return Fraccion(self.uno, self.dos)
def createCincoMedios(self):
return Fraccion(self.cinco, self.dos)
def createSeisQuintos(self):
return Fraccion(self.seis, self.cinco)
def createCuatroMedios(self):
return Fraccion(self.cuatro, self.dos)
def createDosCuartos(self):
return Fraccion(self.dos, self.cuatro)
def setUp(self):
self.cero = self.createCero()
self.uno = self.createUno()
self.dos = self.createDos()
self.tres = self.createTres()
self.cuatro = self.createCuatro()
self.cinco = self.createCinco()
self.seis = self.createSeis()
self.siete = self.createSiete()
self.unQuinto = self.createUnQuinto()
self.dosQuintos = self.createDosQuintos()
self.dosVeinticincoavos = self.createDosVeinticincoavos()
self.unMedio = self.createUnMedio()
self.cincoMedios = self.createCincoMedios()
self.seisQuintos = self.createSeisQuintos()
self.cuatroMedios = self.createCuatroMedios()
self.dosCuartos = self.createDosCuartos()
def testAEsCeroDevuelveTrueSoloParaElCero(self):
self.assertTrue (self.cero.esCero())
self.assertFalse (self.uno.esCero())
def testBEsUnoDevuelveTrueSoloParaElUno(self):
self.assertTrue (self.uno.esUno())
self.assertFalse (self.cero.esUno())
def testCSumaDeEnteros(self):
self.assertEqual (self.dos,self.uno+self.uno)
def testDMultiplicacionDeEnteros(self):
self.assertEqual(self.cuatro, self.dos*self.dos)
def testEDivisionDeEnteros(self):
self.assertEqual(self.uno, self.dos/self.dos)
def testFSumaDeFracciones(self):
sieteDecimos = Fraccion( self.siete, self.dos * self.cinco ) # <- br="" corresponda="" lo="" por="" que="" reemplazar="">
self.assertEqual (sieteDecimos,self.unQuinto+self.unMedio)
#
# La suma de fracciones es:
#
# a/b + c/d = (a.d + c.b) / (b.d)
#
# SI ESTAN PENSANDO EN LA REDUCCION DE FRACCIONES NO SE PREOCUPEN!
# NO SE ESTA TESTEANDO ESE CASO
#
def testGMultiplicacionDeFracciones(self):
self.assertEqual (self.dosVeinticincoavos,self.unQuinto*self.dosQuintos)
#
# La multiplicacion de fracciones es:
#
# (a/b) * (c/d) = (a.c) / (b.d)
#
# SI ESTAN PENSANDO EN LA REDUCCION DE FRACCIONES NO SE PREOCUPEN!
# TODAVIA NO SE ESTA TESTEANDO ESE CASO
#
def testHDivisionDeFracciones(self):
self.assertEqual (self.cincoMedios,self.unMedio/self.unQuinto)
#
# La division de fracciones es:
#
# (a/b) / (c/d) = (a.d) / (b.c)
#
# SI ESTAN PENSANDO EN LA REDUCCION DE FRACCIONES NO SE PREOCUPEN!
# TODAVIA NO SE ESTA TESTEANDO ESE CASO
#
#
# Ahora empieza lo lindo! - Primero hacemos que se puedan sumar enteros con fracciones
# y fracciones con enteros
#
def testISumaDeEnteroYFraccion(self):
self.assertEqual (self.seisQuintos,self.uno+self.unQuinto)
def testJSumaDeFraccionYEntero(self):
self.assertEqual (self.seisQuintos,self.unQuinto+self.uno)
#
# Hacemos lo mismo para la multipliacion
#
def testKMultiplicacionDeEnteroPorFraccion(self):
self.assertEqual(self.dosQuintos,self.dos*self.unQuinto)
def testLMultiplicacionDeFraccionPorEntero(self):
self.assertEqual(self.dosQuintos,self.unQuinto*self.dos)
#
# Hacemos lo mismo para la division
#
def testMDivisionDeEnteroPorFraccion(self):
self.assertEqual(self.cincoMedios,self.uno/self.dosQuintos)
def testNDivisionDeFraccionPorEntero(self):
self.assertEqual(self.dosVeinticincoavos,self.dosQuintos/self.cinco)
#
# Ahora si empezamos con problemas de reduccion de fracciones
#
def testOUnaFraccionPuedeSerIgualAUnEntero(self):
self.assertEquals(self.dos,self.cuatroMedios)
def testPLasFraccionesAparentesSonIguales(self):
self.assertEquals(self.unMedio,self.dosCuartos)
#
# Las fracciones se reducen utilizando el maximo comun divisor (mcd)
# Por lo tanto, para a/b, sea c = mcd (a,b) => a/b reducida es:
# (a/c) / (b/c).
#
# Por ejemplo: a/b = 2/4 entonces c = 2. Por lo tanto 2/4 reducida es:
# (2/2) / (4/2) = 1/2
#
# Para obtener el mcd pueden usar el algoritmo de Euclides que es:
#
# mcd (a,b) =
# si b = 0 --> a
# si b != 0 -->mcd(b, restoDeDividir(a,b))
#
# Ejemplo:
# mcd(2,4) ->
# mcd(4,restoDeDividir(2,4)) ->
# mcd(4,2) ->
# mcd(2,restoDeDividir(4,2)) ->
# mcd(2,0) ->
# 2
#
def testQLaSumaDeFraccionesPuedeDarEntero(self):
self.assertEquals (self.uno,self.unMedio+self.unMedio)
def testRLaMultiplicacionDeFraccionesPuedeDarEntero(self):
self.assertEquals(self.dos,self.cuatro*self.unMedio)
def testSLaDivisionDeEnterosPuedeDarFraccion(self):
self.assertEquals(self.unMedio, self.dos/self.cuatro)
def testTLaDivisionDeFraccionesPuedeDarEntero(self):
self.assertEquals(self.uno, self.unMedio/self.unMedio)
def testUNoSePuedeDividirEnteroPorCero(self):
try:
self.uno/self.cero
self.fail()
except Exception as e:
self.assertEquals(self.descripcionDeErrorDeNoSePuedeDividirPorCero(),e.message)
def testVNoSePuedeDividirFraccionPorCero(self):
try:
self.unQuinto/self.cero
self.fail()
except Exception as e:
self.assertEquals(self.descripcionDeErrorDeNoSePuedeDividirPorCero(),e.message)
# Este test puede ser redundante dependiendo de la implementacion realizada
def testWNoSePuedeCrearFraccionConDenominadorCero(self):
try:
self.crearFraccionCon(self.uno,self.cero)
self.fail()
except Exception as e:
self.assertEquals(self.descripcionDeErrorDeNoSePuedeDividirPorCero(),e.message)
def crearFraccionCon(self, numerador, denominador):
return Fraccion(numerador, denominador)
def descripcionDeErrorDeNoSePuedeDividirPorCero(self):
return Numero.DESCRIPCION_DE_ERROR_DE_DIVISION_POR_CERO->
En futuros posts voy a ir factorizando este código para que quede más lindo.
Happy hacking,
Aureliano.
Voy a usar esta entrada del blog para guardar links a cosas que me parezcan relevantes para compilar/cambiar/hacer módulos del kernel de linux:
Estuve colaborando en impacket y agregué paquetes para parsear EAP y WPS. Como impacket anda a partir de python 2.5, me instalé un python 2.5 en un Linux Mint para ver que no rompí nada. Instalar un python 2.5 con soporte para crypto es difícil. Abajo les dejo las instrucciones:
Bajar tarballs de:
Etiquetas:
impacket,
linux,
linux mint,
python
El viernes pasado, mientras estábamos almorzando en el trabajo, tuvimos una charla re interesante sobre la homeopatía. Yo afirmé que la homeopatía es puro efecto placebo y un compañero de laburo me dijo que eso era mentira porque él trató a su perro con un tratamiento homeopático. Después de eso yo dije que el efecto placebo seguramente también afecta a animales domésticos, pero ese argunmento no fue lo suficientemente fuerte. Después de eso, me dijo que "no todo lo puede explicar la ciencia" (sic).
Si quieren que yo refute algo, decirme algo así es un buen método. Entonces me puse a googlear y estuvo complicado, porque casi todos los papers de veterinaria están atrás de paywalls :(. Pero al final encontré un survey del año 1999 que se llama The placebo effect in animals pubicado en el "Journal of the American Veterinary Medical Association". También encontré este artículo, que cita varios papers (incluyendo al que mencioné antes).
Si los leen, van a ver que hay evidencia que hace pensar que es significativo el efecto placebo en perros. ¿Saben de alguna referencia mejor que apoye o refute la existencia del efecto placebo en animales?
Etiquetas:
animales,
homeopatía,
placebo,
pseudociencia
Después de mucho tiempo volví a programar un toque en ruby. Por necesidades laborales, tuve que usar de nuevo mi bouncer.rb, pero lamentablemente "rdoc/usage" no está en ruby 1.9. Así que lo adapté para que no lo necesite más. Abajo pongo el código:
#!/usr/bin/env ruby
# == Synopsis
#
# redirect.rb: Redirects TCP connections to distant machines. Handles simultaneously many connections.
#
# == Usage
#
# ruby redirect.rb [OPTION]
#
# -h, --help:
# Show help
#
# --ip ip, -i ip:
# Accept connections from ip (default 127.0.0.1)
#
# --port port, -p port:
# Listen on port (default 12345)
#
# --target ip:port, -t ip:port
# Connect to ip:port (default 127.0.0.1:23456)
#
require 'getoptlong'
#require 'rdoc/usage'
require 'socket'
class Redirect
def initialize( source_ip, listening_port, target_ip, target_port )
@source_ip = source_ip
@target_ip = target_ip
@target_port = target_port
@server_socket = TCPServer.new( "", listening_port )
@server_socket.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )
@descriptors = [ @server_socket ]
@next_step = {}
end
def handle_new_connection
incoming = @server_socket.accept
if incoming.peeraddr[3] == @source_ip
begin
outgoing = TCPSocket.new( @target_ip, @target_port )
@next_step[ incoming ] = outgoing
@next_step[ outgoing ] = incoming
@descriptors += [ incoming, outgoing ]
rescue
silent_close( incoming )
end
else
silent_close( incoming )
end
end
def silent_close( sock )
begin
sock.close
rescue
#do nothing intentionally
end
end
def propagate(sock)
next_sock = @next_step[sock]
next_sock.write(sock.read_nonblock(1000 * 1000))
end
def finish_connection(sock)
next_sock = @next_step[sock]
[ sock, next_sock ].each do
|s|
silent_close(s)
@descriptors.delete(s)
@next_step.delete(s)
end
end
def run
loop do
connections = select( @descriptors )
connections[0].each do
|sock|
if sock == @server_socket then
handle_new_connection
else
begin
sock.eof? ? finish_connection(sock) : propagate(sock)
rescue
finish_connection(sock)
end
end
end
end
end
end
if $0 == __FILE__ then
opts = GetoptLong.new(
[ '--help', '-h', GetoptLong::NO_ARGUMENT ],
[ '--ip', '-i', GetoptLong::REQUIRED_ARGUMENT ],
[ '--port', '-p', GetoptLong::REQUIRED_ARGUMENT ],
[ '--target', '-t', GetoptLong::REQUIRED_ARGUMENT ]
)
ip = '127.0.0.1'
port = '12345'
target = '127.0.0.1:23456'
opts.each do
|opt, arg|
case opt
when '--help'
print """\
Usage:
ruby bouncer.rb [options]
options:
-i [ip] --ip=[ip]
-p [port] --port=[port]
-t [host:port] --target=[host:port]
"""
exit
when '--ip'
ip = arg
when '--port'
port = arg
when '--target'
target = arg
end
end
port = port.to_i
target = target.split(":")
trap("SIGINT") do
exit
end
Redirect.new(ip, port, target[0], target[1].to_i).run
end
Happy hacking,
Aureliano
Quiero ejecutar cscope buscando recursivamente en un directorio los archivos que van a ser indexados, para eso hago:
$ find . -type f -and \( -name "*.c" -or -name "*.h" \) | xargs cscope
y abre el cscope una décima de segundo y se cierra
pero si hago
$ cscope `find . -type f -and \( -name "*.c" -or -name "*.h" \)`
anda bien.
¿Se les ocurre que puede ser?
Update: Cambié el código para que standard output y standard error salgan en la consola del debugger.
Quiero poder debuguear cosas que estoy desarrollando y requieren root. Para eso, me hice un pequeño wrapper que sirve para ejecutar cualquier programa de python y se conecta a un pydevd server.
#!/usr/bin/env bash
PYDEVD_LOCATION=/home/aure/Aptana_Studio_3/plugins/org.python.pydev_2.7.0.2013032300/pysrc
export PYTHONPATH=$PYDEVD_LOCATION:$PYTHONPATH
echo "Check the pydev debug console for output"
python $PYTHONARGS -c "import pydevd;pydevd.settrace(suspend=False,trace_only_current_thread=False,stdoutToServer=True,stderrToServer=True);import sys;sys.argv=sys.argv[1:];execfile(sys.argv[0])" $@
Para usarlo, copienlo en un archivo ejecutable que esté en el path y cambien PYDEVD_LOCATION para que apunte a dónde tienen pydev (en el script de arriba está como es en mi compu).
A partir de ahora puedo debuguear en root haciendo sudo pydevd my_script_que_corre_como_root.py y lo abre en el debugger de eclipse.
Happy hacking,
Aureliano.
Poner un certificado nuevo en un ELB debería ser fácil, pero no. Genero un .csr y una clave privada a partir de un .conf usando openssl, lo mando a la autoridad certificante y cuando lo quiero subir a AWS se queja, "Invalid private key". ¿Qué carajo te pasa AWS?
Lo que pasa es que es hincha bolas. Solo toma claves RSA. Si tu clave privada empieza así:
-----BEGIN PRIVATE KEY-----
Hay que transformarla en una que empiece así:
-----BEGIN RSA PRIVATE KEY-----
Para eso, hay que correr un comandito en openssl:
openssl rsa -in my.private.key -text
La salida está en el formato que necesito :D. Por suerte esto ya lo habían descubierto antes, porque sino hubiera estado mucho más tiempo para encontrarlo.
Happy hacking,
Aureliano.
Por algún motivo, mi conexión wifi está dropeando paquetes. No creo que sea el aparato, ya que probé con 2 distintos. Ahora voy a probar otra cosa. Lo que voy a hacer es cambiar el MTU (o sea el tamaño máximo de cada paquete) para la conexión wifi para ver si eso lo arregla.
Hacer eso en Windows 7 es re-oscuro. Googleando encontré acá cómo hacerlo. Dejo las instrucciones abajo para que quede claro:
Para salir a través de un proxy usando la línea de comando de svn hay que cambiar la configuración del cliente de svn. Una opción es ir a tocar el archivo ~/.subversion/servers, otra opción es pasarle por línea de comando host y port del proxy así:
svn --config-option servers:global:http-proxy-host=the.proxy.server --config-option servers:global:http-proxy-port=3128 checkout http://some.svn/repo
Happy hacking!
Etiquetas:
bash,
http_proxy,
linux,
subversion,
svn,
unix
Cuando una conexión de ssh se caga, para poder seguir usando la terminal hay que hacer: ENTER ~. ENTER y la conexión de ssh se corta.
El problema es que no sé como hacer para hacer algo similar para una conexión nesteada.
Desde mi workstation me ssheo al host A y desde el host A al B.
Las conexiones quedan así:
W ----ssh-----> A ------ssh-----> B
Y por algún motivo se caga la conexión entre A y B, todo el quilombo queda así:
W ----ssh-----> A --ssh(cagó)---> B
Para romper la conexión entre A y B hay que hacer: ENTER ~~. ENTER
El ñuflo extra es para escapar el ~ de la primera conexión y que le llegue a la segunda.
Happy hacking!
Keepass2 en Linux (corriéndolo con mono), pone el password en un clipboard (cuando hacés Ctrl-C) que gnome-terminal no usa por default (mirando con xset, lo pone en el clipboard "clipboard", pero no en el "secondary"). Por lo tanto, no anda ni CTRL-V ni el menú para hacer paste del password (o el usuario) sacado de keepass2. Este problema lo vi en Linux Mint, pero debería darse en cualquier interacción entre mono y gnome-terminal.
Workarounds:
Etiquetas:
debian,
devop,
gnome-terminal,
keepass2,
linux,
linux mint,
mono,
ubuntu
La vida me transformó en un devop por un rato, así que estoy teniendo algunos problemas de sysadmin. Entre ellos, estoy buscando un buen sistema de manejo de passwords. Hay passwords que son sólo míos (muejeje!) y passwords que tenemos que tener varias personas. Por último, estaría bueno tener acceso a esos passwords desde varias compus.
Para tener los passwords en una sola compu, keepass o password safe están bien. Para manejar los passwords que uso por la web, last pass parece estar bueno, pero ¿puedo tener passwords que uso en la línea de comando? (ejemplo, claves para desencriptar archivos .pem).
¿Pero, cómo hago para compartir algunos de estos passwords con otras personas? La solución que se nos ocurrió en el laburo es meter el archivo de keepass en el control de versiones (svn). Los problemas de esto es que si por algún motivo hay un conflicto, la resolución es un quilombo y que tener derecho más granulares sobre los passwords no parece algo fácil (¿diferentes archivos de keepass, con diferentes passwords, en función del dominio de seguridad?).
¿Alguien probó last pass premium? (que permite compartir passwords)
¿Alguna otra sugerencia?
Happy hacking,
Aureliano.
Update: Parece que hicieron un estudio parecido al que yo propongo en la década del 80, y los resultados no fueron nada alentadores para los defensores de la astrología.
Ayer estaba charlando y se me ocurrió un experimento que se puede hacer para validar o refutar que las cartas natales funcionan.
Ingredientes:
Etiquetas:
carta natal,
ciencia,
cómo,
horóscopo,
pseudociencia
El otro día fui a ver a un amigo a hacer standup y eso me inspiró para escribir un monologuito sobre algunos aspectos del tango como baile social. Cualquier parecido o divergencia con la realidad es pura coincidencia. El título del mismo es "Cómo empecé a hacer stand up"
Hola,
yo soy Aureliano, sí mis viejos me la hicieron complicada, y bailo tango.
Ustedes se preguntaran como puede ser que baile tango. (con voz de viejo todo encorvado) No tengo 80 años, soy carilindo (guiño de ojos), parezco un cantante de glam de la década del 80, o me parezco a Jesús (peinado a 2 aguas mientras miro el piso, cuando termino miro al público).
Bueno, ¿cuántos de ustedes bailan tango? (Mirando al público)
Veo que no hay nadie (o hay muy poquitos) que saben bailar tango acá. Pensé que estábamos en la cuna del tango, donde nació Gardel, donde compusieron la Cumparsita, donde se ponía en pedo Piazzolla (pausa). Buenos Aires es la cuna del tango. Bueno, les voy a contar un poco como funciona todo esto porque sino no van a entender ningún chiste.
El baile del tango viene en dos sabores, escenario y salón. El tango escenario es el que pueden ver en un teatro, o en Caminito un domingo al mediodía. Una o más parejas haciendo piruetas. Los chabones, (reflexionando) ¿chabón si que es una palabra tanguera, no?, los chabones disfrazados de muñeco de torta, con una flor roja en el ojal. Las minas con medias de red y un vestido largo rojo con un tajo al costado (señalo con el brazo opuesto haciendo el recorrido del tajo) que les llega hasta la axila. Bueno (pausa), yo no hago eso.
Lo mío es el tango salón, o tango social. Ese tango es el tango que bailaban nuestros abuelos, rechazaron nuestros padres. Se baila en unos lugares que se llaman milongas. Yo tengo identificados tres circuitos en los que clasifico a las milongas.
El primero es el turístico, es el que más conoce la gente que no baila. Suelen ser milongas que están por el centro. Hay principalmente turistas de todo origen, edad, sexo, nivel de baile y peso.También hay argentinos tratando de rapiñar algo, ¡cuándo no!. Hay profesores y profesoras de tango buscando alumnos, gente que alquila alojamiento, taxi-dancers, que son algo así como las putas del baile. Algún o alguna patadura no quiere planchar en la milonga y le paga a un bailarín o bailarina para que los baile. Y, como no, siempre hay alguien en busca de sexo ocasional (cara de inocente) y/o un viajecito a Europa desde arriba.
El segundo circuito es el de las milongas de viejos. Éstas abren generalmente más temprano y son en lugares como el Cuartel de Bomberos Voluntarios de Lanús. Estas milongas son extrañas. No hay nada más bizarro que ver a una señora de la edad de tu abuela vestida con un traje de leopardo pegado al cuerpo, al lado otra que está con una minifalda y con ellas una tercera que en un traje largo parece un matambre. Acá no van a encontrar ni un turista.
Por último está el circuito joven. Aunque su epicentro está por Palermo, también es fuerte por la zona de San Telmo. Hay un montón de turistas en este circuito, y también un montón de argentinos y argentinas, y, como dice el nombre, acá vienen el grueso de la gente de menos de 40. Este circuito se caracteriza por la violencia de las patadas que se propinan en la pista. Por ejemplo el otro día presencié como una mina tiró un voleo alto y cortó el muslo de otra mina con el taco aguja.
En cualquiera de los circuitos funciona el cabeceo. El mismo consiste en hacer un movimiento en diagonal ascendente apuntando hacia la pista mientras estableces contacto visual con una mina (mirar a alguien del público y hacer el movimiento lentamente). Si la mina está de acuerdo con la invitación asiente con la cabeza y espera a que la vaya a buscar. ¡Chicas! no se levanten directamente que si el cabeceo no es para ustedes es un bochorno.
Te acercás a la pista, y muchas veces sin mediar una sola palabra, te fundís en un abrazo. Esto es de lo más lindo del tango, y un tanguero que se precie puede, solo con ese abrazo, saber muchas cosas de la mina con la que está. ¿Estás nerviosa? ¿Está triste? ¿Se bañó? ¿Tiene las tetas operadas? (gesto de tetas con las manos, pausa). Podés saber todo eso antes de saber como se llama.
En las milongas se bailan grupos de 4 tangos, que se llaman tandas y que están separados entre sí por una canción no bailable, que se llama cortina. Una vez que termina la tanda, todos se van de la pista.
Entre tango y tango, dentro de una tanda, la pareja de bailarines tiene unos 20 segundos para tener una pequeña charla. Y, la verdad, nunca supe bien qué decir en esos momentos. Sí les puedo contar que intenté.
Yo: Qué linda tanda
Ella: qué orquesta es?
Yo: ni idea (cara de :-\ )
Yo: "La milonga está re-llena"
Ella: Y?
Yo: (cara de y en donde me meto)
Yo: "La milonga está re-llena"
Ella: Me estás diciendo gorda?
Yo. De dónde sos?
Ella. Eurasia.
Yo. Y eso qué es?
También probé no decir nada. A veces está todo bien, pero no siempre. Es especialmente malo cuando el disk jockey tarda en poner el siguiente tango. Son 5, 10 o 20 segundos fatales. De mirarse sin decir nada.
Lo peor, para mi, es preguntar el nombre de mi bailarina.
Yo: Cómo te llamas? (cara de langa)
Ella: Ya es la cuarta de vez que me preguntás mi nombre.
Yo: ups
Ella: Y a una amigas ya le preguntaste 2 veces
Yo: (hago un pozo con una pala y me entierro)
Aunque a veces zafo un poco más.
Yo: Dejé de preguntar nombres porque siempre me olvido.
Ella: Yo siempre me olvido también. ¿Cómo te llamás?
Yo: Aureliano.
Ella: Mi nombre también es complicado.
Yo: ¿Cómo es?
Ella: Emanuela
Yo: Mi segundo nombre es Emanuel
Ella: ¡Me parece que ya tuvimos esta conversación alguna vez!
Yo: ¡Esto lo voy a poner textual en el monólogo que estoy escribiendo!
Una cosa que me funcionó llamativamente bien es decir "no sé qué decir entre tango y tango", el problema es que como ahora sé que decir, ahora no sé qué decir y ahora que no sé qué decir sé que decir. ¡Bertrand Russell estaría orgulloso de mi!
Y reflexionando sobre esto me di cuenta que de da para hacer de esto un guión y así empecé a hacer standup.
Publicaron en el blog de Core un artículo donde explico qué es esto del crackeo confidencial de passwords (en inglés). El paper, "Oblivious password cracking", lo había anunciado en este post.
Happy hacking,
Aureliano.
Etiquetas:
criptografía,
hacking,
hellman tables,
paper,
passwords,
pir,
rainbow tables
El viernes presenté el paper del que les conté hace unos meses, "An Oblivious Password Cracking Server" en el 4to Workshop de Seguridad Informática, parte de 41va JAIIO.
Salió todo buenísimo, y están disponibles el paper y los slides en la página de CoreLabs.
Happy hacking,
Aureliano.
Etiquetas:
criptografía,
hacking,
hellman tables,
paper,
passwords,
pir,
rainbow tables
Update: El setting debug=True hace que se recargue todo lo que puede ser recargado. Creo que este hack no hace falta.
Este pequeño método deja sin efecto el cache de contenido estático de tornado.
def debug_hacks():
Discá *#06# en tu TE y aparece tu número de IMEI. Esto está en el standard de GSM (o sea, debería andar en todos los celulares de Argentina, salvo Nextel).
Happy hacking,
Aureliano.
Si quieren configurar subclipse en windows sigan estas instrucciones.
Happy hacking,
Aure.
Ya pasaron 2 semanas desde que pusiste todo a fermentar. Abrís el fermentador y tiene olor a cerveza. ¿Y ahora qué?
Ya falta poco. Desinfectamos las botellas, las tapas, una de las ollas con canilla y una manguera. Preparamos la tapadora. Diluímos el azucar en agua sin cloro (8g por litro de cerveza). Tiramos el agua azucarada en el fermentador y pasamos todo el contenido del fermentador a la olla que desinfectamos hace un ratito.
Enchufamos la manguera en la canilla y llenamos las botellas, dejando el cuello sin llenar para que la presión del gas no haga quilombo. Y las tapamos.
Felicitaciones, las botellas están listas. Ahora hay que esperar 2 semanas con las botellas a temperatura ambiente para que se forme el gas y se termine de asentar el gusto de la cerveza. Una vez pasadas las 2 semanas, podés meter las botellas en la heladera y disfrutar de la riquísima cerveza que hiciste vos mismo.
Happy hacking,
Aureliano.
Etiquetas:
cerveza
Aceptaron el paper "An Oblivious Password Cracking Server" en el
4to Workshop de Seguridad Informática (WSegI) de la JAIIO.
Cuando lo presente mando más data por acá,
Aureliano.
Etiquetas:
criptografía,
hacking,
hellman tables,
paper,
passwords,
pir,
rainbow tables
Etiquetas:
cerveza
Etiquetas:
cerveza
Hacer ptys en python es complicado. En este post (en inglés) muestran cómo hacer un programa en python pueda encapsular a otro y hacerle creer que tiene su terminal.
Happy hacking,
Aureliano.
Abajo pongo un script que hice en python para cambiar el certificado por un ELB usando boto. Asumo que el load balancer escucha en el puerto 443 (https). Cambien las constantes para que use las que les corresponda en su proyecto.
import boto
AWS_ACCESS_KEY = "AWS_ACCESS_KEY_HERE"
SECRET_KEY = "SECRET_KEY_HERE"
PRIVATE = """\
PRIVATE KEY .pem CONTENT HERE
"""
BODY = """\
CERTIFICATE .pem CONTENT HERE
"""
CHAIN = """\
CHAIN CERTIFICATE .pem content HERE
"""
CERT_NAME = "name-for-the-new-cert"
ELB_NAME = "elb-to-be-updated"
iam = boto.connect_iam(AWS_ACCESS_KEY, SECRET_KEY)
iam.upload_server_cert(CERT_NAME, BODY, PRIVATE, CHAIN)
cert = iam.get_server_certificate(CERT_NAME)
elb = boto.connect_elb(AWS_ACCESS_KEY, SECRET_KEY)
for lb in elb.get_all_load_balancers():
if lb.name == ELB_NAME:
lb.set_listener_SSL_certificate(443,cert.arn)
Happy hacking,
Aureliano.
Leyendo Hacker News me crucé una explicación re buena de cómo hacer objetos en JavaScript. Disfrútenla.
Happy hacking,
Aure.
Etiquetas:
javascript
Estoy tratando de copiar archivos en mi red WIFI, pero estoy teniendo un problemita.
Tengo un modem ADSL WIFI como el que explico en mi post anterior. Puse en la red WIFI 2 compus a las que se le asignaron los IPs 10.0.0.3 y 10.0.0.4 respectivamente.
En ambas compus me conecté a la red WIFI y puedo navegar x internet. Cada una de ellas puede pinguear al gateway (10.0.0.2):
>ping 10.0.0.2
Haciendo ping a 10.0.0.2 con 32 bytes de datos:
Respuesta desde 10.0.0.2: bytes=32 tiempo=3ms TTL=64
Respuesta desde 10.0.0.2: bytes=32 tiempo=1ms TTL=64
Respuesta desde 10.0.0.2: bytes=32 tiempo=1ms TTL=64
Respuesta desde 10.0.0.2: bytes=32 tiempo=4ms TTL=64
Estadísticas de ping para 10.0.0.2:
Paquetes: enviados = 4, recibidos = 4, perdidos = 0
(0% perdidos),
Tiempos aproximados de ida y vuelta en milisegundos:
Mínimo = 1ms, Máximo = 4ms, Media = 2ms
BCM96338 ADSL Router
Login: admin
Password:
> ping 10.0.0.3
NoHang -> ping 10.0.0.3
PING 10.0.0.3 (10.0.0.3): 56 data bytes
56 bytes from 10.0.0.3: icmp_seq=0 ttl=128 time=5.0 ms
56 bytes from 10.0.0.3: icmp_seq=1 ttl=128 time=0.0 ms
56 bytes from 10.0.0.3: icmp_seq=2 ttl=128 time=0.0 ms
--- 10.0.0.3 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.0/1.6/5.0 ms
> ping 10.0.0.4
NoHang -> ping 10.0.0.4
PING 10.0.0.4 (10.0.0.4): 56 data bytes
56 bytes from 10.0.0.4: icmp_seq=0 ttl=128 time=0.0 ms
56 bytes from 10.0.0.4: icmp_seq=1 ttl=128 time=0.0 ms
56 bytes from 10.0.0.4: icmp_seq=2 ttl=128 time=0.0 ms
56 bytes from 10.0.0.4: icmp_seq=3 ttl=128 time=0.0 ms
--- 10.0.0.4 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.0/0.0/0.0 ms
>
>
>ping 10.0.0.4
Haciendo ping a 10.0.0.4 con 32 bytes de datos:
Respuesta desde 10.0.0.3: Host de destino inaccesible.
Respuesta desde 10.0.0.3: Host de destino inaccesible.
Respuesta desde 10.0.0.3: Host de destino inaccesible.
Respuesta desde 10.0.0.3: Host de destino inaccesible.
Estadísticas de ping para 10.0.0.4:
Paquetes: enviados = 4, recibidos = 4, perdidos = 0
(0% perdidos),
>route print -4 10.*
IPv4 Tabla de enrutamiento
===========================================================================
Rutas activas:
Destino de red Máscara de red Puerta de enlace Interfaz Métrica
10.0.0.0 255.255.255.0 En vínculo 10.0.0.3 281
10.0.0.3 255.255.255.255 En vínculo 10.0.0.3 281
10.0.0.255 255.255.255.255 En vínculo 10.0.0.3 281
===========================================================================
Rutas persistentes:
Ninguno
Hola,
si tienen wifi con arnet, quizás esta info les sirva. En mi casa, el ip 10.0.0.2 es el ip del access point. Si te conectás a http://10.0.0.2 podés cambiar algunas configuraciones básicas.
Pero hay más. Si te conectás por telnet a 10.0.0.2 contesta:
BCM96338 ADSL Router
Login:
No tiene sentido, pero a veces se puede cambiar el comportamiento de los objetos cambiando los nombres de las clases pero sin mencionar su nombre en el código, jugando con la forma cabeza de hacer name-mangling de los atributos privados:
$ python
Python 2.7.2+ (default, Oct 4 2011, 20:03:08)
[GCC 4.6.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> class A(object):
... def __init__(self): self.__sarlanga = 1
... def s(self): return self.__sarlanga
...
>>> B = A
>>> B
>>> class A(B):
... def __init__(self):
... B.__init__(self)
... self.__sarlanga = 2
...
>>> aa = A()
>>> aa.s()
2
>>> class C(B):
... def __init__(self):
... B.__init__(self)
... self.__sarlanga = 3
...
>>> c = C()
>>> c.s()
1
Etiquetas:
hack,
name_mangling,
python
Como muchos de ustedes saben, soy padre y estoy divorciado. Eso hizo que me preocupe por encontrar cuál es la forma éticamente correcta de manejar un montón de situaciones bastante complicadas, y estoy buscando un marco moral que me permita tomar decisiones correctas y justas.
Estoy usando VMWare Player 4.0.2 en un Linux Mint de 64 bits y quiero instalar las VMWare Tools en los guests que vaya haciendo. El problema es que VMWare Player no viene con los tools y la opción del menú para instalar las tools no anda :(.
Workarround:
Happy hacking!
Fuente: http://brandonhutchinson.com/Installing_VMware_Tools_with_VMware_Player.html
Etiquetas:
linux,
linux mint,
linux x64,
vmware,
vmware tools
Algo que es muy común cuando uno lleva a una principiante es que "baile sola". O sea, que da pasos que no son marcados. ¿Por qué? Creo que es el miedo al vacío, a que había que hacer algo en ese compás y el paso que le enseñaron era ése.
Poder esperar hasta el siguiente paso, manteniendo el equilibrio, no es fácil. Y a mi me gusta mucho hacer pausas cuando bailo y pasar 2 o 3 compases sin pisar (o sea, conservando el peso de los pies tanto míos como los de mi pareja). Entonces estuve buscando alguna forma de poder ayudar a que puedan estar sin pisar, cosa que hace que yo disfrute más del baile y que ellas bailen mejor (y, espero, que lo disfruten también). A lo que llegué, es que están demasiado enfocadas en los pasos. Creo que esto es algo común tanto para cuando llevamos como para cuando somos llevados.
Mi contrapropuesta es que pensemos en otra cosa. Pensemos en nuestra pareja de baile y como interactúa con nosotros. En el calor que se siente en las partes del cuerpo que están en contacto. Brazo con espalda, mano con mano, pecho con pecho, panza con panza, etc. Y hagamos eso todo el tiempo. Pensemos en cómo va variando cuando hacemos diferentes pasos, con la respiración. Si nos concentramos, a veces también podemos sentir los latidos del corazón.
Lamentablemente, cuando llevamos tenemos otras responsabilidades. Manejar el espacio y la circulación en la pista. Empezar y terminar las frases de la música. Preveer el final para no quedar pagando. Pero si tenés la suerte de estar siguiendo, podés entregarte 100% a sentir a tu pareja de baile, que es lo más lindo del tango.
Nos vemos en la milonga,
Aureliano.
PD: No, no doy clases de tango.
Etiquetas:
tango
Hoy salió la versión 4.0 de bindiff, y le incluyeron un feature que se llama "Combined visualization of two flowgraphs" que se parece mucho a lo que presenté en Hack.lu 2010 (y que presenté anteriormente en este blog). De todas maneras, me parece que les faltó ir hasta el fondo y unir cada par de basic-blocks en uno solo (si alguien de Zynamics ve este blog, miren mi paper para ver cómo hacerlo).
Happy hacking,
Aureliano.
Etiquetas:
aureliax,
bindiff,
seguridad,
turbodiff,
visualización
Ayer fue un día bizarro. A la mañana participé de la grabación de un programa del History Channel que se llama "Super Humanos" o algo así. En el mismo estuve con 2 amigos evaluando a Jaime García Serrano, que calculó raíces cuadradas, logaritmos, funciones trigonométricas, las inversas de las trigonométricas y factoriales, mientras nosotros teníamos que decir si lo calculaba bien o no, mirando los resultados en una compu.
Salí corriendo porque a la tarde tenía otro compromiso. A las 14.15 tenía turno para que me saquen una muela de juicio. Me sacaron la muela y ahora estoy tomando antibióticos y analgésicos, y el helado es mi principal alimento.
A la noche fui a La Glorieta, donde bailé algunos tangos y me encontré con amigos.
Al final, me fui a dormir.
PD: Me dijeron que el programa sale en abril.
Etiquetas:
bizarro,
dentista,
glorieta,
history channel,
tango
Para zippear un directorio controlado por svn sin poner la info administrativa de svn podés ejecutar este comando en bash y va a andar:
find . -not \( -type d -name ".svn" -prune \) -type f -print | zip -@ ~/zip_file_name
EXPLICACIÓN DE UNA COMPARACIÓN EN LA LETRA CAMBALACHE
¡EXACTA REAL DEMOSTRABLE Y CREIBLE;PARECE MENTIRA QUE JAMAS LO EXPLICARAN LOS MILES DE ESCRIBAS, LITERATOS E INTELECTUALOIDES QUE DICEN " ESTUDIAR EL TANGO"
La Biblia y el Calefón –
Se habla de ello y la mayoría no sabe de qué se trata:
He aquí la historia de un hecho de la vida cotidiana, que acontecía en la ciudad de Buenos Aires –no sé si en otros lugares pasaba o no–, y que explica el porqué de la aparentemente surrealista asociación de la Biblia junto al calefón que aparece en el tango "Cambalache", cuyas letra y música fueron compuestas por Enrique Santos Discépolo en 1935.
La historia tiene relación con los baños, la higiene personal y la forma de realizarla; y como no se me escapa que algunos lectores pueden ser jóvenes y pueden no haber conocido otro tipo de baños que los que se estila usar en la actualidad al menos en el mundo occidental y cristiano, voy a recordar primero un par de datos que considero necesario sean tenidos en cuenta.
Los baños que conocemos y que en algunos lugares son llamados 'completos', es decir, los que constan como mínimo de retrete inodoro, lavabo y ducha (algunos exquisitos, como el irresponsable que escribe, exigen que además tenga bidet –artefacto desconocido en muchos sitios–) son relativamente nuevos.
Hasta finales del siglo XIX se utilizaban bacinillas (también llamadas ‘tazas de noche’), cuyos contenidos eran arrojados por las ventanas al grito de "agua va"; y antes aún, letrinas, que solían estar en los fondos de las casas.
En Buenos Aires coexistieron bacinillas y letrinas hasta principios del siglo XX, época en que las familias ‘acomodadas’ comenzaron a instalar baños.
Luego el uso de baños se generalizó y se empezó a construirlos en todas las viviendas, aun en las más modestas. El sencillo 'miniambiente' constaba al menos de retrete y lavabo y si los lujuriosos dueños de casa gustaban de practicar la morisca costumbre de lavarse todo el cuerpo más o menos seguido, y si además tenían medios económicos suficientes como para costearse ese capricho, los baños también tenían una ducha. Claro, si había una ducha era necesario calentar el agua, así que al lado de la ducha se instalaba un calefón.
Sin embargo, el papel higiénico tardó en obtener su carta de ciudadanía
para poder trabajar en limpio en estas sucias tierras y aun cuando apareció era bastante caro y no estaba al alcance de todas las familias, las cuales se veían obligadas a utilizar para esos fines sanitarios el vulgar papel de diario o, en su defecto, cualquier otro.
Por supuesto, eran muy estimados los papeles más sedosos, así que los sufridos usuarios trataban de conseguir en las verdulerías y fruterías los papeles con los que venían envueltas las manzanas y otros productos de campo.
Otro muy apreciado era el llamado ‘papel biblia’, especialmente delgado y suave.
Ahora bien, ya por entonces existía la Sociedad Bíblica, una de cuyas misiones parece ser la de difundir la Biblia protestante, para lo cual regalaba ejemplares del sagrado libro –en la actualidad, lo sigue haciendo–.
Pues, muchos de los habitantes de Buenos Aires deben de haber parecido devotos creyentes, ya que aceptaban de continuo esas gentilezas, y que siendo mayoría la grey católica, lo mismo pasaban y retiraban la biblia protestante tantas veces como sabían que la Sociedad las tenía en obsequio en las calles, plazas o en su sede central .
LA BIBLIA Y EL CALEFÓN
Sin embargo, cuentan los hombres dignos de fe (aunque Alá sabe más) que quienes obtenían esas Biblias les perforaban una tapa y las colgaban de un gancho de alambre, al lado del calefón, cerca del retrete, e iban arrancando las suaves hojas para usarlas como papel higiénico.
En este hecho se habría inspirado Enrique Santos Discépolo para decir con elegancia propia de un grande autor:
Igual que en la vidriera
irrespetuosa
de los cambalaches
se ha mezclao la vida,
Y HERIDA POR UN SABLE SIN REMACHE
VES LLORAR LA BIBLIA
JUNTO AL CALEFÓN.
Edgardo G. Maggiora
BARILOCHE
Gracias Mayca por este material!
Un post de este blog se va para arriba. Los números de Aure aparecen en el último libro de Paenza. Mirá la página 224.
Happy hacking,
Aureliano.
Para cortar video usando ffmpeg hay un comando que me resultó re-práctico. Lo pongo acá para acordarme.
ffmpeg -sameq -ss [start_seconds] -t [duration_seconds] -i [input_file] [outputfile]
Etiquetas:
video
adapté una conocida canción para conmemorarlo. Pongo acá abajo letra y acordes.
Mim Sim Mim
Se equivocó la paloma, se equivocaba,
en vez de al norte, al server room
Do Sim MIm
pensó que el cable era paja, se equivocaba
Sol
Pensó que Sun era el cielo,
Mim
la mudanza era mañana,
Do Lam MIm
se equivocaba, se equivocaba
Lam Si7 Mim
que las bandejas manzanas,
Lam Si7 Mim Re
que la calor la nevada,
Sol Si7 Lam
se equivocaba, se equivocaba.
Si7 MIm
Que tu CAT,era tu blusa,
Do Si7 Do Re
que tu bandeja, su casa,
Mim Re Mim Mi7-Lam
se equivocaba, se equivocaba,
Re7 Sol Mim Lam
ella se durmio en la silla,
Si7 Mim
tu en la cumbre de un ra-ack.
Si7 MIm
Que tu CAT,era tu blusa,
Do Si7 Do Re
que tu bandeja, su casa,
Do Mim
se equivocaba, se equivocaba.
Etiquetas:
canción,
música,
paloma,
server room,
servers
Update: Parece que se viene esto como parte de paver 1.1
Hice un pequeño hack y ahora puedo usar el API de fabric cuando escribo tasks de paver y que la tarea se ejecute una vez para cada host.
Para hacer eso, hice un decorator, que se llama multihost y es así:
from fabric import state, network
def multi_host(f):
"""\
Run the decorated function for each host in options.get("host_strings").
Will use the private key set in options.pk if set.
"""
def decoratee(options):
for host_string in options.get("host_strings"):
network.interpret_host_string(host_string)
pk = options.get("pk", None)
state.env.key_filename = [pk] if pk else None
f(options)
decoratee.func_name = f.func_name
return cmdopts((
("pk=", None, "Private key file"),
))(decoratee)
from paver.easy import task, needs
from fabric import api
@task
def find_hosts(options):
options["host_strings"] = ["host1", "user@host2", "user2@host3:2222"]
@task
@needs("find_hosts")
@multi_host
def remote_hello_world(options):
api.run("echo hello world")