My projects website
I have uploaded some of my projects to dotsboxes.tk.
martes, 27 de enero de 2015
GopherGala 2015
Las publicaciones del resto de los participantes pueden verse acá: http://gopher-gala.challengepost.com/submissions
lunes, 19 de enero de 2015
Aprovechando los Makefiles
Al programar es común tener que correr programas que hagan ciertas tareas de forma rutinaria. Por ejemplo: compilar, formatear el código fuente, importar bibliotecas, correr un servidor, etc.
Al final uno termina usando la consola, pero ciertamente recordar todos los comandos puede ser dificil y aburrido.
Una solución sencilla que he encontrado es usar Makefiles. El comando make está disponible en todos los Linux, y nos permite correr diferentes comandos facilmente.
Por ejemplo, el siguiente Makefile es para una aplicación de Google App Engine, y me permite correr el servidor, importar las bibliotecas y generar las traducciones, todo con comandos simples:
GAESDK=/home/usuario/google_appengine
run:
$(GAESDK)/dev_appserver.py .
test:
nosetests --gae-sdk-path=$(GAESDK) --with-ferris app/tests
requirements:
pip install -r requirements.txt -t packages
i18n:
mkdir -p locale
pybabel extract -F babel.cfg -o locale/messages.pot ./
pybabel update -l en_US -d locale -i locale/messages.pot
pybabel update -l es_ES -d locale -i locale/messages.pot
pybabel compile -f -d locale
Posteriormente, para correr cada comando es necesario ejecutar una línea simple, fácil de recordar:
- Correr el servidor
make run- Correr las pruebas
make test- Descargar las bibliotecas
make requirements- Generar los archivos po
make i18n
Por supuesto, se pueden agregar muchos más comandos, según sea necesario.
martes, 10 de julio de 2012
Cómo guardar contraseñas
Espero que esto de algunas ideas para las personas que terminan implementando un sistema de estos, y sobre todo para no caer en errores simples (o no tanto).
Al principio... era el texto plano, y fue un horror
USUARIO: fulanito@example.com
CONTRASEÑA: ¡FraseSuperSecreta!
Cifrar las contraseñas (tampoco es tan seguro)
USUARIO: fulanito@example.com
CONTRASEÑA: 8cd93beb1fc767dbd98591d5582e4ba02f131e2462b53c92966270e5bf59d3a0
¡Cuidado con su función HASH!
Cifre sus contraseñas, añada sal al gusto y revuelva :)
CONTRASEÑA ORIGINAL: ¡FraseSuperSecreta!
SAL DEL SITIO: SOYSAL
HASH: 9b2d2085531f29fe009bf94d788bbc1af85d642e2285ee53ac1c1d5dbc467bacUtilizar la sal hará que sea necesario computar tablas rainbow para cada "sal" distinta, algo que ya no es muy deseable... Y si queremos complicar aún más la cuestión simplemente podemos volver a repetir el proceso varias veces (con o sin sal):
1: 9b2d2085531f29fe009bf94d788bbc1af85d642e2285ee53ac1c1d5dbc467bacComo se puede ver ya el proceso se volvería computacionalmente costoso, y esto es algo que aprovechan algoritmos como BCRYPT (utilizado por OpenBSD). En particular es mejor utilizar algo que sirva (como BCRYPT) el lugar de inventarnos nuestra propia receta para cocinar contraseñas.
2: d13b72194c638088e88e06c3f0e5599bc68d632ff731d0d0910628e81dfa0fd3
3: ee241c46e83757d66e6e372f0679f654ae0cd1983db527ffd9f56d7c211d5e3f
Consideraciones finales
- Contraseña debil: CASA (Palabra del diccionario. Además se puede adivinar en menos de 2^32 pasos)
- Otra contraseña debil: C@$@ (Se puede adivinar en menos de 2^32 pasos)
- Contraseña ¿fuerte?: e372f0679f654ae0cd1983db527ffd9f56d7c21 (FUERTE: ¿No es una frase? ¡No! ¡es porque es larga! Tiene 39 letras, se requerirían 2^312 pasos para adivinarla. DEBIL: ¿Usted se la podría aprender? Probablemente termine escribiéndola en un papel...)
- Contraseña realmente fuerte: Estaba-la-pájara-pinta-sentadita-en-su-verde-limón.-Pues-en-un-lugar-de-la-mancha-de-cuyo-nombre-no-quiero-acordarme-la-pájara-pinta-voló
lacucarachavoló1313¡quesusto!
Postdata
miércoles, 26 de agosto de 2009
Los Captcha
Recientemente muchos sitios web implementan algo conocido como captcha para evitar que robots hagan uso de los servicios que ofrecen. Todo muy bien. Evitan que los blogs se llenen de comentarios spam, evitan que robots creen cuentas o ingresen a sitios donde no deberían.
Pero lo más curioso que he visto son los captchas de Google. ¡Yo no puedo leer las letras! De hecho debo tratar varias veces antes de poder acertar las letras. Google debería tener una función de "el siguiente", pues esto dificulta la usabilidad de los sitios
Una solución mejor a los captchas me parece que sería usar captchas más sencillos que puedan ser facilmente por humanos (y quizá por robots) pero que tengan instrucciones como qué día es hoy, "dos más cuatro" o ¿de qué color son las letras a? o ordene de menor a mayor los números.
Estas alternativas son relativamente faciles de hacer, fáciles de ver por un humano pero muy dificiles de programar y en caso de que el robot logre "leer" las letras encima tendrá que adivinar qué le están pidiendo. Pero, deben ser cosas fáciles. Hay un sitio ruso en que el captcha es resolver una diferencial :S.
domingo, 26 de julio de 2009
Programando en Logo
Algunos no lo consideran muy útil, pero la verdad es que Logo es un lenguaje completo, que permite hacer muchas cosas con gran facilidad. Es ideal para niños, personas que quieren aprender a programar o simplemente para quien necesita hacer un prototipo rápido.
Por estas razones (y quizá también por otro proyecto, que creo que al final siempre utilizará QT… Nokia ganó >:-|) he comenzado Programando en Logo, que pretende mostrar aspectos de este lenguaje.
La dirección es:
domingo, 28 de septiembre de 2008
Crear Widgets en Scheme 2
La entrada anterior sobre como hacer widgets en Scheme no traía ningún ejemplo. Aquí pondré un ejemplo de como hacer el widget (con código). ¡Se trata de un widget que permite pintar en un canvas% !
(define canva-pintable%
(class canvas%
(init-field parent) ; el padre de este control
(init-field color) ; el color con el que dibujaré
(super-new (parent parent)(min-width 400)(min-height 400)(horiz-margin 2)(vert-margin 2)
(paint-callback (lambda (cnv dc)(void)))
(style '(control-border vscroll hscroll)))
(send (send this get-dc) set-pen color 1 'solid)
;recibe un mouse-event%
(define/override (on-event evento)
(cond ((send evento dragging?) (send (send this get-dc) draw-point (send evento get-x) (send evento get-y)))
)
)
(define/override (on-char evento)
(send (send this get-dc) clear)
)
)
) ;fin de mi widget
(define miVentana (new frame% (label "Dibujame!")))
(define miCanva (new canva-pintable% (parent miVentana)(color "black")))
(send miVentana show #t)
El programa final se vería algo así:
sábado, 27 de septiembre de 2008
Crear widgets en Dr. Scheme
Haciendo una progra en Dr Scheme (el administrador de álbumes para Ruidosa S.A.) quise usar una tabla para mostrar la información sobre los álbumes, etcétera. Investigando en la documentación descubrí la pavorosa noticia: ¡Mr. Ed NO tiene tablas!
Para solventar esto inicialmente usé varias list-box% pegadas, pero como el resultado es estéticamente feo (y quise agregar extras a la tabla) me decidí por implementar por completo mi propio widget.
Un "widget" en Scheme en realidad es una clase que extiende a otra clase que sí es un widget. Cuando hagamos nuestros widgets lo más probable es que extendamos alguna clase horizontal-panel%, vertical-panel%, o canvas%. También puede usar cualquier otro control si lo desea. La imagen es una captura de mi widget tabla. Esta permite añadir texto o imágenes a una columna, añadir filas, encabezado, cambiar el tamaño de las columnas y autoordenar por columna al hacer clic en el encabezado. Este una extensión de la clase canvas%.
Un widget tiene como ventaja que se puede programar una vez y usarse muchas veces, incluso en proyectos ajenos (obviamente si está bien diseñado). También se caracteriza porque cada instancia es independiente de las demás. Por ejemplo, podemos crear un widget formulario y los datos de cada formulario estarán aislados de los otros.
A por el código
El código propio del widget no es muy diferente a cualquier otro programa de Scheme. "Simplemente" hay que programar todo el comportamiento de este, que sucede cuando recibe el foco, cuando lo pierde, cuando recibe clics, teclasos, etc. La parte diferente viene acá:
(module advTable
mzscheme
(provide (all-defined))
(require (lib "mred.ss" "mred")
(lib "class.ss")
(file "sortCadenas.ss"))
(define advanced-list%
(class canvas%
(init-field parent)
(init-field callback)
(super-new (parent parent)(min-width 500)(horiz-margin 2)(vert-margin 2)
(paint-callback (lambda (cnv dc)(Redibujar cnv dc)))
(style '(control-border vscroll hscroll)))
;...
;el resto del código va aquí
;...
;hay que cerrar los paréntesis :)
- El "module advTable" indica que se desea crear un módulo, en este caso llamado advTable.
- La instrucción
(provide (all-defined))indica que el módulo expone al exterior todas las funciones definidas (esto tal vez no es algo deseado, pero esto lo programé en aquellos tiempos que...). - Luego vienen las instrucciones "require": las dos primeras aparentemente son necesarias, la última es de una clase auxiliar de mi programa.
- Luego viene la definición del widget propiamente dicha. En este caso la variable se llama advanced-list% (para seguir con los nombres de Dr. Scheme...). Como se ve el valor de la variable es una clase canvas%.
- Los init-field sirven para especificar valores a la hora de crear el widget en el programa (mas tarde hablaré de ellos).
- Para finalizar el super-new lo que hace es que instancia la clase padre del widget, en este caso un canvas%, de estos parámetros todos son los normales a la hora de crear un canvas% excepto quizá
(lambda (cnv dc)(Redibujar cnv dc)). Esta es una función que redibuja la canvas% y está dentro del widget. Quizá hayan notado que hay un(init-field parent)y un(parent parent); las palabras en rojo se refieren a la misma variable. - El canvas% tiene funciones propias, como
on-event,on-size, entre otras. Lo que debemos hacer para implementar nuestras funciones es suplantar estas funciones. Esto se hace definiendo la función con el mismo nombre, pero en lugar de usar undefinese escribedefine/override. Esto indicará a Scheme que se desea suplantar la función actual por esta. Es importante verificar que nuestra función tenga la misma sintaxis que la original.
Finalmente para poder usar nuestro widget en nuestro programa debemos el siguiente código al principio del programa:
(require (file "advTable.ss") ; así se llama nuestro archivo con el widget
;... otras bibliotecas que se requieran...
)
Y ya podemos usar nuestro widget como cualquier otro. Por ejemplo para crear una instancia de la tabla se usaría el siguiente código:
(define tbxRecorridos (new advanced-list%
(parent panRecorridos) ; formulario padre que contiene el widget
(callback recorridosCallback) ; función a la que se llamará
; cuando ocurra un evento
)
)
Nótese que "parent" y "callback" son los nombres especificados en los init-field del widget.