2014-04-15

Recuperando mi mongo en debian

Update: La máquina en la que hice esto es un debian. De todas maneras en ubuntu seguramente es muy parecido.

Chequeo el estado de mi server mongo en mi debian y me dice:
$ sudo service mongodb status
[FAIL] Checking status of database: mongodb apparently not running failed!


Entonces miro en /var/log/mongodb/mongodb.log y encuentro esta línea:
Unclean shutdown detected.
Please visit http://dochub.mongodb.org/core/repair for recovery instructions.

¿Hago lo que dice ahí de una? No. Porque el mongo en ubuntu corre con un usuario específico. Mejor hago
$ sudo -u mongodb mongod -f /etc/mongodb.conf  --repair

Espero un rato, y termina de correr el script. Después hago:

$ sudo service mongodb start
[ ok ] Starting database: mongodb.

Happy hacking,
Aureliano.

2014-04-11

Pipeando procesos en python

A veces uno quiere correr varios procesos en python y enchufar el standard output de un proceso con el stdin del siguiente. Esto sería equivalente a hacer en el shell:
$ prog1 param1 | prog2 param21 param22 | prog3

Para poder hacer algo así en python hice este método:
import subprocess
def pipe(*args):
    last_proc = None
    for command in args:
        in_file = last_proc.stdout if last_proc else tempfile.TemporaryFile()
        proc = subprocess.Popen(command, stdin=in_file, stdout=subprocess.PIPE)
        if last_proc:
            last_proc.stdout.close()
        last_proc = proc
        

    last_proc.communicate()

Para hacer lo mismo que el comando de arriba hay que hacer:
pipe(
  ("prog1", "param1"),
  ("prog2", "param21", "param22"),
  ("prog3",)
)

La única limitación es que no puedo procesar la salida de standard output del último proceso. 

Happy hacking,
Aureliano.

2014-04-08

scl y screen

En RedHat existe un mecanismo para tener en el mismo host diferentes versiones del mismo software que se activa corriendo desde línea de comando. Por ejemplo, para activar python27 (en vez del 2.7, default de la distro) hay que correr scl enable python27 bash.

El problema es que si después corrés screen, ese seteo no pasa en forma limpia al shell que corre adentro del screen. Por lo tanto, lo que hay que hacer es hacer el enable "adentro" del screen. Por ejemplo, para correr un bash en screen con soporte para python 2.7 hay que correr screen scl enable python27 bash

La idea de cómo hacer esto la saqué de la documentación de CentOS. Busquen "coreutils component" dentro de la página para ver el detalle.

Happy hacking,
Aureliano.

Hacer un pem con clave a partir de uno sin clave

Tengo un .pem sin clave que me sirve para acceder a un server y me parece demasiado inseguro. Entonces corro:

openssl rsa -des -in orig.pem -out con-clave.pem 

Me pide la clave y en con-clave.pem tengo el .pem con clave, así que puedo borrar el otro (pero lo pruebo antes por las dudas).

Happy hacking,
Aureliano

2014-04-07

Nombres para sandro

Estoy pensando los nombres para los subcomponentes de sandro. Voy a seguir la línea del primer intento y usar nombres de canciones de Sandro (compuestas o interpretadas por él) para nombrarlos.
Acá les tiro mis ideas:

  • rosa: sistema de templating.
  • tengo: persistencia.
  • ya: sistema de caché.
  • asi: unit-testing framework.
  • penumbras: el sistema de base. Carga módulos, integra con la JVM.
  • maniqui: mock objects.
  • ave_de_paso: lib de promises.
  • camino: routing (la canción es "Por algún camino").
  • nada_mas: colección de helpers.
Voy a ir agregando cosas a la lista a medida que se me ocurran o me las sugieran.

Espero sus sugerencias, 
Aureliano.

2014-03-30

sandro reboot

Hace ya casi 4 años empecé un proyecto para hacer más fácil hacer páginas web seguras al que llamé sandro. Ahora estoy empezando el mismo proyecto de nuevo, siguiendo con mismas ideas rectoras:

  • Un solo lenguaje en todos lados, JavaScript.
  • Templating client-side y server side compartiendo código.
  • Validación de datos en el cliente y server compartiendo código.
  • Seguro por defecto. El diseño del framework debería hacer que sea más fácil hacer aplicaciones seguras que inseguras.
La primera versión va a estar basada en rhino, igual que la vez anterior, pero va a haber algunos cambios que creo que son importantes:
  • No va a estar enfocado a correr en app-engine.
  • Para mantener la idea de que haya JavaScript en todos lados, el motor de base de datos elegido va a ser mongodb.
  • Para reconciliarme con la naturaleza asíncrona y mono-thread del browser, voy a cambiar el manejo de módulos de commonjs por requirejs en el cliente y una API compatible con requirejs en el server.
Si quieren ir viendo el avance del proyecto, está en un proyecto público de bitbucket.

Espero feedback y, sobre todo, pull requests.

Happy hacking,
Aureliano.

2014-03-16

Cabeceo, técnica y táctica

En muchas milongas es de mala educación acercarse directamente a una persona y preguntarle si quiere bailar. Yo entiendo que es porque si no quiere, la forzás a elegir entre 2 opciones que son una cagada. La primera es bailar con vos de todas maneras y la segunda es exponerlos a ambos a que quede claro que no quiso bailar con vos.
Para evitar esto, existe un procedimiento que se llama cabeceo y es así (en su forma heteronormativa):

  1. Hombre y mujer establecen contacto visual.
  2. El hombre, sin romper el contacto visual, inclina su cabeza levemente hacia la pista.
  3. La mujer, sin romper el contacto visual, asiente con la cabeza.
  4. El hombre, sin romper el contacto visual, se acerca a donde la mujer esté sentada.
  5. Ambos van juntos hacia la pista.
Aunque parezca bastante machista, en realidad no lo es. El secreto está en el contacto visual. Si alguno de los 2 no quiere bailar con el otro, todo lo que tiene que hacer es romper el contacto visual. Así la otra parte sabrá que no quiere bailar y evita el escarnio público del rechazo (el rechazo en sí me parece que es inevitable).
Ahora la táctica. Si sos mujer y querés bailar, lo que tenés que hacer es:
  1. Estar bien sentada, tu postura corporal es lo que nos dice si querés bailar o no.
  2. Prestá atención a los bailarines con los que querés bailar, y tratá de establecer contacto visual con ellos. Si estás hablando con la chica que está sentada al lado tuyo, sin prestar atención a tu alrededor, es mucho más difícil invitarte a bailar. Esto es especialmente importante durante el primer tango de la tanda. 
Si sos hombre, 
  1. Tenés que hacer que te vean. Para eso en muchas milongas es normal circular por el pasillo (o borde de la pista)
  2. Salvo que tenga mucha confianza con la bailarina, o estés en una milonga que el cabeceo no se use, no invites a bailar a alguien sin seguir el procedimiento de arriba.
El procedimiento de arriba sirve para evitar malos entendidos. Si 2 bailarines invitan a la misma bailarina. La bailarina va a mantener contacto visual con el que haya elegido, y el otro podrá retirarse sin que nadie se de cuenta lo que pasó. Lo mismo si 2 bailarinas piensan que las invitó el mismo bailarín.

Nos vemos en las milongas,
Aureliano.

2014-03-14

Selección de los hijos

En este post no estoy proponiendo al hijo del Kun para la selección de fútbol sino que quiero mostrar una solución a un problema puntual en d3. Hace un tiempito postié cómo hacer para hacer un selector de CSS que busque solo en los hijos de un nodo. El objetivo era hacer más robustas las selecciones de nodos en los gráficos que hago con d3. Lamentablemente ese truco no anda con un montón de browsers, pero encontré otro mucho más simple. Si queremos una selección con todos los nodos hijos de la selección actual, lo más fácil es hacer:

my_selection.selectAll(function() { return this.childNodes })

Al final era bastante fácil. No entiendo porqué esto no está en ningún lado. Casi siempre cuando uso selectAll quiero obtener los hijos de los nodos de la selección actual.

Happy hacking,
Aureliano.

2014-03-10

Como esto pero distinto, no en CSS

Quiero poder decir, esta clase es como tal otra, pero el font es de tamaño x; y no puedo.

Acá está el detalle: http://stackoverflow.com/questions/1065435/can-a-css-class-inherit-one-or-more-other-classes.

Otro motivo más que muestra porqué habría que tener un lenguaje de programación y una lib estándar en vez del hack horrible de CSS.

Happy hacking,
Aureliano.

2014-02-20

Word wrap en SVG

El elemento text de svg no tiene forma de decirle que corte el texto en líneas respetando un ancho, ni como cambiar el font de una parte del texto, etc. Por suerte existe otro elemento que se llama foreignobject y sirve, entre otras cosas para embeber html. Y obvio que el html embebido puede hacer word wrap (como siempre en html). Cuando pueda lo voy a probar bien, por ahora pueden ver en este artículo como usarlo.

Happy hacking,
Aureliano

2014-02-13

CSS selector, hijo de un nodo

Update: Lo probé en Firefox 24 y no anda. La funcionalidad está implementada pero no está habilitado en la configuración por defecto (https://developer.mozilla.org/en-US/docs/Web/CSS/:scope).

En un montón de bibliotecas para el browser, como d3 o jquery podemos usar selectores de CSS para elegir nodos que son descendientes de un conjunto de nodos dado. Esta funcionalidad, casi siempre está basada en el método elem.querySelectorAll(css_selector). Hoy descubrí algo muy interesante de este método. Hay una pseudo-clase de css que se llama :scope y cuando es usada en el selector del método de arriba refiere al elem sobre el que se hizo la consulta.
Ésta pseudo-clase, la podemos usar para elegir a los hijos de un elemento que cumplan cierta condición. Por ejemplo, elem.querySelectorAll(":scope > .klass") busca todos los elementos hijos (y solo hijos, no nietos) de elem que tienen klass como clase.
Como las bibliotecas que mencioné al principio usan esto en sus entrañas, también se puede usar en las mismas cuando buscás nodos. Por ejemplo, en d3 sería algo así: my_selection.selectAll(":scope > g").
Happy hacking,
Aureliano.
PD: La información original sobre cómo hacer esto la saqué de acá.
PD2: Lo probé con d3 en mi Chrome y anda. La documentación de Firefox también dice que anda, pero no lo probé. El resto de los browsers son un misterio para mi. Si lo prueban en otros contextos, avisen.

2013-12-31

Ema Ortuzar

Si entran a http://www.smn.gov.ar/dpd/tiepre/mercobras/mb3uv.htm pueden la información meteorológica de la estación automática de observación que tiene el servicio meteorológico en la Ciudad de Buenos Aires.

2013-11-29

Delicias del JavaScript

>> 1 == "1"
true
>> 1 === "1"
false

Conclusión, no usar == nunca más

2013-11-27

His road to go

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!!!!!

2013-11-22

D3 tips and tricks

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.

2013-10-28

Fracciones de Peano

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.

2013-09-16

Instalando python 2.5

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:

  • python 2.5 (link)
  • sqlite3 (tarball con autoconf) (link)
  • openssl (link)
  • libsasl2 (link)
  • pycrypto (link)
Una vez que tengan todo eso hay que compilar. Yo decidí hacerlo en un lugar separado ($HOME/p25) para no mezclar las cosas con el resto de mi instalación.

Hay que destarear todo e instalarlo. Para eso, hacé esto (el orden de las instalaciones es importante):

sqlite3:
$ ./configure --prefix=$HOME/p25
$ make
$ make install

openssl:
$ ./config --prefix=$HOME/p25 -shared
$ make
$ make install

libsasl2:
$ ./configure --prefix=$HOME/p25
$ make
$ make install

python:
$ ./configure --prefix=$HOME/p25
$ make
$ make install

pycrypto:
$ PATH=$HOME/p25/bin:$PATH
$ python setup.py build
$ python setup.py install

Y con eso tengo un python 25 en $HOME/p25/bin que puede correr los tests de impacket.

Espero que les sirva,
Aureliano.

2013-08-18

Homeopatía, animales y efecto placebo

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?

2013-07-29

Bouncer aggiornado

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

2013-05-29

No entiendo porqué uno anda y el otro no

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?

2013-05-03

Debugueando en root con pydev

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.

2013-04-04

Invalid private key

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.

2013-03-29

Cambiando el MTU

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:


  1. Abrí un cmd cómo Administrator (botón derecho en Todos los Programas > Accessorios > Símbolo de Sistema y elegí Ejecutar como administrador) ...
  2. Escribí netsh y esperá el prompt
  3. Escribí interface y esperá el prompt
  4. Escribí ipv4 y esperá el prompt
  5. Escribí show interfaces y fijate cuál es la conexión que querés tocar (en mi compu fue Conexión de red inalámbrica)
  6. Escribí set subinterface "Aca va el nombre de la conexion que queres cambiar" mtu=1400 store=persistent
Creo que eso arregla el problema.

Happy hacking,
Aureliano.

2013-03-27

Línea de comando svn por proxy http

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!

2013-03-19

¿Cómo cierro conexiones nesteadas de ssh?

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!

2013-02-21

gnome-terminal y keepass2

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:

  1. Extrañamente, CTRL-SHIFT-INSERT sí pega las cosas que pusiste en el clipboard con keepass2 (fuente: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=645200).
  2. Drag-and-drop de keepass2 a la gnome-terminal correspondiente.
Happy hacking,
Aureliano.

2013-02-03

Bug Brother's Design Rules


  • War is Peace: assume you are at war, all input is an attack, and then you can be at peace.
  • Slavery is Freedom: the more you constrain your code's behavior, the more freedom you have to act. The smaller your interface, the smaller your attack surface.
  • Ignorance is Strength: the less your code knows about, the fewer things it can break. This is the principle of least authority.

2013-02-02

Manejo de passwords

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.

2012-12-27

Cómo convencerme de que las cartas natales funcionan

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:

  • Varias personas que sepan hacer e interpretar cartas natales (que llamaré "adivinos").
  • Varias personas que estén dispuestas a no revelar su fecha y lugar de nacimiento en una entrevista con un adivino (que llamaré "cobayos").
Mecanismo:
  1. Los cobayos son divididos en 2 grupos que tienen igual cantidad de miembros, los "mentirosos" que son aquellos a los que se les cambia levemente la fecha de nacimiento (+- 1 semana) y los "realistas", a los que se les deja la fecha de nacimiento como es. Cada cobayo no sabe si es realista o mentiroso.
  2. Cada adivino es asignado con la misma cantidad de mentirosos y realistas, y usando la información de momento y lugar de nacimiento (que está mal solo para los mentirosos) prepara las cartas natales de cada cobayo.
  3. Los adivinos se reúnen con cada uno de sus cobayos individualmente y tienen una charla de una hora. En esa charla está prohibido que hablen de la fecha exacta o lugar exacto de nacimiento del cobayo. El objectivo de la charla es que el adivino pueda establecer si la fecha y lugar de nacimiento que le dieron del cobayo es correcta o no, viendo si el mismo "matchea" con la carta natal que preparó.
  4. Después de terminar cada entrevista, cada adivino deja escrito si piensa que el cobayo es mentiroso o realista.
  5. Por último, teniendo todas las respuestas de los adivinos, hacemos un test de significación estadística para ver si los adivinos son efectivos distinguiendo a los realistas de los mentirosos.
Si el test estadístico dice que hay diferencias significativas, entonces voy a empezar a creer en esas cartas natales. Mientras tanto, y siguiendo el principio de la navaja de Occam, voy a seguir creyendo que son una paparruchada. 

Happy hacking,
Aureliano.

PD: Tarea para el hogar, diseñar un test parecido para el horóscopo.

2012-12-01

Comida fácil de preparar: Hoy, berenjenas a la plancha.

  1. Prenda el fuego y ponga la plancha encima
  2. Lave una berenjena y córtela en rodajas de aproximadamente 4 milímetros
  3. Ponga las rodajas en la plancha y tíreles un chorrito de aceite de oliva
  4. Espere 5 minutos y délas vuelta.
  5. Espere 5 minutos y apague el fuego
  6. Sirva en un plato.


2012-11-27

Cómo empecé a hacer stand up

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.

2012-09-12

Blogpost explicando mi paper

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.


2012-09-04

Paper publicado

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.

2012-08-09

Inutilizando el caching de contenido estático en tornado

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

    from tornado.web import StaticFileHandler
    import time
   
    StaticFileHandler.CACHE_MAX_AGE = 0.1 #caches 0.1 seconds

    def clean_hash_cache():
        while True:
            StaticFileHandler.reset()
            time.sleep(0.1)
           
    clean_thread = threading.Thread(target=clean_hash_cache)
    clean_thread.daemon = True
    clean_thread.start()

Hay que ejecutarlo antes de arrancar tornado para que sirva.

Happy hacking,
Aureliano.

2012-07-20

IMEI de tu celular

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.


2012-07-18

Subclipse

Si quieren configurar subclipse en windows sigan estas instrucciones.

Happy hacking,
Aure.

2012-07-10

Haciendo cerveza - Día 2

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.

2012-06-25

Paper aceptado

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.

2012-06-09

Haciendo cerveza - Día 1

Preparativos

Asegurate de tener todo lo que necesitás para hacer cerveza. El día anterior, agarrá 60 litros de agua de la canilla y dejala evaporar en las ollas para que se desclore.

Haciendo el mosto

Vas a hacer el "té" más grande de tu vida. Poné en la olla el filtro (o sea la tela) y adentro de ella toda la malta molida (la del kit). Agregá 30 litros (más o menos) del agua desclorada y prendé el fuego. Llevá la temperatura a 65 grados y mantenela ahí por una hora. Si tiene menos de 60 grados o más de 70 la cagaste. Chequeá con el termómetro que estés siempre en el rango de temperaturas correcto. A este proceso se le llama "conversión de azúcares". ¿Ya pasó una hora? Apagá el fuego y, usando la canilla del fondo de la olla, pasá la infusión que te queda a otra olla. Esa infusión se llama "mosto". 
Hay 2 cosas que podés hacer en este paso para obtener más cerveza. Una opción es recircular el mosto poniéndolo de nuevo en la olla que tiene la malta, extrayendo un líquido más denso. La otra, es agregar agua (acordate que esté desclorada). El objetivo es tener el mayor volumen de mosto posible cuya densidad sea de 1040 g/l (tenés el densímetro ahí, ¿no?). En la olla original van a quedar todos los restos de la malta, frenados por el filtro. Tiralos o usalos de abono.

Hervor

Ahora hay que hervir el mosto durante 1 hora. En cuanto rompa en hervor ponele la mitad del lúpulo. Y, 15 minutos antes, empezá a prepararte, porque viene la parte difícil de hacer cerveza. 
15 minutos antes de que termine de hervir activá la levadura poniéndola en un jarrito con un poco de agua desclorada tibia (con temperatura de entre 25 y 30 grados). Después de hacer eso, hay que esterilizar cosas. Usando el alcohol, esterilizá el fermentador, las mangueras y el enfriador. Todo lo que toque el mosto después de hervirlo tiene que estar esterilizado.
5 minutos antes de terminar el hervor, agregale lo que queda del lúpulo y el clarificante (nunca me acuerdo si acá va el whirlfloc o el isinglass :S).

Esto es lo más complicado

Apagá el fuego y hacé el whirlpool (o sea, hacé un remolino en la olla para que los restos que hay adentro queden en el medio). Enchufá el enfriador a las mangueras. Una va a a una canilla de agua fría y la otra al desagote. Meté el enfriador esterilizado adentro del mosto. Tapá la olla. Abrí la canilla para que el enfriador empiece a andar. Este es el momento más jodido cuando hacés cerveza. Si se contamina la cagaste.
Enfriá el mosto a temperatura ambiente y trasvasalo al fermentador. Cuando hayas terminado, tirale la levadura que activaste previamente y cerrá el fermentador, armando la trampa de aire (podés comprar una o improvisar una con una manguera y una botella de gaseosas). Dejá la cerveza en un lugar que tenga poca variación de temperatura. Si hacés Ale, tiene que estar alrededor de los 20 grados (aproximadamente).

Felicitaciones, en este paso ya tenés cerveza. Pero todavía falta para tomarla, la próxima te cuento como sigue.

Happy hacking,
Aureliano.

2012-05-26

Haciendo cerveza - Cosas que necesito

Reusables


  • 2 personas (una tiene que saber hacer cerveza, puedo ser yo ;) )
  • 2 ollas de 40 litros con una canilla en la parte de abajo. La forma de hacerlas es comprar 2 ollas de 40 litros de aluminio, hacerles un agujero con agujereadora y ponerles una canilla. Lo que yo hago es pedirlas prestadas (¡gracias Norbi!).
  • Tapadora (¡gracias Norbi!)
  • Fermentador (o su versión casera, un bidón de Sparkling con un tapón y una trampa de aire)
  • Mi cocina
  • Enfriador. En mi caso es un caño de bronce para gas doblado en forma de serpentina. Compré 3 metros y me quedé corto, mejor compren 5 metros. Si se sienten aventureros pueden hacerse un enfriador a contracorriente
  • 2 mangueras de pvc, las mangueras tienen que encajar en las canillas de las ollas y en la serpentina. Si cada manguera tiene 1,5 metros ya debería alcanzar. Un poco más es mejor
  • Termómetro, densímetro y probeta.
  • Botellas, calculá 20 litros. Podés comprarlas, cartonearlas o usar las botellas de cerveza que tenés tiradas en tu casa. Si comprás, comprate las de 660cm^3.

Consumibles

  • Maltas, lúpulos y levadura. Lo más fácil es comprar un kit en minicervecería como éste. Es mejor si comprás las maltas molidas.
  • Tapas para botellas (una por botella :p).
  • Azúcar de maíz (si querés ahorrar, podés usar azúcar blanca común y sale también).
  • Alcohol (es para esterilizar cosas, no va directo en la cerveza).

Protocolo

En general no vas a tener todas las cosas que hacen falta para hacer cerveza las primeras veces. Si tenés amigos que tienen los elementos, lo que se acostumbra es que te los presten y que después como pago les regales algo de la cerveza que hiciste. Si estás leyendo esto y me conocés, puedo prestarte algunas cosas; pero prometé que me las vas a cuidar.

En próximos posts voy a explicar cómo hacer la cerveza, suscribite al feed de rss o pasá por acá de vez en cuando para ver cómo sigue,
Aureliano.

2012-05-24

Pseudo-terminales en python

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.

2012-05-23

Recordatorio para mi mismo,
Si quiero que sudo me pida el password de nuevo tengo que correr sudo -k.

Happy hacking,
Aureliano.

2012-04-23

Cambiando el certificado de SSL de un ELB

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.

2012-04-22

Bailé

Ayer bailamos con Ivana en "Flor de fiesta tanguera". Este es el video:

2012-04-19

Bailo


Bailo acá el sábado.

Los espero!

2012-04-08

Objetos en JS

Leyendo Hacker News me crucé una explicación re buena de cómo hacer objetos en JavaScript. Disfrútenla.

Happy hacking,
Aure.

2012-04-07

Problemas en mi red wifi

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

y ambas pueden ser pingueadas desde el gateway.
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
>
>

Pero no puedo hacer que se pingueen entre sí:
>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),

Mirando las rutas, no veo nada que me diga un problema:
>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

Se les ocurre cuál puede ser el problema?

2012-04-06

El modem wifi de ARNET

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:

Googleando un toque encontré acá que el usuario "admin" y password "alvlgeddl" les dan acceso a una bonita consola con comandos. Y si se sienten con ganas de usar un shell de Linux más normal tipean "sh" (sin las comillas) y van a la línea de comando.
Por último, también hay una interfaz administrativa escondida por http en http://10.0.0.2/admin.html que pueden usar.
Happy hacking,
Aure.

PD: En la consola, podés hacer "passwd usuario nuevo_password" y cambiar los passwords. Los posibles usuarios son: support, admin y user.
PD2: Obvio que los míos ya están cambiados ;).

2012-03-09

Jugando con el name mangling en python

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

Happy hacking,
Aure.