Showing posts with label programacion. Show all posts
Showing posts with label programacion. Show all posts

Tuesday, November 02, 2010

bug in wicket 1.4.12: AjaxButton does not update Panel models when opening a Modal Window

After a googling a bit about this bug, I couldn't find the written solution to this issue, described in this link:

http://apache-wicket.1842946.n4.nabble.com/Panel-not-refreshed-from-ModalWindow-via-Ajax-Button-td2235354.html

I didn't found this clearly specified in the wicket 1.4.13 changelog (that is why I'm posting this, so help fellow programmers googling the solution), but this issue is solved already. Just update to wicket 1.4.13.

Thursday, December 31, 2009

Rotar wallpapers en pocas lineas de Python


import os, random, shutil

dir = '/home/nicolas/wallpapers'
os.chdir(dir)
all_files = os.listdir(dir)
new_wall = all_files[random.randint(0, len(all_files))]
shutil.copyfile(new_wall, '/home/nicolas/.wallpaper.jpg')


Se explica solo, pero básicamente, elige un wallpaper al azar de la carpeta /home/nicolas/wallpapers y lo copia al archivo /home/nicolas/.wallpaper.jpg, entonces al setear este archivo como wallpaper cada vez que corremos el script lo hacemos rotar. yo lo tengo como un icono en el panel de Gnome para rotarlo cada vez que me aburre, y en el crontab para rotarlo cada una hora.

Sunday, December 13, 2009

Obteniendo información de la internéssss

Ok, les voy a comentar una hackeada que hice el otro día, y que más o menos funcionó. Tenía una lista de albumes musicales en una planilla de cálculo con una columna con el artista y el nombre. y quería agregarle el año. pero eran 100 discos y aunque más o menos me acordaba el año, no quería googlearlos todos. Entonces a modo de experimento (no sé si ahorré más tiempo la verdad pero fue más entretenido que hacer 100 google searches), se me ocurrió hacer un script que lo googleara por mí.

El primer paso fue googlear "google search cpan". CPAN es el repositorio de librerías Perl y hay para hacer cualquier pelotudez, así que supuse que habría una librería para buscar en google. Había una, pero leyendo un rato descubrí que necesité una clave de Google API que no sé que pija es, pero ya me pareció muy complicado, pero encontré que había una librería para buscar en Yahoo! que no requería nada. Así que eso usé. La librería se llama, sorprendentemente, "Yahoo::Search".

Y acá está la magia de CPAN, para instalar la librería en tu pc escribís

cpan Yahoo::Search


y se conecta a internet y baja la librería y todas las dependencias y las instala todas y ya está lista para usar.

Luego traté de armar una búsqueda que en el resumen de la búsqueda me trajera la fecha de publicación. Por ejemplo si escribo "Metallica Ride the lightning wikipedia released" obtengo un resumen como

Ride the Lightning is the second album by American heavy metal band Metallica, released on July 27, 1984 by Megaforce Records and re-released by Elektra ...

Como verán, ahí está el año en el que salió el disco. Entonces basandome en el código de ejemplo de búsqueda yahoo armé este script:


use Yahoo::Search;

$data_file="discos";
open(DAT, $data_file);
@discos=;
close(DAT);

for my $disco (@discos) {
my @Results = Yahoo::Search->Results(Doc => $disco . " wikipedia Released ",
AppId => "YahooDemo",
Mode => 'all', # all words
Start => 0,
Count => 1,
Type => 'any', # all types
AllowAdult => 0, # no porn, please
AllowSimilar => 0, # no dups, please
Language => undef,
);
warn $@ if $@; # report any errors

for my $Result (@Results)
{
printf "%s\n", $Result->Summary;
}
}


Lo que hice entonces fue por cada búsqueda, imprimir el "summary" que es justamente el resumen que aparece. Luego escribí este otro script en python (en python porque me pareció más simple que hacerlo en perl, porque no estoy totalmente cómodo con perl):


import sys

for line in sys.stdin:
try:
spl = line.upper().replace(":","").replace(",","").replace(".","").split()
i = spl.index('RELEASED') + 1
year = spl[i:i+3]
print max(int(y) for y in year if y.isdigit())
except Exception:
print ""


Que hace este script? lee linea a linea el standard output, lo pone en mayúsculas, remueve todos los ":", ".", y "," y luego busca donde diga "RELEASED" y busca todos los numeros que aparezcan a la derecha de RELEASED y obtiene el máximo de ellos. En general suele ser el año, los otros numeros son el mes y el día o algo así.

Entonces corrí


perl scriptperl.pl | python scriptpython.py > listayears


y obtuve la lista de años. Como cada script leyo una linea y escribió una linea, tengo una linea por disco en el mismo orden, así que pude copiar y pegar la lista de años. Obviamente no me trajo TODOS los años ni me trajo TODOS los años correctos (me trajo varios años de "re releases"), pero hice un par de busquedas similares (en vez de en wikipedia released también busqué en amazon y en rateyourmusic) y obtuve varios años, borré a mano todo lo que no encajaba y obtuve la lista de años. ¿Podría haberlo hecho con más precisión? Sí, pero no quería perder taaaanto tiempo. Pero quería que sirva como un burdo ejemplo de como cualquier boludo puede automatizar búsquedas en internet de info con una librería cualunque de CPAN.

Saturday, December 12, 2009

QWERTZ

Si estás en Austria y tenés un teclado QWERTZ (qwerty con Z e Y intercambiadas), usá este script:






Thursday, November 19, 2009

Algoritmos genéticos y Redes Neuronales

Solo quiero compartirles un link, muchachos.

Acá en esta página, en inglés, hay dos tutoriales muy simplecitos, uno de algoritmos genéticos y otro de redes neuronales:

http://www.ai-junkie.com/index.html

me parecieron muy fáciles de entender y directos. El de algoritmos genéticos viene con dos ejercicios como para practicar y experimentar un poco. El de Redes Neuronales viene con código de ejemplo, pero lo interesante es la explicación.

Sunday, November 08, 2009

Crear tu propia "alarmita" rapida en unix

Ok, debería estar estudiando, pero....
Ponía la pava para el mate, me iba a estudiar, y se me hervía el agua! siempre! entonces pensé esta solución: usar un programita en linux para que suene un "ring" después de N minutos.

El problema es que no lo encontré! pero hice el mio en un ratito! Así es como:
hice muchos comanditos

timbre: Lo ejecutás, y hace sonar un timbre
mplayer $HOME/timbre.wav
con-retardo: Llama a sleep, y luego ejecuta un comando pasado por parametro.
sleep $1
shift #shift remueve el primer argumento
$@

con-retardo-bg: Igual que con-retardo, pero lo hace en background.
nohup con-retardo $@ &

Con esos tres comandos alcanza para definir una alarma, "con-retardo-bg TIEMPO timbre" hace sonar una alarma transcurrido el tiempo TIEMPO. Y así defini el comando alarma.

pero yo quería un poquito más, poder hacer click en un icono, que se me abra una ventanita y me pregunte el tiempo, y luego se corra la alarma. Me hubiera bastado un programa que abra una ventana y lea un input y lo imprima por standard error, pero ese programa no existe, asi que defini estos otros comandos:


leer-y-ejecutar: Imprime el primer argumento, luego espera un input del usuario, y luego ejecuta el resto de los argumentos como si fuera un comando pero con el input del usuario al final. Algo así:

nicolas@desktop:~/bin$ leer-y-ejecutar "Ingrese un texto" echo aca se ve el texto lol:
Ingrese un texto
esto es un textoooooo
aca se ve el texto lol: esto es un textoooooo

Y lo definí así:
echo $1
read VAL # lee un valor y lo setea en la variable VAL
shift
$@ $VAL

alarma-window: Abre una terminal que me pregunta el tiempo, y luego ejecuta el programa alarma
gnome-terminal -x leer-y-ejecutar "Tiempo (segundos):" alarma
# abre una terminal que ejecuta el programa y después se cierra


Y eso es todo. puse alarma-window como un icono en mi panel de gnome y ya está, corre al toque!

Este es el código completo no resumido, si te interesa. Como alarma usé este bonito timbre: http://www.freesound.org/samplesViewSingle.php?id=9218

nicolas@desktop:~/bin$ cat timbre
#!/bin/sh
mplayer $HOME/timbre.wav
nicolas@desktop:~/bin$ cat con-retardo
#!/bin/sh
if [ $# -eq 0 ]; then
echo Uso: con-retardo SEGUNDOS-DE-RETARDO comando argumentos...
exit
fi

sleep $1
shift
$@
nicolas@desktop:~/bin$ cat con-retardo-bg
#!/bin/sh
if [ $# -eq 0 ]; then
echo Uso: con-retardo-bg TIEMPO-DE-RETARDO comando argumentos...
exit
fi
nohup con-retardo $@ &

nicolas@desktop:~/bin$ cat alarma
#!/bin/sh
if [ $# -ne 1 ]; then
echo uso: alarma SEGUNDOS
exit
fi

con-retardo-bg $1 timbre

nicolas@desktop:~/bin$ cat leer-y-ejecutar
#!/bin/sh
echo $1
read VAL
shift
$@ $VAL

nicolas@desktop:~/bin$ cat alarma-window
#!/bin/sh
gnome-terminal -x leer-y-ejecutar "Tiempo (segundos):" alarma

Tuesday, July 17, 2007

forth en lisp

estaba aburrido en mi clase de física y me puse a escribir algo que se me ocurrió el otro día: hacer que lisp pueda usarse tipo forth.

forth, por si no lo saben, es un lenguaje stack-based. podriamos decir que carece de sintaxis: es una sucesion de palabras que se lee de izquierda a derecha, y se comunican por una pila o stack. algo así:

2 3 + dup +

Las palabras son "2", "3", "+" y "dup".
"2" y "3" ponen, respectivamente un 2 y un 3 en la pila.
"+" toma los dos primeros elementos de la pila, los suma, y lo pone encima de la pila.
"dup" mira el primer elemento de la pila, y lo vuelve a poner encima de la pila.

El programa se ejecuta así

inicio -- pila: (vacía)
2 -- pila: 2
3 -- pila: 3 2
+ -- pila: 5
dup -- pila: 5 5
+ -- pila: 10

Este estilo de programacion carece de sintaxis, y es muy legible para algunos. Para mi es un quilombo, pero no importa, quise hacer un forth en lisp.

La idea es simple: represento la pila con una lista. Defino funciones comunes de lisp, que reciban la pila/lista, y devuelvan la lista modificada. Luego, para combinar las funciones, las compongo.

En realidad, forth y sus derivados suelen tener otra pila auxiliar, y aca no hay. Otra opcion sería usar dos pilas. En lugar de como hice acá, usar &rest y demases, quiza convenga pasar la lista como un parametro cualquiera, y direcamente pasamos dos listas, o hacer alguna tramoya rara con connect (se podria hacer).

La idea aqui presentada podria expandirse, pero francamente no tengo ganas.

El codigo:

(defun dup (f &rest rest)
    (cons f (cons f rest)))
(defun swap (a b &rest rest)
    (cons b (cons a rest)))
(defun fdrop (a &rest rest)
    rest)
(defmacro if0 (test &body b)
    `(if (= ,test 0) ,@b))
(defun fconnect (f &rest list)
    (if0 (length list)
        f
        (lcompose (apply #'fconnect list) f)))
(defun lcompose (f g)
    (lambda (&rest args)
        (apply f (apply g args))))
        
(defmacro lisp-forth (lispf forthf comb length)
    `(defun ,forthf (&rest list)
        (,comb (apply #',lispf 
                (
take ,length list)) 
                  (drop ,length list))))
(defun take (len list)
    (loop for i from 1 to len
          for e in list
          collect e))
(defun drop (len list)
    (if0 len
         list
         (drop (- len 1) (cdr list))))

(defmacro connect (&rest list)
    `(fconnect ,@(mapcar #'asfunction list)))

(defun asfunction (e)
    (cond ((symbolp e) `(function ,e))
          ((or (numberp e) (eq (car e) 'quote)) 
                `(push-identity ,e))))
(defun push-identity  (e)
    (lambda (&rest list) (cons e list)))
          
(defmacro define-forth (f &rest definition)
    `(defun ,f (&rest args)
        (apply (connect ,@definition) args)))
        
(lisp-forth + f+ cons 2)
(lisp-forth - f- cons 2)
(define-forth lolfun dup f+ 2 f+ 3 swap f-)

(defun lolfun2 (n) ((+ n n 2) 3))

explico rápidamente que hace cada cosa:

dup, swap, y fdrop, hacen lo mismo que en forth.
if0 es una simple comparacion con 0 que uso a veces.
fconnect es una funcion que recibe una lista de funciones estilo forth, y las compone recursivamente. lcompose es como una composicion de funciones normal, pero la diferencia es que lo que devuelve la segunda funcion no es el parametro unico de la primera funcion, sino que es aplicado (funcall vs. apply).

lisp-forth es una macro para definir funciones estilo forth a partir de funciones lisp. damos el nombre de la funcion lisp, el nombre de la funcion que queremos definir, con que vamos a combinar el resultado de la funcion comun con el resultado de la pila, y cuantos elementos de la pila le vamos a pasar como parametro.

connect es una macro que agrega los #' a las funciones y cambia los numeros y cosas quoteadas (simbolos, listas, etc) por funciones que colocan esos objetos en la pila (funciones armadas con push-identity), mediante la funcion asfunction (asfunction podria tener mas opciones pero por ahora, esas).

define-forth es, finalmente, lo que nos permite armar funciones tipo forth en base a otras funciones tipo forth.

espero que les haya gustado, mis dos o tres lectores que seguramente no saben lisp y no van a entender este post (posible excepcion: CC)!

Sunday, July 15, 2007

reduce, foldl, inject, accum, etcetera

Guido Van Rossum, el diseñador de Python, dice que no le gusta la funcion reduce, tambien conocida como foldl, inject o accum. Le parece complicada, y dice que cada vez que la ve haciendo algo mas o menos complicado, tiene que agarrar lapiz y papel para darse cuenta de lo que esta haciendo.

Francamente no entiendo por que, ya que es una funcion sencilla, solo hay que encararla correctamente. Así que, voy a explicarles como usar reduce, así ya se disipa el misticismo.

En primer lugar, vamos a definir reduce. Voy a usar una sintaxis tipo javascript, que es como la de C. Alcanza con que sepan lo siguiente de la sintaxis, que lo diferencia de C, Java, C# y demases: Primero, que no hay tipos en las variables.

function (arg1, arg2, ...) { declaraciones } en javascript.

Aunque ausente de muchos lenguajes como Java o C++, en lenguajes como Python, Ruby, Lisp, Haskell, Smalltalk, Javascript, etc; las funciones son valores como cualquier otro, se pueden asignar a variables, pasar como parametros, devolverse, etc. Toda funcion que reciba una funcion por parametro o devuelva una funcion se llama "funcion de orden superior". Entonces

function (x) { return x + x; }

es una funcion dado un valor, devuelve el doble. Aclaro que cuando en javascript ponemos

function nombre (x) { etc... }

escribir eso en javascript es equivalente a escribir

var nombre = function (x) { etc...}

Vamos a definir reduce, sin más. Reduce recibe tres argumentos, un valor inicial "vi", una funcion "f", y una lista/vector/coleccion/etc "lista". La funcion "f" recibe dos valores, un valor acumulado y un elemento de la lista "lista", y devuelve otro valor. reduce aplica la "f" al primer elemento de la lista, pasandole como valor acumulado el valor inicial "vi". Lo que devuelve "f" se convierte en el nuevo valor acumulado, y asi hasta pasar por todos los elementos de la lista.

algo así:


function reduce(vi,f,lista)
{
for(var i = 0, var accum = vi; i < lista.length; i++)
{
accum = f(accum, lista[i]);
}
return accum;
}



Entonces, veamos que hace esta funcion, graficamente hablando:



Entonces, podemos ver, suponiendo que lista tenga los elementos 1, 2 y 3.

reduce llama a la funcion, totalAcumulado vale el valor inicial, 0, y elem, 1. La funcion devuelve la suma de 0 + 1, entonces la funcion devuelve 1. Este valor pasa a ser el nuevo totalAcumulado. Ahora, reduce llama a la funcion de nuevo, pero ahora, totalAcumulado vale 1, y elem vale 2. La funcion devuelve la suma de los elementos, entonces totalAcumulado pasa a ser 3 y elem pasa a ser 3, y la suma devuelve 9. como no hay mas elementos en la lista, reduce devuelve 6, que es la sumatoria de todos los elementos de la lista.

Expresado en una tablita:



como podemos ver, lo que devuelve la funcion pasa a ser el nuevo total acumulado.

Por cierto, aca podemos ver cierta recursividad, fijense como podemos decir que el resultado de la funcion pasa a ser el nuevo valor inicial. Una definicion recursiva de reduce vendria a ser:

function reduce(vi, f, lista)
{
if(lista.length == 0) return vi;
return reduce(f(vi, first(lista)), rest(lista));
}


donde first(lista) devuelve el primer elemento de la lista, y rest(lista) devuelve una nueva lista sin el primer elemento.

si tantos parentesis les marean, veanlo de vuelta así

function reduce(vi, f, lista)
{
/* si la lista esta vacía, devuelvo vi */
if(lista.length == 0) return vi;
/* primer elemento de la lista */
var pri = first(lista);
/* primer elemento de la lista */
var resto = rest(lista);
/* nuevo valor inicial, vi es el total acumulado, pri es el valor de la lista */
var nuevoVI = f(vi, pri);
return reduce(nuevoVI, f, resto);
}

repitiendo el ejemplo de antes, estamos diciendo que (imaginemos por un momento que javascript tiene una sintaxis para las listas/vectores del tipo [elemento1, elemento2, elemento3, ...]:

var f = function (totalAcumulado, elem) { return totalAcumulado + elem; };
reduce(0, f, [1,2,3]);

devuelve

reduce(f(0,1), f, [2,3]);

(y como f(0,1) = 1, devuelve)

reduce(f(1,2), f, [3]);

(y como f(1,2) = 3, devuelve)

reduce(f(3,3), f, []);

(y como f(3,3) = 6, y la lista esta vacia, devuelve el valor inicial, que es 6).

En general, cada ves que vemos

reduce(vi, function(total, elem) { return expresion }, lista)

podemos suponerlo aproximadamente equivalente a

total = vi;
for(elem in lista)
{
    total = expresion;
}
return total;


resumiendo este embole, es claro ver que hay una redundacia de elementos al escribir el algoritmo entero. Realmente se gana claridad por sobre reduce?

Por ultimo, y ya que guido van rossum dice que todo uso de reduce mas alla de reduce(0, +, listaDeNumeros) o reduce(1, *, listaDeNumeros) es complicado, piensen que hacen estas funciones

reduce(-1, function(total, elem) { return total > elem ? total : elem; }, listaDeNumeros);

reduce(0, function(total, elem) { return total + elem.length; }, listaDeStrings);

(recuerden que aca "total" se refiere no al total completo, sino el total computado hasta el momento).

Wednesday, June 20, 2007

I HERD YOU LIEK HUNGARIAN

En una suerte de break de la tematica general del blog (?), voy a hablar un poquito de programación.

Básicamente, un tal Joel Spolsky publicó, hace unos 2 años, un articulo llamado Making Wrong Code Look Wrong, ubicado en la dirección http://www.joelonsoftware.com/articles/Wrong.html. Lo que Spolsky sugiere es usar convenciones de codigo para detectar errores más visualmente. Les recomiendo que lean el articulo, cuenta algo interesante sobre el verdadero origen de la nunca bien ponderada notación húngara.
En fin, en caso de que no tengan ganas de leerlo (tl;dr), Spolsky presenta como caso de ejemplo la de proteccion contra scripts en apliaciones web. Si uno, por ejemplo, en un foro, permite el posteo directo de tags html, puede incluirse cualquier codigo de tipo javascript, e incurrir en fallas de seguridad. Entonces propone la utilización de prefijos para diferenciar entre strings seguras de ser posteadas como parte de la página y otras que no, para poder detectar visualmente, que cada vez que uno escribe algo como:

Write usName

uno sabe que esta mal, puesto que "us" significa unsafe, o sea estamos escribiendo una string no segura.

El artículo recibió sus alabos, pero también sus criticas. La principal es que idealmente uno tendria que utilizar un sistema de tipeo más estático y poderoso, que permita distinguir entre cadenas seguras e inseguras y de error de compilacion al intentar postear una cadena insegura.

Ok, esto es cierto. Pero no hace falta tener un sistema de tipeo tan poderoso. La primer solucion sería encerrar las strings inseguras en otro tipo, por ejemplo, en este javascript (lenguaje puesto puramente de ejemplo

javascript Unsafe(s)
{
this.unsafeString = s;
}

entonces, cuando quiero acceder a la string que Unsafe recubre, hago

anUnsafe.unsafeString

y consigo la string. Entonces, toda actividad que requiera postear una string va a fallar con este objeto. El problema de esta solucion es que es muy incomoda. Si quiero sumar dos strings que son unsafe, tengo que hacer algo como

Unsafe(s1.unsafeString + s2.unsafeString)

Incomodo. Una solucion permitida por el sistema prototipico de javascript es la siguiente:

function markSafe(s)
{
s.isSafeString = true;
return s;
}

s sigue siendo una string, y sigue sirviendo para todo lo demas. Toda funcion de escritura no la llamás directamente, sino que haces algo como

function safeWrite(s)
{
if(s.isSafeString == true)
Write(s);
else
BOOOOOOMSDFBHDFSDFDFSDF, o bien,
Write(Encode(s));
}

Esto es un ejemplo de javascript, o sea, probablemente si uno no usa alguna suerte de server side javascript, que es raro, esto no aplica . Si no podemos agregar a las strings fields nuevos, podemos tener una suerte de tabla donde guardamos las safe strings, y despues testeamos si existe esa string en la tabla, y listo (no es lo mas optimo, pero bueno)!

En cualquier caso, si uno se equivoca, va a haber un error visible, no una falla de seguridad. Es mejor un error visible y que la aplicacion no ande que un error visible en el codigo al que uno se acostumbra a no cometer, porque uno siempre los comete.
En fin este fue mi primera blogueada de programación, espero que les haya gustado :nivelx: