Willyfroghttp://blog.willyfrog.es/nadaird@willyfrog.esWillyfrogtag:blog.willyfrog.es,2011-06-11:/atom/http://blog.willyfrog.es/favicon.icohttp://blog.willyfrog.es/feed-logo.png2014-05-23T18:26:00Zacrylamidinterrupt.eltag:blog.willyfrog.es,2014-05-23:/2014/interrupt-el2014-05-23T18:26:00ZWillyfroghttp://blog.willyfrog.es/nadaird@willyfrog.es<p>Pues poco a poco he seguido aprendiendo <a class="reference external" href="http://www.gnu.org/software/emacs/">Emacs</a>, diversos sabores de lisp (ninguno a fondo aun) y entre ellos bastante elisp. La cosa es que cada dia disfruto más con Emacs y cada vez estoy mas enredado con él. Hasta el punto que empiezo a desarrollar pequeñas utilidades para mi día a día.</p>
<p>Y de ahí este post, recientemente en mi trabajo tengo la necesidad de mantener un log de las interrupciones sufridas a lo largo de una jornada de trabajo. Es algo que no debería necesitar, pero la freecuencia es elevada y el equipo ha visto la necesidad de hacer algo así. Como cada cual usamos un editor distinto y es algo extraoficial, no hay un metodo común, asi que cada cual se ha buscado las castañas.</p>
<p>En mi caso, como queria aprender <a class="reference external" href="http://orgmode.org/">org-mode</a>, empecé con un fichero donde iba anotando las interrupciones. Una interrupcion: un elemento en la lista, añadia la fecha y marcaba mediante tags al <em>interruptor</em>. En unos dias resultaba un tanto tedioso hacer todo esto, por lo que me pareció el momento perfecto para intentar usar un poco <em>elisp-fu</em> y de ahi surgio <a class="reference external" href="https://github.com/Willyfrog/interrupt.el">interrupt.el</a></p>
<p>Asi que ahora simplemente pulsando <F12> puedo añadir el nombre de quien me interrumpa, ir a ver qué necesita la persona y cuando vuelva tendré el cursor esperando para añadir el motivo. Como extra, puedo pulsar despues <S-F12> y además apuntará la cantidad de minutos que he estado durante la interrupcion.</p>
<p>Desde luego aun está en sus primeras versiones, pero ya hace mucho más de lo que pensaba poner en un principio asi que ya veremos como continua.</p>
Configuracion encriptada en Emacstag:blog.willyfrog.es,2013-10-28:/2013/configuracion-encriptada-en-emacs2013-10-28T15:52:00ZWillyfroghttp://blog.willyfrog.es/nadaird@willyfrog.es<p>En mi aprendizaje de Emacs he descubierto el módulo <a class="reference external" href="http://sf.net/p/emacs-jabber">jabber.el</a> que te permite
mantener las conversaciones de Google Talk dentro del propio editor. Pero
hay que pasarle las contraseñas o guardarlas en modo plano, lo cual es algo
incomodo desde el punto de vista de la seguridad. Si bien para la cuenta del
trabajo me daria igual ya que no usa la autenticación de dos factores y por lo
tanto me se de memoria mi contraseña, en la personal si lo tengo habilitado y
la desconozco y aunque la conociera, seria poco afortunado guardarla como texto
plano.</p>
<p>Por ello, buscando un poco he encontrado como cifrar un fichero <em>.el</em> y la
verdad es que es tremendamente sencillo. Para empezar hay que habilitar la
extensión <em>.el.gpg</em> por lo que incluimos en nuestro .emacs:</p>
<pre class="brush: elisp">
(add-to-list 'load-suffixes ".el.gpg")
</pre>
<p>A partir de aqui, solo hay que crear un fichero con dicha extensión y Emacs
sabrá que hacer ;) Cada vez que guardes, te pedirá la contraseña con la que
debe cifrar el contenido.</p>
<p>Y ya se puede incluir el fichero con</p>
<pre class="brush: elisp">
(require 'fichero-cifrado)
</pre>
<p>con lo que puedes usar lo que haya dentro en el resto del editor.</p>
Mi primera utilidad de elisptag:blog.willyfrog.es,2013-08-28:/2013/mi-primera-utilidad-de-elisp2013-08-28T09:49:00ZWillyfroghttp://blog.willyfrog.es/nadaird@willyfrog.es<p>Desde hace algún tiempo me pasé a <a class="reference external" href="http://www.gnu.org/software/emacs/">Emacs</a>, si bien la versatilidad ya la tenía en vim (es un gran editor) con Emacs puedo además aprovechar para aprender un sabor de lisp: <a class="reference external" href="http://en.wikipedia.org/wiki/Emacs_Lisp">emacs lisp</a> (<em>elisp</em> para abreviar). Esta es una tarea que imagino que me llevará años ya que no es un uso intensivo, sino que intentaré ir haciendo pequeñas funciones y cambios que me permitan aprovechar esa caracteristica tan genial de Emacs de ser programable.</p>
<p>Lo difícil es encontrar algo que hacer, por lo que lo primero que se me ha ocurrido es algo que ya he tenido que hacer varias veces: cerrar todos los buffers de un proyecto. Estoy seguro que si lo busco, encuentro que alguien ya lo ha hecho y mucho mejor que yo, pero si no voy haciendo pequeñas funciones, no creo que aprenda en la vida.</p>
<div class="highlight"><pre><span class="lineno"> 1</span> (defun filter-buffers-by-file-name (partial-path)
<span class="lineno"> 2</span> "return list of buffers which contains 'partial-path'"
<span class="lineno"> 3</span> (remove-if (lambda (x) (or (null (buffer-file-name x))
<span class="lineno"> 4</span> (null (string-match partial-path (buffer-file-name x))))) (buffer-list)))
<span class="lineno"> 5</span>
<span class="lineno"> 6</span> (defun kill-project-buffers (partial-path)
<span class="lineno"> 7</span> "kills all buffers which contains partial-path"
<span class="lineno"> 8</span> (interactive "sPartial name:")
<span class="lineno"> 9</span> (let ((kill-list (filter-buffers-by-file-name partial-path)))
<span class="lineno">10</span> (if (null kill-list)
<span class="lineno">11</span> (message (format "No buffers matched '%s'" partial-path))
<span class="lineno">12</span> (if (y-or-n-p (format "killing %d buffers" (length kill-list)))
<span class="lineno">13</span> (kill-some-buffers kill-list)
<span class="lineno">14</span> (message ("User cancelled"))
<span class="lineno">15</span> )
<span class="lineno">16</span> )))
</pre></div>
<p>Si bien estoy seguro de que se puede hacer mejor, esta es mi segunda aproximación (la original daba mas vueltas a los datos para conseguir lo mismo) que funciona. Lo que hace es buscar entre los buffers que han sido cargados desde un fichero aquellos que contengan en su path el texto indicado, teniendo en cuenta que puede usarse expresiones regulares. De esta manera poniendo el nombre del proyecto (o parte de su path), eliminará los buffers que coincidan.</p>
<p>La última versión de esta funcion, podrá encontrarse siempre en <a class="reference external" href="https://github.com/Willyfrog/vimfiles/tree/master/emacs_custom">github</a></p>
Auriculares para correr miomundotag:blog.willyfrog.es,2013-08-27:/2013/auriculares-para-correr-miomundo2013-08-27T09:39:00ZWillyfroghttp://blog.willyfrog.es/nadaird@willyfrog.es<p>Recientemente he comprado unos <a class="reference external" href="http://www.amazon.es/gp/product/B00D5SRJDA/ref=oh_details_o00_s00_i00?ie=UTF8&psc=1">auriculares</a> ligeros para correr. Esto no debería ser un motivo de entrada para un blog, ¿no? pero me ha llamado la atención el poco cuidado de los detalles que han tenido hasta el punto de que debe haberles perjudicado gravemente a las ventas.</p>
<p>Pero antes de nada decir que me han costado 12 €, por lo que no espero un producto de grandes acabados ni que la calidad de sus graves sea superior. Cuando decidí comprarlos fue porque no queria dejarme mucho dinero en un producto que no se si lo usaré muy a menudo, ya que depende de cuanto continue corriendo. Pero para lo que me ha costado, por ahora estoy contento. Sirve justo para lo que lo quiero, para poner la musica del movil y que no se me caigan los cascos mientras corro, asi que por esa parte me parece genial.</p>
<p>El problema que les he visto es que el "manual" de instrucciones (si se le puede llamar así a cuatro parrafos en la cara posterior del envoltorio) es para un producto similar pero sustancialmente diferente. Hasta el punto de que he estado a punto de devolverlo al no ser capaz de enlazar los cascos con el bluetooth del movil. Finalmente, por cabezonería he encontrado la manera: "mantener pulsado boton de play hasta que parpadee de continuo mientras el móvil busca dispositivos". Pero creo que mucha gente puede haber devuelto el producto por no tener un minimo de detalle y haber puesto la caratula apropiada.</p>
Traduccion elisp en 15 minutos (aprox.)tag:blog.willyfrog.es,2013-08-06:/2013/traduccion-elisp-en-15-minutos-aprox2013-08-06T08:17:00ZWillyfroghttp://blog.willyfrog.es/nadaird@willyfrog.es<p>El otro dia vi un tutorial sencillo y rapido para aprender <a class="reference external" href="http://bzg.fr/learn-emacs-lisp-in-15-minutes.html">emacs lisp</a>, me pareció una introducción muy necesaria para la gente que (como yo) está aprendiendo <a class="reference external" href="http://www.gnu.org/s/emacs/">Emacs</a>. Más que nada porque aprender Emacs y no aprender como funciona elisp es perder el tiempo. ¡Ojo! esto no quiere decir que sea necesario tener la capacidad de escribir grandes y complicados programas en él, sino simplemente ser capaz de leerlo y entender por donde van los tiros. Y es que su propia configuración está escrita en elisp, por lo que si no lo entiendes, dependes del resto para poder configurar tu editor.</p>
<p>En fin, que me gustó lo suficiente como para dedicar un par de horas y hacer un <em>pull request</em> a <a class="reference external" href="https://twitter.com/adambard">adambard</a> y su <a class="reference external" href="http://learnxinyminutes.com/">learnXinYminutes</a> traduciendolo.</p>
<p>El resultado lo podeis ver <a class="reference external" href="http://learnxinyminutes.com/docs/es-es/elisp-es/">aqui</a> y si veis un fallo podeis bien <a class="reference external" href="https://github.com/adambard/learnxinyminutes-docs">corregirlo</a> o avisarme y me encargo yo.</p>
Movimiento estáticotag:blog.willyfrog.es,2013-06-24:/2013/movimiento-estatico2013-06-23T23:22:00ZWillyfroghttp://blog.willyfrog.es/nadaird@willyfrog.es<p>Finalmente he movido el blog de <a class="reference external" href="http://wordpress.com">Wordpress</a> a algo estático, como llevaba queriendo hacer desde hace tiempo. Wordpress no tiene nada malo, me sigue pareciendo una plataforma de blog muy buena, especialmente para gente que no quiera complicarse la vida.</p>
<p>Pero (y si no hubiera un pero, seria que me gusta mover por mover) requiere ser activo, cosa que no me pasa con el blog, que durante un tiempo escribo y durante un tiempo dejo de escribir, alternandose ambos a lo largo del tiempo. Y wordpress, siendo dinamico, con php y mysql, require de mimo, cuidado y mantenimiento para evitar que alguien utilize algun exploit, andar con temas de antispam, etc.</p>
<p>Resultado, he eliminado los comentarios, he migrado todo de mi <a class="reference external" href="http://blog.willinux.net">antiguo blog</a> y he pasado parte de las vacaciones aprendiendo como funciona acrylamid (toma nombrecito) para ajustarlo a mis necesidades.</p>
<p>Además, si alguien me seguia, verá que ahora estreno dominio. Voy a dejar willinux por éste por el que me siento algo más identificado.</p>
<p>Por ultimo, si te interesa como está montado el blog, está todo el <a class="reference external" href="https://github.com/Willyfrog/blog">código en github</a>.</p>
Cargando modulos dinámicamente en la botellatag:blog.willyfrog.es,2012-11-04:/2012/cargando-modulos-dinamicamente-en-la-botella2012-11-04T09:42:00ZWillyfroghttp://blog.willyfrog.es/nadaird@willyfrog.es<p>Estoy algo liado montando una api para un pequeño proyecto mio, buscando
que sea lo más cercano a RESTFUL por motivos laborales y por aprender
cosas nuevas (entremedias estoy probando Emacs, que me esta costando un
rato el cambio desde Vim).</p>
<p>Como framework estoy usando <a class="reference external" href="http://bottlepy.org/">bottle</a>, ya que siempre estoy usando
Flask y quería probar otro distinto a ver qué tal. Y más adelante
intentaré montarlo de manera asíncrona, pero eso para más adelante.</p>
<p>Como digo, es una primera aproximación, imagino que el código final
tendrá una pinta muy diferente, pero para alguien que quiera cargar
dinámicamente los módulos y tratar de ejecutar las funciones es un buen
punto de partida.</p>
<div class="highlight"><pre><span class="lineno"> 1</span> <span class="nd">@route</span><span class="p">(</span><span class="s">'/:module/:action'</span><span class="p">)</span> <span class="c"># las rutas dinámicas están compuestas de la forma modulo/función</span>
<span class="lineno"> 2</span> <span class="k">def</span> <span class="nf">run_action</span><span class="p">(</span><span class="n">module</span><span class="p">,</span><span class="n">action</span><span class="p">):</span>
<span class="lineno"> 3</span> <span class="k">try</span><span class="p">:</span>
<span class="lineno"> 4</span> <span class="n">m</span> <span class="o">=</span> <span class="n">import_module</span><span class="p">(</span><span class="n">module</span><span class="p">)</span>
<span class="lineno"> 5</span> <span class="k">except</span> <span class="ne">ImportError</span><span class="p">:</span>
<span class="lineno"> 6</span> <span class="n">redirect</span><span class="p">(</span><span class="s">'/404'</span><span class="p">)</span>
<span class="lineno"> 7</span> <span class="n">action_call</span> <span class="o">=</span> <span class="n">module</span> <span class="o">+</span> <span class="s">'_'</span> <span class="o">+</span> <span class="n">action</span>
<span class="lineno"> 8</span> <span class="c"># para evitar que cualquier función del modulo pueda ser llamada, solo aquellos que comienzan por el nombre del modulo pueden ser invocados</span>
<span class="lineno"> 9</span> <span class="k">try</span><span class="p">:</span>
<span class="lineno">10</span> <span class="n">a</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">m</span><span class="p">,</span> <span class="n">action_call</span><span class="p">)</span>
<span class="lineno">11</span> <span class="k">except</span> <span class="ne">AttributeError</span><span class="p">,</span> <span class="n">e</span><span class="p">:</span> <span class="c"># diferencia entre fallo por modulo o accion</span>
<span class="lineno">12</span> <span class="k">print</span> <span class="s">"ERROR: module </span><span class="si">%s</span><span class="s"> doesn't have a </span><span class="si">%s</span><span class="s"> function"</span> <span class="o">%</span> <span class="p">(</span><span class="n">module</span><span class="p">,</span> <span class="n">action_call</span><span class="p">)</span>
<span class="lineno">13</span> <span class="k">print</span> <span class="s">"ERROR: </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="n">e</span>
<span class="lineno">14</span> <span class="n">redirect</span><span class="p">(</span><span class="s">'/400'</span><span class="p">)</span>
<span class="lineno">15</span> <span class="k">return</span> <span class="n">a</span><span class="p">()</span>
</pre></div>
<p>A este código habría que añadir el paso de parámetros, así como si hay
diferenciación por método (get, post, put o delete)</p>
Des/activando virtualenv automaticamentetag:blog.willyfrog.es,2012-08-01:/2012/desactivando-virtualenv-automaticamente2012-08-01T13:05:00ZWillyfroghttp://blog.willyfrog.es/nadaird@willyfrog.es<p>Algo que no se me habia ocurrido hasta que mi compañero me lo comentó
es la activación automática del entorno virtualenv nada más entrar en el
propio directorio, de esta manera ahorramos tiempo y problemas de no
estar en el virtualenv apropiado.</p>
<p>Buscando un poco por la red, encontré este <a class="reference external" href="https://gist.github.com/2198913">gist</a> donde hacía parte
de lo que queria, ya que no terminaba el virtualenv al abandonar el
directorio, por lo que podria dar problemas al seguir en la misma linea
de comandos y ejecutar otras cosas. De ahí que modificara el script para
que al abandonar el directorio desactivara el entorno.</p>
<p>Para poder utilizarlo se puede poner el entorno en .venv en el
directorio o crear un enlace simbolico (llamado igualmente .venv) si
queremos tenerlo en otro lado. El script debe incluirse en .bashrc y ya
solo falta cerrar e iniciar sesión.</p>
<p>El script en cuestión está en un <a class="reference external" href="https://gist.github.com/3226639">fork del enlazado anteriormente</a>.</p>
Receta para introspeccion en pythontag:blog.willyfrog.es,2012-06-15:/2012/receta-para-introspeccion-en-python2012-06-15T08:43:00ZWillyfroghttp://blog.willyfrog.es/nadaird@willyfrog.es<p>Al final no me ha servido ya que hay varias propiedades que no son
legibles en el codigo legacy que estoy mirando, pero por si a alguien le
sirviera copio una receta vista en <a class="reference external" href="http://stackoverflow.com/questions/1006169/how-do-i-look-inside-a-python-object">SO</a> para ver los contenidos de un
objeto:</p>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name"/>
<col class="field-body"/>
<tbody valign="top">
<tr class="field"><th class="field-name">Original:</th><td class="field-body"><a class="reference external" href="http://diveintopython.net/">diveintopython</a></td>
</tr>
<tr class="field"><th class="field-name">Author:</th><td class="field-body">Mark Pilgrim (<a class="reference external" href="http://blog.willyfrog.es/2012/receta-para-introspeccion-en-python/mailto:mark@diveintopython.org">mark@diveintopython.org</a>)</td>
</tr>
</tbody>
</table>
<div class="highlight"><pre><span class="k">def</span> <span class="nf">info</span><span class="p">(</span><span class="nb">object</span><span class="p">,</span> <span class="n">spacing</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">collapse</span><span class="o">=</span><span class="mi">1</span><span class="p">):</span>
<span class="sd">"""</span>
<span class="sd"> Print methods and doc strings.</span>
<span class="sd"> Takes module, class, list, dictionary, or string.</span>
<span class="sd"> """</span>
<span class="n">methodList</span> <span class="o">=</span> <span class="p">[</span><span class="n">e</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="nb">dir</span><span class="p">(</span><span class="nb">object</span><span class="p">)</span> <span class="k">if</span> <span class="nb">callable</span><span class="p">(</span><span class="nb">getattr</span><span class="p">(</span><span class="nb">object</span><span class="p">,</span> <span class="n">e</span><span class="p">))]</span>
<span class="n">processFunc</span> <span class="o">=</span> <span class="n">collapse</span> <span class="ow">and</span> <span class="p">(</span><span class="k">lambda</span> <span class="n">s</span><span class="p">:</span> <span class="s">" "</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">s</span><span class="o">.</span><span class="n">split</span><span class="p">()))</span> <span class="ow">or</span> <span class="p">(</span><span class="n">lambdas</span><span class="p">:</span> <span class="n">s</span><span class="p">)</span>
<span class="k">print</span> <span class="s">"</span><span class="se">\\</span><span class="s">n"</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="s">"</span><span class="si">%s</span><span class="s"> </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span>
<span class="p">(</span><span class="n">method</span><span class="o">.</span><span class="n">ljust</span><span class="p">(</span><span class="n">spacing</span><span class="p">),</span>
<span class="n">processFunc</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="nb">getattr</span><span class="p">(</span><span class="nb">object</span><span class="p">,</span> <span class="n">method</span><span class="p">)</span><span class="o">.</span>\<span class="n">_</span>\<span class="n">_doc</span>\<span class="n">_</span>\<span class="n">_</span><span class="p">)))</span>
<span class="k">for</span> <span class="n">method</span> <span class="ow">in</span> <span class="n">methodList</span><span class="p">])</span>
<span class="k">if</span> <span class="n">name</span> <span class="o">==</span> <span class="s">"main"</span><span class="p">:</span>
<span class="k">print</span> <span class="n">help</span><span class="o">.</span><span class="n">doc</span>
</pre></div>
<p>En parte no lo uso por como está estructurado el codigo este que
tenemos, de hecho finalmente una variación más sencilla y peor
formateada me sirvió para lo que queria:</p>
<div class="highlight"><pre><span class="n">lista_negra</span> <span class="o">=</span> <span class="p">[</span><span class="s">'atributos problematicos aqui'</span><span class="p">]</span>
<span class="n">logWARN</span><span class="p">(</span><span class="s">"</span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="p">[</span><span class="s">"</span><span class="si">%s</span><span class="s">: </span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="p">(</span><span class="n">val</span><span class="p">,</span> <span class="nb">getattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">val</span><span class="p">,</span> <span class="s">"No legible"</span><span class="p">))</span> <span class="k">for</span> <span class="n">val</span> <span class="ow">in</span> <span class="nb">dir</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="k">if</span> <span class="n">val</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">lista_negra</span><span class="p">])</span><span class="sb">``</span>
</pre></div>
<p>la lista negra es porque en este trozo de codigo concreto hay muchos
'alias' de funcion y al solicitar su valor ejecuta la funcion la cual ni
siquiera esta en el contexto apropiado. Supongo que es lo que tiene que
el objeto contenga unos 600 valores entre atributos, métodos y alias
T_T</p>
Pyweek 2012tag:blog.willyfrog.es,2012-05-28:/2012/pyweek2012-05-28T10:58:00ZWillyfroghttp://blog.willyfrog.es/nadaird@willyfrog.es<p>Despues del "subidon" con ludum dare, me atreví a meterme en pyweek.</p>
<p>No ha sido tan excitante en algunos aspectos, ya que tenia mucho más
tiempo y eso provocó el "luego lo hago". La mayor parte del tiempo se me
fue en pequeños errores (alguno de los cuales aun siguen existiendo) en
el tema de colisiones. En general los consejos y criticas son los que yo
mismo pensaba cuando subí la versión final.</p>
<p>Quizás me planteo para más adelante recuperar la idea y hacerlo de nuevo
con otro engine... pero eso es hablar del futuro.</p>
<p><a class="reference external" href="http://pyweek.org/e/bot_uprising/">Mi participación en el pyweek</a></p>
Ludum daredtag:blog.willyfrog.es,2012-04-23:/2012/ludum-dared2012-04-23T09:37:00ZWillyfroghttp://blog.willyfrog.es/nadaird@willyfrog.es<p>Este fin de semana me he dado un homenaje tremendamente geek: he
participado en un gamejam (<a class="reference external" href="http://www.gamejam.es/">explicacion en castellano</a>) de 48 horas, en
concreto el <a class="reference external" href="http://www.ludumdare.com/compo/">ludum dare</a> en su 23ª edición. Las reglas son sencillas:
dado un tema tienes 48 horas para hacer un juego completo tú solo
(incluye código, animaciones, sonido, etc.)</p>
<p>No he podido entregar al final del concurso, aunque ciertamente no
esperaba hacerlo. Este fin de semana he tenido varios compromisos que no
me iban a permitir sacar el máximo de horas para el evento, pero estoy
contento de tener algo jugable</p>
<p>Una de las cosas que me ha permitido el ir tan relajado es el probar
Scala como lenguaje de programación utilizando Slick2D como framework y
la verdad es que ha sido muy cómodo. El mayor problema que he tenido es
el no poder generar un .jar ejecutable para poder hacer la entrega. De
haber usado Scala antes, eso lo tendría solucionado y es algo que espero
hacer en un futuro cercano. Además, como algo insólito en mi, he
desarrollado desde windows ya que el stack de Scala es muy cómodo de
instalar y quería probarlo, además de facilitarme el hecho de usar otras
herramientas de edición de imágenes (pyxeledit) que no tienen versión
Linux (no desde que Adobe retiró Air para Linux).</p>
<p>La toma de decisiones es una de las cosas que más me ha fascinado. Con
la continua falta de tiempo todo es una decisión a tomar en el momento,
si pospones la decisión es algo que no harás. Y quizás debería haber
llevado una lista más completa de cosas que quería/debería hacer durante
el concurso. En ocasiones me daba cuenta de que algo importante lo había
desplazado por otra tarea por no haberme acordado de ella. La
refactorización y el eliminar código para rehacer algo ha sido contínuo.</p>
<p>Por ultimo: el código y assets están disponibles en mi <a class="reference external" href="https://github.com/Willyfrog/tinygod">github</a> Hasta
que consiga generar un ejecutable hace falta scala + sbt y ejecutarlo
desde ahí.</p>
<p>La duda que me queda es: ¿lo continuaré en las próximas semanas?</p>
Nuevo mini-proyecto: tuitorrenttag:blog.willyfrog.es,2012-04-10:/2012/nuevo-mini-proyecto-tuitorrent2012-04-10T07:49:00ZWillyfroghttp://blog.willyfrog.es/nadaird@willyfrog.es<p>En estos días, he intentado sacar algo de tiempo para un mini-proyecto
que tenía en mente desde hace mucho y que recordé hace poco gracias a un
artículo: <a class="reference external" href="http://inventwithpython.com/blog/2012/03/25/how-to-code-a-twitter-bot-in-python-on-dreamhost/">"Como crear un bot de Twitter en Python"</a> (titulo traducido
libremente).</p>
<p>La idea es la de un bot de twitter al que mandarle torrents y que este
se encargue de gestionarlos. Por ahora solo descarga el torrent y lo
coloca en una carpeta, la cual está vigilada por utorrent que al
detectar el nuevo archivo lo pone a la cola. Como efecto extra, también
descarga archivos que no sean torrent, pero en este caso no se añaden a
la lista y se quedan ahí.</p>
<p>El <a class="reference external" href="https://github.com/Willyfrog/tuitorrent">proyecto está alojado en github</a> bajo una licencia BSD de 3
clausulas (que podeis trastear con él todo lo que queráis mientras
sigáis diciendo de donde salio ;) ). Esto me recuerda que tambien tengo
que añadir la licencia al proyecto :P</p>
<p>Los requisitos que tiene son pocos por ahora: Python 2.X (solo he
probado con la 2.7) y python-twitter</p>
<p>Por ahora está en una versión muy primaria (alfa que se suele decir),
por lo que tiene varios problemas:</p>
<blockquote>
<ul class="simple">
<li>la instalación es más complicada de lo que me gustaría. Aunque he</li>
</ul>
</blockquote>
<div class="system-message">
<p class="system-message-title">System Message: WARNING/2 (<tt class="docutils"><string></tt>, line 25)</p>
Block quote ends without a blank line; unexpected unindent.</div>
<p>puesto un shell script, hay que asegurarse de al menos tener python y
virtualenv, cosa no siempre disponible (para windows ni siquiera he
intentado automatizarlo). Además requiere generar un token de oauth en
twitter y darle las claves al bot, para que pueda leer y escribir de la
cuenta.</p>
<blockquote>
<ul class="simple">
<li>la ejecución requiere pasos poco necesarios fuera de un entorno de</li>
</ul>
</blockquote>
<div class="system-message">
<p class="system-message-title">System Message: WARNING/2 (<tt class="docutils"><string></tt>, line 32)</p>
Block quote ends without a blank line; unexpected unindent.</div>
<p>desarrollo. Cuando desarrollo con python uso virtualenv para abstraer el
uso de librerías del resto de la máquina, esto hace que hay que activar
el entorno previamente a lanzar el cliente.</p>
<blockquote>
<ul class="simple">
<li>python-twitter tiene un problema con la codificación de caracteres</li>
</ul>
</blockquote>
<div class="system-message">
<p class="system-message-title">System Message: WARNING/2 (<tt class="docutils"><string></tt>, line 37)</p>
Block quote ends without a blank line; unexpected unindent.</div>
<p>que he arrastrado y espero solucionar en algún momento, ya que justo en
mac es donde me ha sucedido, aunque espero arreglarlo esta tarde/noche.</p>
<p>De cara a un futuro, me gustaría por un lado facilitar el uso e
instalación del bot y por otro, montarle un pequeño sistema de plugins
de manera que pueda realizar más acciones que solo descarga de archivos
y quizás filtrar los tipos de archivos descargables o una lista blanca
de quien descargar.</p>
Curva de Hilbert en un 'tuit'tag:blog.willyfrog.es,2012-03-14:/2012/curva-de-hilbert-en-un-tuit2012-03-14T15:33:00ZWillyfroghttp://blog.willyfrog.es/nadaird@willyfrog.es<p>Actualmente estoy mirando implementaciones de las curvas de <a class="reference external" href="http://es.wikipedia.org/wiki/Curva_de_Peano">Peano</a> y
<a class="reference external" href="http://es.wikipedia.org/wiki/Curva_de_Hilbert">Hilbert</a> y me he encontrado en la <a class="reference external" href="http://comments.gmane.org/gmane.org.user-groups.python.argentina/43309">lista de python-argentina</a> con una
curiosa implementación de una curva de Hilbert en un tweet (es decir en
140 caracteres o menos):</p>
<div class="highlight"><pre><span class="lineno">1</span> <span class="kn">from</span> <span class="nn">turtle</span> <span class="kn">import</span> <span class="o">*</span>
<span class="lineno">2</span> <span class="n">l</span><span class="o">=</span><span class="n">left</span>
<span class="lineno">3</span> <span class="n">f</span><span class="o">=</span><span class="n">forward</span>
<span class="lineno">4</span> <span class="k">def</span> <span class="nf">h</span><span class="p">(</span><span class="n">n</span><span class="p">,</span><span class="n">a</span><span class="p">):</span>
<span class="lineno">5</span> <span class="k">if</span> <span class="n">n</span><span class="p">:</span><span class="n">n</span><span class="o">-=</span><span class="mi">1</span><span class="p">;</span><span class="n">l</span><span class="p">(</span><span class="n">a</span><span class="o">*</span><span class="mi">3</span><span class="p">);</span><span class="n">h</span><span class="p">(</span><span class="n">n</span><span class="p">,</span><span class="o">-</span><span class="n">a</span><span class="p">);</span><span class="n">f</span><span class="p">(</span><span class="mi">4</span><span class="p">);</span><span class="n">l</span><span class="p">(</span><span class="n">a</span><span class="p">);</span><span class="n">h</span><span class="p">(</span><span class="n">n</span><span class="p">,</span><span class="n">a</span><span class="p">);</span><span class="n">f</span><span class="p">(</span><span class="mi">4</span><span class="p">);</span><span class="n">h</span><span class="p">(</span><span class="n">n</span><span class="p">,</span><span class="n">a</span><span class="p">);</span><span class="n">l</span><span class="p">(</span><span class="n">a</span><span class="p">);</span><span class="n">f</span><span class="p">(</span><span class="mi">4</span><span class="p">);</span><span class="n">h</span><span class="p">(</span><span class="n">n</span><span class="p">,</span><span class="o">-</span><span class="n">a</span><span class="p">);</span><span class="n">l</span><span class="p">(</span><span class="n">a</span><span class="o">*</span><span class="mi">3</span><span class="p">)</span>
<span class="lineno">6</span> <span class="n">h</span><span class="p">(</span><span class="mi">6</span><span class="p">,</span><span class="mi">90</span><span class="p">)</span>
</pre></div>
<p>Además no conocía el módulo de la tortuga</p>
Snipet: Generador de etiquetastag:blog.willyfrog.es,2012-03-01:/2012/snipet-generador-de-etiquetas2012-03-01T21:49:00ZWillyfroghttp://blog.willyfrog.es/nadaird@willyfrog.es<p>Para poder generar automaticamente etiquetas para nodos (aunque valdria
para cualquier otra cosa) he hecho un generador automatico sencillo que
va dando strings de texto:</p>
<div class="highlight"><pre><span class="k">def</span> <span class="nf">generador_etiquetas</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">'''genera etiquetas,primero minusculas, luego mayusculas y finalmente</span>
<span class="sd"> digitos'''</span>
<span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">string</span><span class="o">.</span><span class="n">lowercase</span><span class="p">:</span>
<span class="k">yield</span> <span class="n">a</span>
<span class="k">for</span> <span class="n">A</span> <span class="ow">in</span> <span class="n">string</span><span class="o">.</span><span class="n">uppercase</span><span class="p">:</span> <span class="c">#cuando termina con las minusculas, pasa a las</span>
<span class="c"># mayusculas</span>
<span class="k">yield</span> <span class="n">A</span>
<span class="n">n</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">while</span> <span class="mi">1</span><span class="p">:</span>
<span class="n">n</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">yield</span> <span class="nb">str</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>
</pre></div>
<p>El while 1 en vez de while True, es porque al parecer es ligeramente más
rapido (imagino que por alguna optimización del compilador del
interprete)</p>
Si un paper fuera un lenguaje de programaciontag:blog.willyfrog.es,2012-02-14:/2012/si-un-paper-fuera-un-lenguaje-de-programacion2012-02-14T08:55:00ZWillyfroghttp://blog.willyfrog.es/nadaird@willyfrog.es<p>Quizás por verme cercano al momento PFC he encontrado este cómic bastante gracioso:
<img alt="if term papers were programming languages" src="http://www.somethingofthatilk.com/comics/135.jpg"/>
Una traducción rápida después del salto
Fuente: <a class="reference external" href="http://www.somethingofthatilk.com/index.php?id=135">Something of that ilk</a></p>
<p><strong>Python</strong>: Esto es plagio. No puedes hacer "import ensayo" y
quedarte tan tranquilo.</p>
<p><strong>Java</strong>: Llevo leídas dos páginas y aun no tengo ni idea de lo que
estás hablando.</p>
<p><strong>Ensamblador</strong>: ¿De verdad tenías que redefinir cada palabra del
español?</p>
<p><strong>C</strong>: Esta muy bien, pero se te olvidó añadir la terminación en null
y ahora solo estoy leyendo basura.</p>
<p><strong>C++</strong>: Te pedí una copia, no cuatrocientas.</p>
<p><strong>Shell</strong>: No tengo permiso para leer esto</p>
<p><strong>Latex</strong>: Tu trabajo no tienen ningún sentido, pero es la cosa más
bonita que he visto.</p>
<p><strong>HTML</strong>: Esto es una maceta.</p>
¿Censura o hactivismo?tag:blog.willyfrog.es,2012-01-27:/2012/censura-o-hactivismo2012-01-27T17:54:00ZWillyfroghttp://blog.willyfrog.es/nadaird@willyfrog.es<p>Hoy, dia ocupado como pocos en el trabajo (pero de eso igual hago otra
entrada), me sorprendian un monton de tuits hablando de censura, cosa
que no entendia y me comenzaba a temer una nueva vuelta de tuerca (a
mucho peor) de la conocida "Ley de Sinde". Pero no, era el anuncio por
parte de <a class="reference external" href="http://twitter.com">Twitter</a> acerca de su <a class="reference external" href="http://www.genbeta.com/redes-sociales/twitter-censurara-tweets-de-acuerdo-a-la-legislacion-de-cada-pais">nueva politica</a>. En resumidas cuentas
viene a decir que en base a legislación y bajo peticion expresa de una
entidad competente (entiendo que es alguien designado por el gobierno)
no serán visibles los tuits que incumplan algun tipo de ley (y en
ocasiones cuestiones morales/culturales).</p>
<p>Esto, me ha hecho pensar y mucho en lo que estaba poniendo la gente,
sobre como se acababa el mundo, que si a mi no me censura nadie, que
menuda mierda de red, etc. Y cada vez lo entendía menos. Quizás lo que
mas me ha hecho pensar es la opinion generalizada de que twitter se
habia acabado como herramienta de coordinación de movimientos
activistas, especialmente explicada en los medios más tradicionales
(periodicos y webs de noticias que necesitan tiempo antes de dar una
noticia... hum, competencia de twitter, diria)</p>
<p>Pero lo cierto es que yo lo estoy viendo de otra manera, como una
herramienta más potente de cara al hacktivismo: ahora un chino podría
escribir tranquilamente en formato de 140 caracteres sin el temor a que
sus vecinos o amigos le denuncien a un regimen, porque su tuit será
borrado de su alrededor y sin embargo será accesible al resto del mundo,
poniendo de relieve situaciones que se conocen vagamente por el miedo a
las consecuencias. Y donde digo un chino, digo un cubano o tantos otros
bajo politicas donde la libertad de expresión no es un derecho.</p>
<p>Y sigo pensando que seguirá siendo una herramienta magnifica de
organización, porque para bloquear un "trending topic" primero habrá
tenido que serlo (me acojonaré si empezamos con los precons de minority
report, pero mientras tanto...) y una vez ha sido TT las formas de
organización ya no pasan por tuits sino por multiples medios (IM,
noticias, webs, foros, de palabra, etc.)</p>
<p>Mientras no haya un chivatazo por parte de Twitter a las autoridades de
turno, creo que aplaudiré este paso y su conversión a una mejor
herramienta de hacktivismo.</p>
<p>Y de paso mencionar otro <a class="reference external" href="http://gallir.wordpress.com/2012/01/27/la-masa-enfurecida-ahora-contra-twitter/">post interesante</a> de Ricardo Galli (creador
de meneame) que ademas me ha puesto en marcha para escribir este.</p>
Acortador de urls terminadotag:blog.willyfrog.es,2012-01-26:/2012/acortador-de-urls-terminado2012-01-26T14:15:00ZWillyfroghttp://blog.willyfrog.es/nadaird@willyfrog.es<p>He terminado (alcanzado el estado de 1.0) mi pequeño proyecto de
<a class="reference external" href="https://bitbucket.org/Willyfrog/misurl/">acortador de urls</a>, no pretende ser útil en el mundo real, pero si
quizás sirva como punto de partida para otros en caso de querer ver un
ejemplo de flask+redis+sqlalchemy.</p>
<p>La motivación principal, es una entrega para la facultad, pero he
aprovechado para aprender un par de cosas y puede que acabe usándola
para dar una charla introductoria en <a class="reference external" href="http://codemotion.es/">codemotion</a>.</p>
<p>Está bajo licencia <a class="reference external" href="http://en.wikipedia.org/wiki/BSD_licenses#3-clause_license_.28.22New_BSD_License.22_or_.22Modified_BSD_License.22.29">BSD (3 clausulas)</a>, por lo que podeis hacer casi
cualquier cosa con ella ;)</p>
<p>Una última cosa, está pensada para trabajar con postgresql, pero
cambiando la configuración de la bb.dd. debería poder adaptarse a otras
bases de datos SQL</p>
Recomendacion de libro para aprender haskelltag:blog.willyfrog.es,2012-01-23:/2012/recomendacion-de-libro-para-aprender-haskell2012-01-23T07:34:00ZWillyfroghttp://blog.willyfrog.es/nadaird@willyfrog.es<p>Si estás necesitado de aprender Haskell a marchas forzadas este fin de
semana me ayudó mucho el libro: <a class="reference external" href="http://learnyouahaskell.com">learn you a haskell for greater good</a>.
Y si lo prefieres en castellano está traducido en <a class="reference external" href="http://aprendehaskell.es/">Aprende Haskell</a> (si
pongo los dos es porque al parecer la traducción es muy reciente y esta
en proceso de revisión). Bastante conciso y la mayoría de los conceptos
(si no eres nuevo completamente en programación funcional) se cogen
rápido con la excepción quizás de los functores y las mónadas.</p>
<p>Realmente útil para iniciarse en ese complejo mundo que es Haskell.
Seguramente acabe cogiendome la versión en papel de amazon</p>
Calculo de numeros primostag:blog.willyfrog.es,2012-01-10:/2012/calculo-de-numeros-primos2012-01-10T07:55:00ZWillyfroghttp://blog.willyfrog.es/nadaird@willyfrog.es<p>En un problema que resolvi recientemente en el proyecto euler, descubrí
un algoritmo sencillo para calcular numeros primos: la <a class="reference external" href="http://es.wikipedia.org/wiki/Criba_de_Erat%C3%B3stenes">criba de
eratóstenes</a> El cual inicialmente traduje a python como:</p>
<div class="highlight"><pre><span class="lineno">1</span> <span class="k">def</span> <span class="nf">eratostenes</span><span class="p">(</span><span class="n">m</span><span class="p">):</span>
<span class="lineno">2</span> <span class="n">primos</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="n">m</span><span class="o">+</span><span class="mi">1</span><span class="p">))</span>
<span class="lineno">3</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">xrange</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="nb">int</span><span class="p">(</span><span class="n">sqrt</span><span class="p">(</span><span class="n">m</span><span class="p">))</span><span class="o">+</span><span class="mi">1</span><span class="p">):</span>
<span class="lineno">4</span> <span class="k">if</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">primos</span><span class="p">:</span>
<span class="lineno">5</span> <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">xrange</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="n">m</span><span class="o">/</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">):</span>
<span class="lineno">6</span> <span class="n">primos</span><span class="o">.</span><span class="n">discard</span><span class="p">(</span><span class="n">i</span><span class="o">*</span><span class="n">j</span><span class="p">)</span>
<span class="lineno">7</span>
<span class="lineno">8</span> <span class="k">return</span> <span class="n">primos</span>
</pre></div>
<p>No comento el código por ser una transcripción directa del algoritmo
enlazado, asi que si no entiendes como funciona, mejor leer el articulo
de la <a class="reference external" href="http://es.wikipedia.org/wiki/Criba_de_Erat%C3%B3stenes">wikipedia</a>.</p>
<p>El problema de esta solución es que para números grandes, el conjunto
inicial es muy grande y se crea nada mas empezar, por lo que en caso de
no tener memoria suficiente pasará lo que tiene que pasar cuando el 99%
de las aplicaciones están en la <a class="reference external" href="http://es.wikipedia.org/wiki/Espacio_de_intercambio">partición de swap</a>.</p>
<p>Por ello, cree una modificación del algoritmo de eratóstenes, para
continuar un set de primos dado:</p>
<div class="highlight"><pre><span class="k">def</span> <span class="nf">erato_follow</span><span class="p">(</span><span class="n">m</span><span class="p">,</span><span class="n">primes</span><span class="p">):</span>
<span class="sd">'''</span>
<span class="sd"> m - nuevo numero tope</span>
<span class="sd"> primes - antiguo set de numeros primos</span>
<span class="sd"> '''</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">primes</span><span class="p">:</span> <span class="c">#si se ha llamado sin pasar un set antiguo</span>
<span class="c"># se trabaja como siempre</span>
<span class="n">pl</span> <span class="o">=</span> <span class="n">eratostenes</span><span class="p">(</span><span class="n">m</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">pl</span> <span class="o">=</span> <span class="n">primes</span>
<span class="n">np</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="nb">max</span><span class="p">(</span><span class="n">pl</span><span class="p">),</span><span class="n">m</span><span class="p">))</span> <span class="c">#nuevos primos</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">xrange</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="nb">int</span><span class="p">(</span><span class="n">sqrt</span><span class="p">(</span><span class="n">m</span><span class="p">))</span><span class="o">+</span><span class="mi">1</span><span class="p">):</span>
<span class="k">if</span> <span class="n">i</span> <span class="o"><</span> <span class="nb">max</span><span class="p">(</span><span class="n">pl</span><span class="p">):</span> <span class="c">#aprovechamos lo aprendido</span>
<span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">xrange</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="n">m</span><span class="o">/</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">):</span>
<span class="n">np</span><span class="o">.</span><span class="n">discard</span><span class="p">(</span><span class="n">i</span><span class="o">*</span><span class="n">j</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span> <span class="c">#sacamos los que quedan</span>
<span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">xrange</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="n">m</span><span class="o">/</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">):</span>
<span class="n">np</span><span class="o">.</span><span class="n">discard</span><span class="p">(</span><span class="n">i</span><span class="o">*</span><span class="n">j</span><span class="p">)</span>
<span class="k">return</span> <span class="n">pl</span> <span class="o">|</span> <span class="n">np</span> <span class="c"># union de ambos</span>
</pre></div>
<p>mediante esta funcion, podemos seguir aumentando el numero de primos en
incrementos manejables, si bien habrá que tener cuidado con el set
completo ya que al final acabará creciendo por encima de la memoria
disponible.</p>
El arbol de navidad de QBerttag:blog.willyfrog.es,2011-12-23:/2011/el-arbol-de-navidad-de-qbert2011-12-23T09:43:00ZWillyfroghttp://blog.willyfrog.es/nadaird@willyfrog.es<p>En el <a class="reference external" href="http://www.pythonweekly.com/">weekly python newsletter</a>, enlazaban al problema de sacar la
suma máxima, dado un árbol y utilizando el movimiento del clásico
videojuego <a class="reference external" href="http://en.wikipedia.org/wiki/Qbert">qBert</a> (no del todo cierto porque qBert sí podía subir,
pero eso son tecnicismos). El árbol en concreto sería así:</p>
<div class="highlight"><pre><span class="n">chrismasTree</span> <span class="o">=</span> <span class="p">[</span>
<span class="p">[</span><span class="mi">75</span><span class="p">],</span>
<span class="p">[</span><span class="mi">95</span><span class="p">,</span><span class="mi">64</span><span class="p">],</span>
<span class="p">[</span><span class="mi">17</span><span class="p">,</span><span class="mi">47</span><span class="p">,</span><span class="mi">82</span><span class="p">],</span>
<span class="p">[</span><span class="mi">18</span><span class="p">,</span><span class="mi">35</span><span class="p">,</span><span class="mi">87</span><span class="p">,</span><span class="mi">10</span><span class="p">],</span>
<span class="p">[</span><span class="mi">20</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span><span class="mi">82</span><span class="p">,</span><span class="mi">47</span><span class="p">,</span><span class="mi">65</span><span class="p">],</span>
<span class="p">[</span><span class="mi">19</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span><span class="mi">23</span><span class="p">,</span><span class="mi">75</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span><span class="mi">34</span><span class="p">]</span>
<span class="p">]</span>
</pre></div>
<p>Y las reglas son que qBert siempre debe bajar por el árbol, bien hacia
un lado o el otro.</p>
<p>Dado el pequeño número de datos, se puede hacer una aproximación por
fuerza bruta (recorriendo todos los posibles caminos y comparándolos)
pero esta solución sería malísima si cambiamos el set de datos al
proporcionado por el <a class="reference external" href="http://projecteuler.net">proyecto euler</a> en su <a class="reference external" href="http://projecteuler.net/problem=67">problema 67</a>, que
aseguran que si pudieras comprobar 10⁷ rutas por segundo, tadarías 20
billones americanos (millardos por aquí) de años en resolverlo.</p>
<p>El código para generar este segundo árbol, sería:</p>
<div class="highlight"><pre><span class="n">tri</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">peUrl</span> <span class="o">=</span> <span class="s">"http://projecteuler.net/project/triangle.txt"</span>
<span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">urllib</span><span class="o">.</span><span class="n">urlopen</span><span class="p">(</span><span class="n">peUrl</span><span class="p">)</span><span class="o">.</span><span class="n">readlines</span><span class="p">():</span>
<span class="n">tri</span><span class="o">.</span><span class="n">append</span><span class="p">([</span><span class="nb">int</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">line</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">" "</span><span class="p">)])</span>
<span class="k">print</span> <span class="n">qbertRun</span><span class="p">(</span><span class="n">tri</span><span class="p">)</span>
</pre></div>
<p>Y por si quieres intentar resolverlo, no pondré mi solución hasta
después de "Leer mas".</p>
<p><strong>Solucion:</strong>
La parte crítica de la solución está en la siguiente función:</p>
<div class="highlight"><pre><span class="k">def</span> <span class="nf">solve_line</span><span class="p">(</span><span class="n">curr</span><span class="p">,</span> <span class="n">prev</span><span class="p">):</span>
<span class="sd">"""</span>
<span class="sd"> dadas 2 lineas, hacemos una nueva con cada elemento</span>
<span class="sd"> max(curr[i]+prev[i],curr[i]+prev[i+1])</span>
<span class="sd"> """</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">prev</span><span class="p">:</span>
<span class="n">res</span><span class="o">=</span><span class="n">curr</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">res</span><span class="o">=</span><span class="p">[</span><span class="nb">max</span><span class="p">(</span><span class="n">prev</span><span class="p">[</span><span class="n">i</span><span class="p">],</span><span class="n">prev</span><span class="p">[</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">])</span><span class="o">+</span><span class="n">curr</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">curr</span><span class="p">))]</span>
<span class="k">return</span> <span class="n">res</span>
</pre></div>
<p>Es decir, tomamos el árbol de navidad como un <a class="reference external" href="http://es.wikipedia.org/wiki/%C3%81rbol_binario">árbol binario</a> y
sumamos a cada línea el máximo de los dos caminos posibles.</p>
<p>Esto en realidad, nos daría un resultado incorrecto si lo aplicaramos
de arriba a abajo, ya que se iria por el primer resultado gordo que
hubiera, pero si invertimos el arbol y empezamos por el lado ancho, lo
que hace es recortar los caminos, dejando cada vez el camino mayor. Por
ello, la funcion que tratará los datos, lo primero que hace es invertir
la lista:</p>
<div class="highlight"><pre><span class="k">def</span> <span class="nf">qbert</span><span class="p">(</span><span class="n">arbol</span><span class="p">):</span>
<span class="sd">"""</span>
<span class="sd"> dada una lista en forma de arbol (ver variable tree) resolver</span>
<span class="sd"> la suma maxima pudiendo solo bajar bien a izda. o dcha.</span>
<span class="sd"> """</span>
<span class="n">arbol</span><span class="o">.</span><span class="n">reverse</span><span class="p">()</span> <span class="c">#invertimos la lista</span>
<span class="n">res</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">l</span> <span class="ow">in</span> <span class="n">arbol</span><span class="p">:</span>
<span class="n">res</span> <span class="o">=</span> <span class="n">solve_line</span><span class="p">(</span><span class="n">l</span><span class="p">,</span><span class="n">res</span><span class="p">)</span>
<span class="k">return</span> <span class="n">res</span>
</pre></div>
Salpimentar al gusto la contraseñatag:blog.willyfrog.es,2011-12-09:/2011/salpimentar-al-gusto-la-contrasena2011-12-09T11:14:00ZWillyfroghttp://blog.willyfrog.es/nadaird@willyfrog.es<p>Actualmente estoy trabajando en un prototipo de aplicación bastante
sencillo, pero que requiere que aprenda bastantes cosas (y por lo tanto
voy algo lento). Uno de los pequeños problemas con los que me enfrenté
fue la creación de un sistema de usuarios y no quería dejar el
<em>password</em> en abierto en la base de datos aun cuando solo fuera a
utilizarlo yo.</p>
<p>Echando un ojo al módulo <a class="reference external" href="http://docs.python.org/library/crypt.html">crypt</a> de <em>Python</em>, requería un poco de
<a class="reference external" href="http://en.wikipedia.org/wiki/Salt_%28cryptography%29">sal</a>, por lo que me vi de repente con que no quería meter la sal ni en
un fichero de configuración ni obviamente en el código fuente. Por lo
que finalmente decidí que la sal iba a ser parte del login y de ahí
sacar todo. Así para comprobar la clave únicamente hago:</p>
<div class="highlight"><pre><span class="kn">from</span> <span class="nn">crypt</span> <span class="kn">import</span> <span class="n">crypt</span>
<span class="k">def</span> <span class="nf">auth</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">clave</span><span class="p">):</span>
<span class="sd">'''Comprueba si la clave suministrada es la del usuario'''</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">password</span> <span class="o">==</span> <span class="n">crypt</span><span class="p">(</span><span class="n">clave</span><span class="p">,</span><span class="bp">self</span><span class="o">.</span><span class="n">username</span><span class="p">[:</span><span class="mi">2</span><span class="p">])</span>
</pre></div>
<p>El motivo de usar 2 caracteres es únicamente debido a los ejemplos que
vi de uso de <em>crypt</em>, imagino que se podrían más caracteres, pero no me
pareció necesario.</p>
<p>Si acaso, mi mayor problema con esta implementación es que la sal se
vuelve conocida con solo leer el código y no se si a partir de ahí y con
la clave encriptada se podría sacar la clave en plano. Por ahora y para
la demo, esto me sirve y más adelante estudiaré mejores sistemas de
encriptación y almacenado.</p>
<p>Mientras tanto, lo publico por si a alguien le viene bien.</p>
<p>Ah, decir además que esto lo uso mezclado con el decorator que
sugieren en un <a class="reference external" href="http://flask.pocoo.org/snippets/8/">snippet</a> de <a class="reference external" href="http://flask.pocoo.org">Flask</a>, pero obviamente cambiando la
manera de acceso.</p>
Peores momentos de programartag:blog.willyfrog.es,2011-11-28:/2011/peores-momentos-de-programar2011-11-28T11:19:00ZWillyfroghttp://blog.willyfrog.es/nadaird@willyfrog.es<p>Ultimamente he sufrido las dos cosas que mas me molestan al programar
(provocadas por mi, claro está)</p>
<ul class="simple">
<li>una es la búsqueda de un error en el sitio incorrecto. El log de error</li>
</ul>
<div class="system-message">
<p class="system-message-title">System Message: WARNING/2 (<tt class="docutils"><string></tt>, line 5)</p>
Bullet list ends without a blank line; unexpected unindent.</div>
<p>no deja claro o puede llevar a error y te tiras un par de días buscando
un error en el sitio equivocado.</p>
<ul class="simple">
<li>en el proceso de aprendizaje de una librería, descubrir que algo lo</li>
</ul>
<div class="system-message">
<p class="system-message-title">System Message: WARNING/2 (<tt class="docutils"><string></tt>, line 9)</p>
Bullet list ends without a blank line; unexpected unindent.</div>
<p>entendiste mal</p>
<p>Estoy seguro de que hay más cosas que me molesten, pero esas dos suelen
aparecer antes o después. Si me acuerdo ya pondré mas, porque por ahora
parece una excusa promocional para stackoverflow :)</p>
Más recursos para leer de pythontag:blog.willyfrog.es,2011-11-16:/2011/mas-recursos-para-leer-de-python2011-11-16T07:23:00ZWillyfroghttp://blog.willyfrog.es/nadaird@willyfrog.es<p>Esta mañana he encontrado un <a class="reference external" href="http://jessenoller.com/good-to-great-python-reads/">enlace recopilatorio</a> de lecturas sobre
python, cubriendo un buen montón de temas. Algunos de los mencionados ya
los <a class="reference external" href="http://blog.willyfrog.es/2011/recursos-de-python">nombré hace poco</a>.</p>
<p>Intentaré actualizar este post segun vaya leyendo algunos de esos
artículos si merecen algún tipo de reseña especial.</p>
Música en una línea de codigo, versión Pythontag:blog.willyfrog.es,2011-11-15:/2011/musica-en-una-linea-de-codigo-version-python2011-11-15T15:25:00ZWillyfroghttp://blog.willyfrog.es/nadaird@willyfrog.es<p>El otro día vi en reddit <a class="reference external" href="http://www.reddit.com/r/programming/comments/mbakl/experimental_oneline_algorithmic_music/">algunos</a> <a class="reference external" href="http://xiatek.org/?p=296">temas</a> en los cuales se creaba
música a partir de una línea de código (en realidad algo mas, pero la
parte importante estaba solo en una) y como curiosidad personal, decidí
hacer una versión serpentina de dicho programa, una vez conseguido
(fácil, rápido y feo) quise poner un poco mas interés y utilizar
funciones lambda y generadores. El resultado es el siguiente:</p>
<div class="highlight"><pre><span class="c">#redirigir el output a /dev/audio o instalar sox y redirigir a</span>
<span class="c"># "play -u -b 8 -t raw -r 8000 -" sin las comillas</span>
<span class="c">#modificar la parte interna de la funcion int() para variar la "melodia"</span>
<span class="n">func</span> <span class="o">=</span> <span class="k">lambda</span> <span class="n">t</span><span class="p">:</span> <span class="nb">int</span><span class="p">((</span><span class="n">t</span><span class="o"><<</span><span class="mi">6</span><span class="o">|</span><span class="n">t</span><span class="o">|</span><span class="p">(</span><span class="n">t</span><span class="o"><<</span><span class="mi">16</span><span class="p">))</span> <span class="o">*</span> <span class="mi">10</span> <span class="o">+</span> <span class="p">((</span><span class="n">t</span><span class="o"><<</span><span class="mi">11</span><span class="p">)</span> <span class="o">&</span> <span class="mi">7</span><span class="p">))</span>
<span class="c">#generador de secuencia</span>
<span class="k">def</span> <span class="nf">inc</span><span class="p">(</span><span class="n">t</span><span class="p">):</span>
<span class="sd">'''generador para incrementar t'''</span>
<span class="n">c</span><span class="o">=</span><span class="n">t</span>
<span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
<span class="k">yield</span> <span class="n">c</span>
<span class="n">c</span><span class="o">=</span><span class="n">c</span><span class="o">+</span><span class="mi">1</span>
<span class="k">if</span> <span class="n">__name__</span><span class="o">==</span><span class="s">'__main__'</span><span class="p">:</span>
<span class="k">for</span> <span class="n">t</span> <span class="ow">in</span> <span class="n">inc</span><span class="p">(</span><span class="mi">0</span><span class="p">):</span>
<span class="k">print</span><span class="p">(</span><span class="s">"</span><span class="si">%X</span><span class="s">"</span> <span class="o">%</span> <span class="n">func</span><span class="p">(</span><span class="n">t</span><span class="p">))</span>
</pre></div>
<p>Espero que alguien lo encuentre interesante y genere nuevas
"melodías". Quizás decir que el generador es lo que menos me ha gustado
ya que queda poco "pitónico", si bien el programa final queda bastante
legible ya que añadí algo de codigo por variar la funcionalidad inicial
y dar mas opciones con el fichero.</p>
<p>Para ver el resultado final recomiendo <a class="reference external" href="http://www.youtube.com/watch?feature=player_detailpage&v=qlrs2Vorw2Y#t=16s">el video</a> de los enlaces</p>
time, datetime, epoch y el lio de todos los tiempostag:blog.willyfrog.es,2011-10-31:/2011/time-datetime-epoch-y-el-lio-de-todos-los-tiempos2011-10-31T11:17:00ZWillyfroghttp://blog.willyfrog.es/nadaird@willyfrog.es<p>Estoy intentando hacer la transición del código de Python de una
aplicación desde mx.DateTime a la librería estándar de Python datetime.
Las razones son 2, por un lado quitarnos una dependencia que no hace
falta realmente y por otra facilitar la transición a psycopg2 (estamos
usando el 1 ahora mismo). La mayor parte de las cosas son fácilmente
traducibles ya que en ocasiones usan la misma sintaxis o parecida.</p>
<p>Si bien nadie debería jugar demasiado con <a class="reference external" href="http://en.wikipedia.org/wiki/Unix_epoch">epoch</a> dado que Python
ofrece múltiples opciones para jugar con la fecha tanto en mx.DateTime
como en datetime, parece que los tiempos de C no se olvidan y hay quien
lo prefiere. Esto, me ha supuesto un problema ya que para traer una
fecha de un timestamp a datetime es sencillo, pero la inversa no. En
cualquier otro caso estaría estudiando un poco el código para adaptarlo
y hacerlo sencillo, pero dado que tengo que cambiar algo más de 100
ficheros, me corre cierta prisa cambiar todo y que de primeras funcione
igual, es decir que no puedo cambiar apenas el código mas que lo
estrictamente necesario.</p>
<p>Por si alguien más lo necesita, el código para pasar de datetime al
número de segundos desde 'epoch' sería el siguiente:</p>
<div class="highlight"><pre><span class="n">time</span><span class="o">.</span><span class="n">mktime</span><span class="p">(</span><span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">today</span><span class="p">()</span><span class="o">.</span><span class="n">timetuple</span><span class="p">())</span>
</pre></div>
<p>datetime.datetime.today() puede sustituirse por cualquier otra fecha en
formato datetime, además se pierde la precisión del float debido al uso
de timetuple, por lo que si los microsegundos son importantes, esta no
es una forma válida, aunque posiblemente sería parcheable.</p>
<p><a class="reference external" href="http://bytes.com/topic/python/answers/522572-datetime-timestamp">Fuente</a></p>