<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3499379363161703464</id><updated>2012-01-28T17:05:57.933+01:00</updated><category term='ensamblador'/><category term='linux'/><category term='ruby'/><category term='QT'/><category term='scala'/><category term='openbsd'/><category term='javascript'/><category term='java'/><category term='erlang'/><category term='web'/><category term='php'/><category term='ajax'/><category term='perl'/><category term='boost'/><category term='programacion'/><category term='bases de datos'/><category term='c'/><category term='c#'/><category term='jquery'/><category term='wikipedia'/><category term='android'/><category term='css'/><category term='proyectos'/><category term='opengl'/><category term='python'/><category term='ingenieria inversa'/><category term='symbian'/><category term='rails'/><category term='memcached'/><category term='windows'/><category term='c++'/><category term='redes'/><title type='text'>Blog de javiyu</title><subtitle type='html'>Blog de programación y diseño de software</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default?start-index=101&amp;max-results=100'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>147</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-3066137733966506648</id><published>2011-12-10T09:52:00.001+01:00</published><updated>2011-12-10T10:12:37.867+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Plantillas javascript</title><content type='html'>Las aplicaciones web que usan AJAX suelen seguir un patrón similar:&lt;br /&gt;1) Se lanza un evento javascript&lt;br /&gt;2) Se genera una petición al servidor&lt;br /&gt;3) El servidor produce código javascript de vuelta con el objetivo de añadir/eliminar HTML de la página.&lt;br /&gt;&lt;br /&gt;Cuando hay que insertar gran cantidad de HTML el código javascript producido suele ser poco mantenible, el primer planteamiento es crear una gran cadena de marcado HTML para insertarla en algún lugar de la página.&lt;br /&gt;&lt;br /&gt;Por suerte, existe un plugin para la librería jQuery llamado &lt;a href="https://github.com/jquery/jquery-tmpl"&gt;jQuery Templates&lt;/a&gt; que elimina este problema.&lt;br /&gt;&lt;br /&gt;Para usar este plugin, podemos definir una plantilla javascript de la siguiente forma:&lt;br /&gt;&lt;pre name="code" class="javascript"&gt;&amp;lt;script id="templateId" type="text/x-jquery-tmpl"&amp;gt;&lt;br /&gt;${templateText}&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;/pre&gt;Siguiendo este ejemplo, con el id 'templateId' recuperaremos posteriormente la plantilla y podremos hacer la sustitución de 'templateText' con la siguiente llamada.&lt;br /&gt;&lt;pre name="code" class="javascript"&gt;$("#templateId").tmpl({templateText:"Hello world"})&lt;br /&gt;&lt;/pre&gt;Como se puede ver, es similar a cualquier sistema de plantillas, se puede interpolar marcado HTML, crear condicionales:&lt;br /&gt;&lt;pre name="code" class="javascript"&gt;&amp;lt;script id="templateId" type="text/x-jquery-tmpl"&amp;gt;&lt;br /&gt;{{if error}}&lt;br /&gt;&amp;lt;h2&amp;gt;Error!&amp;lt;/h2&amp;gt;&lt;br /&gt;{{else}}&lt;br /&gt;&amp;lt;h1&amp;gt;OK&amp;lt;/h1&amp;gt;&lt;br /&gt;{{/if}}&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre name="code" class="javascript"&gt;$("#templateId").tmpl({error:false})&lt;br /&gt;&lt;/pre&gt;O incluso bucles:&lt;br /&gt;&lt;pre name="code" class="javascript"&gt;&amp;lt;script id="templateId" type="text/x-jquery-tmpl"&amp;gt;&lt;br /&gt;&amp;lt;h1&amp;gt;${title}&amp;lt;/h1&amp;gt;&lt;br /&gt;{{each items}}&lt;br /&gt;&amp;lt;li&amp;gt;${$value}&amp;lt;/li&amp;gt;&lt;br /&gt;{{/each}}&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre name="code" class="javascript"&gt;$("#templateId").tmpl({title:"Titulo", items:["uno", "dos", "tres"]})&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-3066137733966506648?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/3066137733966506648/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=3066137733966506648&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3066137733966506648'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3066137733966506648'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2011/12/plantillas-javascript.html' title='Plantillas javascript'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-6800472046124361256</id><published>2011-09-18T12:39:00.001+02:00</published><updated>2011-09-18T12:39:44.063+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Batch processing en rails</title><content type='html'>En aplicaciones web con cierta complejidad, es común que aparte de responder a las peticiones de los clientes, se necesite realizar trabajos batch o simplemente migrar la base de datos a una nueva estructura.&lt;br /&gt;&lt;br /&gt;Cuando la base de datos crece, aparecen nuevos problemas, uno de ellos es que las tablas de la base de datos pueden no caber en memoria. En hostings baratos este problema se acentúa ya que no se suele contar con demasiada RAM. Con ruby on rails es muy fácil solventar esta dificultad. &lt;br /&gt;&lt;br /&gt;Tomando como ejemplo una tabla muy grande de usuarios en la que hay que recalcular un campo para cada usuario.&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;User.find_each{|u| u.karma = calculate_karma(:user =&gt; u)}&lt;br /&gt;&lt;/pre&gt;&lt;i&gt;find_each&lt;/i&gt; toma bloques de 1000 usuarios y va devolviendo de uno en uno de forma transparente, se utilizan 1000 entradas por defecto pero se puede cambiar mediante el parámetro &lt;i&gt;batch_size&lt;/i&gt;.&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;User.find_each(:batch_size =&gt; 200){|u| u.karma = calculate_karma(:user =&gt; u)}&lt;br /&gt;&lt;/pre&gt;&lt;i&gt;find_each&lt;/i&gt; se implementa usando &lt;i&gt;find_in_batches&lt;/i&gt;, se puede llegar a mayor nivel de control usando esta función que devuelve directamente los grupos de entradas.&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;User.find_in_batches(:batch_size =&gt; 2000){|group| group.each{|u| u.karma = calculate_karma(:user =&gt; u)}}&lt;br /&gt;&lt;/pre&gt;Puede que este último ejemplo parezca más complejo sin ningún tipo de beneficio, pero sería muy útil en caso de querer paralelizar el proceso.&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;User.find_in_batches(:batch_size =&gt; 2000){|group| Process.fork{calculate_karma(:group =&gt; group)}}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-6800472046124361256?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/6800472046124361256/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=6800472046124361256&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/6800472046124361256'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/6800472046124361256'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2011/09/batch-processing-en-rails.html' title='Batch processing en rails'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-5495294019952895841</id><published>2011-09-04T12:41:00.000+02:00</published><updated>2011-09-04T12:41:39.434+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Temporizadores en javascript: PollJS</title><content type='html'>Realizar tareas regulares en el tiempo en una web con javascript es una tarea algo pesada. &lt;a href="https://github.com/mtrpcic/polljs"&gt;PollJS&lt;/a&gt; es una librería muy pequeña y sencilla que facilita algo esta tarea.&lt;br /&gt;&lt;br /&gt;Un ejemplo de una tarea regular con PollJS.&lt;br /&gt;&lt;pre name="code" class="javascript"&gt;Poll.start({&lt;br /&gt;    name: "refresh_list",&lt;br /&gt;    interval: 1000,&lt;br /&gt;    action: function(){}&lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;Esa es la sintaxis básica para crear una tarea con PollJS, evidentemente nos deja establecer un intervalo de espera entre repeticiones y definir la acción que queremos ejecutar. Además se puede dar nombre a cada tarea para referenciarla posteriormente, por ejemplo, para detenerla.&lt;br /&gt;&lt;pre name="code" class="javascript"&gt;Poll.stop("refresh_list");&lt;br /&gt;&lt;/pre&gt;Existe otra forma de detener una tarea, devolviendo &lt;i&gt;false&lt;/i&gt; en la función que se pasa como acción se detiene el temporizador.&lt;br /&gt;&lt;br /&gt;Con esta librería podemos además definir un número de reintentos máximo y una función de fallback si en ninguno de los intentos se ha detenido el temporizador.&lt;br /&gt;&lt;pre name="code" class="javascript"&gt;Poll.start({&lt;br /&gt;    name: "refresh_list",&lt;br /&gt;    action: function(){},&lt;br /&gt;    interval: 1000, &lt;br /&gt;    attempts: 5,&lt;br /&gt;    fallback: function(){}&lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-5495294019952895841?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/5495294019952895841/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=5495294019952895841&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/5495294019952895841'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/5495294019952895841'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2011/09/temporizadores-en-javascript-polljs.html' title='Temporizadores en javascript: PollJS'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-4172275095587310581</id><published>2011-08-24T11:27:00.005+02:00</published><updated>2011-08-24T11:49:21.618+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Visor de PDF en HTML5</title><content type='html'>Andreas Gal (investigador de Mozilla Corporation) ha publicado la librería javascript &lt;a href="https://github.com/andreasgal/pdf.js"&gt;PDF.js&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Con esta librería se pueden visualizar ficheros PDF en el navegador sin plugins externos, las ventajas son claras, no hay necesidad  de un programa externo, es multiplataforma, más seguro y provee de mayor interacción con el navegador.&lt;br /&gt;&lt;br /&gt;PDF.js está todavía en proceso de desarrollo y pero el autor pretende lanzar una extensión de firefox para abrir los ficheros PDF directamente en el navegador.&lt;br /&gt;Por ahora para visualizar un fichero PDF se crea dinámicamente un elemento &lt;span style="font-style:italic;"&gt;canvas&lt;/span&gt; en el que se muestra la información, sin embargo, se planea migrar a &lt;span style="font-style:italic;"&gt;SVG&lt;/span&gt; para permitir selección de texto, búsquedas y mayor interacción con el fichero.&lt;br /&gt;&lt;br /&gt;Es un paso importante hacer que este tipo de ficheros se integren completamente en la web, ya algunos buscadores indexan su texto y lo incluyen en las búsquedas.&lt;br /&gt;&lt;br /&gt;Por contra, tanto &lt;span style="font-style:italic;"&gt;canvas&lt;/span&gt; como &lt;span style="font-style:italic;"&gt;SVG&lt;/span&gt; están disponibles solo en los navegadores que soportan HTML5 y aún no hay un porcentaje aceptable de usuarios que  usen este tipo de navegadores para aceptar esta solución como medida única.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-4172275095587310581?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/4172275095587310581/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=4172275095587310581&amp;isPopup=true' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/4172275095587310581'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/4172275095587310581'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2011/08/visor-de-pdf-en-html5.html' title='Visor de PDF en HTML5'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-5904730927205658760</id><published>2011-06-03T19:53:00.003+02:00</published><updated>2011-06-03T20:09:37.889+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Extensión de clases en Scala</title><content type='html'>En algunos lenguajes de programación dinámicos como ruby se permite añadir funcionalidad a clases ya existentes. Cuando esto ocurre, se dice que las clases en ese lenguaje son 'abiertas'. &lt;br /&gt;&lt;br /&gt;Un lenguaje de programación con clases abiertas añade mucha flexibilidad para el programador, sin embargo, esta flexibilidad hace que sea más difícil auditar el código.&lt;br /&gt;&lt;br /&gt;La principal ventaja de esta técnica es poder aumentar la funcionalidad de las clases que proporciona en lenguaje. Al tener unos tipos básicos con una interfaz más rica, el código comienza a ser más sencillo y se reduce el número de líneas de código para desarrollar una funcionalidad.&lt;br /&gt;&lt;br /&gt;En Scala, las clases no son abiertas, sin embargo, tiene un mecanismo similar con el que se pueden llegar a resultados no muy distintos.&lt;br /&gt;&lt;br /&gt;Ejemplo:&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;&lt;br /&gt;class RomanNumber(val number:Int){&lt;br /&gt; def toRoman:String = {&lt;br /&gt;  if(number == 1) return "I";&lt;br /&gt;  else if(number == 2) return "II";&lt;br /&gt;  else if(number == 3) return "III";&lt;br /&gt;  else if(number == 4) return "IV";&lt;br /&gt;  else if(number == 5) return "V";  &lt;br /&gt;  else return "Unknown";&lt;br /&gt; } &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;object Main extends Application{&lt;br /&gt; implicit def intRomanNumber(x:Int) = new RomanNumber(x);&lt;br /&gt;&lt;br /&gt; override def main(args: Array[String]){&lt;br /&gt;  println(1.toRoman);&lt;br /&gt;  println(3.toRoman);&lt;br /&gt;  println(5.toRoman);&lt;br /&gt;  println(6.toRoman);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;En este ejemplo se crea una clase 'RomanNumber' que contiene la funcionalidad que necesitamos añadir a los enteros 'toRoman'.&lt;br /&gt;&lt;br /&gt;El código resultaría muy redundante si cada vez que queremos usar el método 'toRoman' necesitamos crear una instancia de la clase y pasarle como argumento el entero. Algo como: &lt;span style="font-style:italic;"&gt;new RomanNumber(4).toRoman&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Para este tipo de casos, Scala provee del mecanismo de conversión implícita, en el ejemplo el método 'intRomanNumber'.&lt;br /&gt;Al definir un método como 'implicit' se llamará para hacer el correspondiente cambio de tipos como se le indique, en este caso creando una instancia de 'RomanNumber'.&lt;br /&gt;&lt;br /&gt;El resultado final es el que aparece en el ejemplo, parece que los métodos añadidos mediante conversión implícita pertenezcan a la clase original, muy similar al caso de los lenguajes dinámicos y las clases abiertas.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-5904730927205658760?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/5904730927205658760/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=5904730927205658760&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/5904730927205658760'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/5904730927205658760'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2011/06/extension-de-clases-en-scala.html' title='Extensión de clases en Scala'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-801114638398575442</id><published>2011-04-16T10:28:00.002+02:00</published><updated>2011-04-16T10:34:02.475+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>attr_accessor_with_default</title><content type='html'>Un pequeño tip sobre los atributos en ruby on rails, normalmente en cualquier clase se pueden declarar atributos con &lt;span style="font-style:italic;"&gt;attr_accessor&lt;/span&gt;, pero, si lo que se necesita es un atributo que tenga un valor por defecto, existe una función menos conocida &lt;span style="font-style:italic;"&gt;attr_accessor_with_default&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Un ejemplo&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;&lt;br /&gt;class Example&lt;br /&gt;  attr_accessor_with_default :attr, 'default message'&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;e = Example.new&lt;br /&gt;e.attr&lt;br /&gt;=&gt; 'default message'&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-801114638398575442?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/801114638398575442/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=801114638398575442&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/801114638398575442'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/801114638398575442'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2011/04/attraccessorwithdefault.html' title='attr_accessor_with_default'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-8294107638142917254</id><published>2011-03-20T11:35:00.003+01:00</published><updated>2011-03-20T12:03:30.488+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Propagación de eventos en jQuery</title><content type='html'>La primera aproximación de asignación de eventos a los elementos del DOM es la más sencilla, simplemente se establece el callback a ejecutar en el elemento que posee el evento.&lt;br /&gt;&lt;pre name="code" class="javascript"&gt;&lt;br /&gt;$('#element').click(function(){alert('hello');})&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Usando este método se disparará el evento del elemento con id 'element', después su padre, y así sucesivamente.&lt;br /&gt;&lt;br /&gt;La segunda posibilidad es usar 'live', de esta forma todos los elementos futuros que cumplan con el selector dispararán el evento.&lt;br /&gt;&lt;pre name="code" class="javascript"&gt;&lt;br /&gt;$('#element').live('click', function(){alert('hello');})&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Esta aproximación asigna el callback a la raíz del DOM (document) de tal forma que cada vez que se dispara un evento si coincide tanto en tipo como en su selector, se dispara el callback. &lt;br /&gt;Esta implementación, aún siendo muy útil puede dar lugar a comportamientos inesperados, el callback establecido con 'live' se ejecutará el último en la jerarquía de propagación del evento.&lt;br /&gt;&lt;br /&gt;'live' no es más que una particularización de 'delegate'. 'delegate' se puede usar para hilar más fino en el establecimiento de la respuesta a eventos.&lt;br /&gt;&lt;pre name="code" class="javascript"&gt;&lt;br /&gt;$('#parent').delegate('#element', 'click', function() { alert("hello") });&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;En este caso, establecemos el callback en 'parent' en lugar de en document, por lo demás el funcionamiento es similar a 'live'. &lt;br /&gt;Cada vez que el evento llegue a 'parent' se comprobará si coincide tanto en tipo como en el selector, de ser cierto se dispara el callback.&lt;br /&gt;&lt;br /&gt;'delegate' es mucho más eficiente que 'live' puesto que solo comprueba los eventos tomando como raíz el elemento que le indicamos en lugar de todo el documento como es el caso de 'live'. Aún así el problema en el orden de propagación aparece al igual que en 'live'.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-8294107638142917254?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/8294107638142917254/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=8294107638142917254&amp;isPopup=true' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/8294107638142917254'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/8294107638142917254'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2011/03/propagacion-de-eventos-en-jquery.html' title='Propagación de eventos en jQuery'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-4994590952570759117</id><published>2011-02-03T22:04:00.004+01:00</published><updated>2011-02-03T22:08:46.761+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Generar proyectos ruby on rails con versiones anteriores</title><content type='html'>Después del cambio de versión de ruby on rails de la rama 2 a la 3, surge un caso muy típico, tener instalado rails 3 y querer generar un proyecto con la versión 2.&lt;br /&gt;&lt;br /&gt;Para generar un proyecto de ruby on rails con una versión anterior que tengamos instalada tan solo hay que ejecutar lo siguiente:&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;&lt;br /&gt;rails _VERSION_ proyecto&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Donde VERSION es la numeración específica de la versión de rails, por ejemplo, para crear un proyecto con la versión 2.3.8 (actualmente la última de la rama 2).&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;&lt;br /&gt;rails _2.3.8_ proyecto&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-4994590952570759117?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/4994590952570759117/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=4994590952570759117&amp;isPopup=true' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/4994590952570759117'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/4994590952570759117'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2011/02/generar-proyectos-ruby-on-rails-con.html' title='Generar proyectos ruby on rails con versiones anteriores'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-6044292663159555842</id><published>2011-01-20T20:56:00.003+01:00</published><updated>2011-01-20T21:04:07.962+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Depuración android por red</title><content type='html'>Hay dispositivos android que no permiten la depuración a través del conector USB, aún así, es posible usarlos para desarrollo usando la conectividad por Wi-Fi.&lt;br /&gt;&lt;br /&gt;Simplemente hay que conectar el dispositivo a la misma red Wi-Fi que el PC desde el que estamos desarrollando y ejecutar el comando:&lt;br /&gt;&lt;pre name="code" class="c"&gt;&lt;br /&gt;adb connect ip:5555&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Donde ip es la dirección IP del dispositivo en la interfaz Wi-Fi.&lt;br /&gt;A partir de ahí se puede usar adb igual que cuando está conectada la depuración USB, se puede usar la shell, la transferencia de ficheros, etc, incluso el android SDK sin necesidad de cables.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-6044292663159555842?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/6044292663159555842/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=6044292663159555842&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/6044292663159555842'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/6044292663159555842'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2011/01/depuracion-android-por-red.html' title='Depuración android por red'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-6182467358887367367</id><published>2011-01-07T19:17:00.003+01:00</published><updated>2011-01-07T19:30:35.751+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Conocer el método desde el que una función es llamada en Java</title><content type='html'>El lenguaje de programación Java en sus últimas versiones tiene algunas construcciones que permiten introspección.&lt;br /&gt;&lt;br /&gt;Como ejemplo en el siguiente trozo de código la función '&lt;span style="font-style:italic;"&gt;print&lt;/span&gt;' tiene un comportamiento u otro dependiendo de que método le llama. En general esto no es una buena práctica de programación pero sirve como ejemplo ilustrativo.&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;public class Ejemplo{ &lt;br /&gt; public static void print(){&lt;br /&gt;  StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();&lt;br /&gt;  StackTraceElement e;&lt;br /&gt;  String str = stackTraceElements[2].getMethodName();&lt;br /&gt;    &lt;br /&gt;  if(str.equals("other")){&lt;br /&gt;   System.out.println("Other message!");&lt;br /&gt;  } &lt;br /&gt;  else{&lt;br /&gt;   System.out.println("Hello world!");   &lt;br /&gt;  }  &lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; public static void other(){&lt;br /&gt;  print();&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; public static void main(String[] args){&lt;br /&gt;  print();&lt;br /&gt;  other();&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;La llamada '&lt;span style="font-style:italic;"&gt;Thread.currentThread().getStackTrace()&lt;/span&gt;' devuelve un array de elementos '&lt;span style="font-style:italic;"&gt;StackTraceElement&lt;/span&gt;', cada uno de estos elementos representa una llamada de la pila de llamadas a funciones.&lt;br /&gt;&lt;br /&gt;En el ejemplo anterior se consulta el nombre del método, pero se pueden extraer más datos, más información en el javadoc de &lt;a href="http://download.oracle.com/javase/6/docs/api/java/lang/StackTraceElement.html"&gt;StackTraceElement&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-6182467358887367367?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/6182467358887367367/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=6182467358887367367&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/6182467358887367367'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/6182467358887367367'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2011/01/conocer-el-metodo-desde-el-que-una.html' title='Conocer el método desde el que una función es llamada en Java'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-7400556929651128411</id><published>2010-12-25T11:09:00.002+01:00</published><updated>2010-12-25T11:29:39.910+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Javascript orientado a objetos</title><content type='html'>Debido al gran auge de la web, últimamente han surgido numerosas librerías y tutoriales acerca de como programar javascript orientado a objetos.&lt;br /&gt;&lt;br /&gt;No es difícil encapsular código javascript simulando que se está trabajando con clases.&lt;br /&gt;&lt;pre name="code" class="javascript"&gt;&lt;br /&gt;function Article(title, body){&lt;br /&gt;    this.title = title;&lt;br /&gt;    this.body = body;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;var a = new Article('titulo', 'noticia')&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Incluso se puede conseguir visibilidad privada para los atributos de la 'clase' que elijamos.&lt;br /&gt;&lt;pre name="code" class="javascript"&gt;&lt;br /&gt;function Article(title, body){&lt;br /&gt;    this.body = body;&lt;br /&gt;    var _title = title;&lt;br /&gt;    this.getTitle = function(){&lt;br /&gt;        return _title;&lt;br /&gt;    }&lt;br /&gt;    this.setTitle = function(title){&lt;br /&gt;        _title = title;&lt;br /&gt;    }     &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Sin embargo, en mi opinión todas estas aproximaciones conducen a escribir código javascript poco natural. Javascript fue pensado como un lenguaje de programación basado en prototipos y su flujo principal de ejecución es orientado a eventos.&lt;br /&gt;&lt;br /&gt;Está basado en prototipos, la encapsulación, las 'clases' se obtienen a partir de la clonación de objetos y no de una estructura tan rígida como la orientación a objetos. Esto hace al lenguaje mucho más propicio para las tareas que fue pensado.&lt;br /&gt;&lt;br /&gt;De la orientación a eventos del lenguaje han surgido proyectos muy interesantes como &lt;a href="http://nodejs.org/"&gt;node.js&lt;/a&gt;, hay que tratar de aprovechar las bondades del lenguaje, no cambiarlas a través de capas de abstracción.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-7400556929651128411?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/7400556929651128411/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=7400556929651128411&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/7400556929651128411'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/7400556929651128411'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/12/javascript-orientado-objetos.html' title='Javascript orientado a objetos'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-1791885486906009591</id><published>2010-12-15T23:37:00.002+01:00</published><updated>2010-12-15T23:45:39.466+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Logger en ruby</title><content type='html'>Similar al proyecto &lt;span style="font-style:italic;"&gt;log4j&lt;/span&gt; existe para ruby una librería de logging para el depurado de aplicaciones, gestión de mensajes de error, etc.&lt;br /&gt;&lt;br /&gt;El nombre de la librería es &lt;span style="font-style:italic;"&gt;log4r&lt;/span&gt;, se distribuye como gema y es fácilmente personalizable.&lt;br /&gt;&lt;br /&gt;Para usarla tan solo hay que instancia un objeto de la clase &lt;span style="font-style:italic;"&gt;Logger&lt;/span&gt;. Para dicho objeto se pueden seleccionar distintos &lt;span style="font-style:italic;"&gt;outputters&lt;/span&gt; (medio de salida), en el ejemplo se muestran los mensajes tanto por salida estándar como por UDP.&lt;br /&gt;&lt;br /&gt;Posteriormente, para cada &lt;span style="font-style:italic;"&gt;outputter&lt;/span&gt; se puede elegir un &lt;span style="font-style:italic;"&gt;formatter&lt;/span&gt; (formato de la salida). En el ejemplo la salida por UDP será en el formato por defecto mientras que la salida estándar será en XML.&lt;br /&gt;&lt;br /&gt;El ejemplo de uso de la librería.&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;&lt;br /&gt;require 'rubygems'&lt;br /&gt;require 'log4r'&lt;br /&gt;require 'log4r/formatter/log4jxmlformatter'&lt;br /&gt;require 'log4r/outputter/udpoutputter'&lt;br /&gt;&lt;br /&gt;include Log4r&lt;br /&gt;&lt;br /&gt;logger = Logger.new 'mylog'&lt;br /&gt;&lt;br /&gt;#Formatters&lt;br /&gt;xmlformat = Log4jXmlFormatter.new&lt;br /&gt;&lt;br /&gt;#Ouputters&lt;br /&gt;stdout = Outputter.stdout&lt;br /&gt;udpout = UDPOutputter.new 'udp', :hostname =&gt; "localhost", :port =&gt; 8888&lt;br /&gt;&lt;br /&gt;stdout.formatter = xmlformat&lt;br /&gt;&lt;br /&gt;logger.outputters = [stdout, udpout]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def debug(logger, txt)&lt;br /&gt;  logger.debug txt&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def error(logger, txt)&lt;br /&gt;  logger.error txt&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;debug(logger, 'Mensaje de DEBUG')&lt;br /&gt;error(logger, 'Mensaje de error')&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Para más información se puede consultar la web oficial de &lt;a href="http://log4r.rubyforge.org/manual.html"&gt;log4r&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-1791885486906009591?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/1791885486906009591/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=1791885486906009591&amp;isPopup=true' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/1791885486906009591'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/1791885486906009591'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/12/logger-en-ruby.html' title='Logger en ruby'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-8660089963120182406</id><published>2010-11-20T20:10:00.003+01:00</published><updated>2010-11-20T20:27:38.755+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='ingenieria inversa'/><category scheme='http://www.blogger.com/atom/ns#' term='windows'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Lectura de memoria entre procesos Windows</title><content type='html'>En todos los sistemas operativos modernos la memoria está protegida entre procesos. &lt;br /&gt;Si un proceso accede o escribe en una posición de memoria no esperada no debe afectar a los demás procesos.&lt;br /&gt;&lt;br /&gt;A pesar de este planteamiento, en Windows es posible leer o escribir zonas de memoria entre procesos, para ello están las funciones del API &lt;span style="font-style:italic;"&gt;ReadProcessMemory&lt;/span&gt; y &lt;span style="font-style:italic;"&gt;WriteProcessMemory&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;El primer paso es encontrar el PID del proceso en el que estamos interesados y después debe obtenerse un handle con la función &lt;span style="font-style:italic;"&gt;OpenProcess&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Para buscar el proceso destino hay varias formas, en este ejemplo se usa el nombre de la ventana visible del proceso.&lt;br /&gt;&lt;pre name="code" class="c"&gt;&lt;br /&gt;#include &amp;lt;QtCore/QCoreApplication&amp;gt;&lt;br /&gt;#include &amp;lt;windows.h&amp;gt;&lt;br /&gt;&lt;br /&gt;DWORD getPIDByWindowName(WCHAR* name);&lt;br /&gt;&lt;br /&gt;int main(int argc, char *argv[]){&lt;br /&gt;    QCoreApplication a(argc, argv);&lt;br /&gt;    BYTE buffer[300];&lt;br /&gt;    DWORD readed;&lt;br /&gt;    DWORD processID = getPIDByWindowName(TEXT("Calculadora"));&lt;br /&gt;    HANDLE procHandle = OpenProcess(0x0010, 0, processID);&lt;br /&gt;    ReadProcessMemory(procHandle, (void*)0x00951558, buffer, 50, &amp;readed);&lt;br /&gt;    return a.exec();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;DWORD getPIDByWindowName(WCHAR* name){&lt;br /&gt;    DWORD processID;&lt;br /&gt;    HWND windowHandle = FindWindowW(NULL, name);&lt;br /&gt;    GetWindowThreadProcessId(windowHandle, &amp;processID);&lt;br /&gt;    return processID;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Gracias al uso de estas funciones del API se abre una nueva posibilidad de comunicación entre procesos, sin embargo, abre también un grave riesgo de seguridad. Entre otros usos, modificando la memoria de los procesos de antivirus o cortafuegos se pueden inutilizar dando una falsa sensación se seguridad.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-8660089963120182406?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/8660089963120182406/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=8660089963120182406&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/8660089963120182406'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/8660089963120182406'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/11/lectura-de-memoria-entre-procesos.html' title='Lectura de memoria entre procesos Windows'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-883355983260278862</id><published>2010-11-16T20:34:00.004+01:00</published><updated>2010-11-16T20:53:19.983+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='QT'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Ejecución de tareas asíncronas en C++ con QT</title><content type='html'>En los programas con interfaz gráfica no deben ejecutarse tareas que puedan demorarse en el mismo hilo de la interfaz.&lt;br /&gt;Esto ocurre muy a menudo si en el evento 'click' de un botón se hace una lectura/escritura de un fichero o una base de datos.&lt;br /&gt;&lt;br /&gt;Con las librerías QT se puede solucionar de varias formas, una es creando un hilo (una clase que herede de &lt;span style="font-style:italic;"&gt;QThread&lt;/span&gt;). Una forma aún más sencilla es crear un objeto &lt;span style="font-style:italic;"&gt;QRunnable&lt;/span&gt; y hacer que el pool de QT lo ejecute en segundo plano.&lt;br /&gt;&lt;br /&gt;Un ejemplo de lo segundo.&lt;br /&gt;&lt;pre name="code" class="c"&gt;&lt;br /&gt;class AsynchrounousTask : public QRunnable{&lt;br /&gt;    protected:&lt;br /&gt;        QLabel *label;&lt;br /&gt;    public:&lt;br /&gt;        AsynchrounousTask(QLabel *label){&lt;br /&gt;            this-&gt;label = label;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        void run(){&lt;br /&gt;            sleep(5); //long task;&lt;br /&gt;            label-&gt;setText("Done!");&lt;br /&gt;        }&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Y para usarlo tan solo hay que hacer.&lt;br /&gt;&lt;pre name="code" class="c"&gt;&lt;br /&gt;    AsynchrounousTask *aTask = new AsynchrounousTask(ui-&gt;label);&lt;br /&gt;    QThreadPool::globalInstance()-&gt;start(aTask);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Aunque creamos un objeto con &lt;span style="font-style:italic;"&gt;new&lt;/span&gt; no hay que preocuparse por su destrucción, al terminar su ejecución a través del pool se liberará de forma automática. Si preferimos que no se libere de forma automática tan solo hay que llamar al método '&lt;span style="font-style:italic;"&gt;setAutoDelete(false)&lt;/span&gt;'.&lt;br /&gt;&lt;br /&gt;Ejecutando las tareas más pesadas de la aplicación de esta forma no se bloqueará la aplicación en ningún momento y siempre responderá a las nuevas peticiones que el usuario haga.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-883355983260278862?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/883355983260278862/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=883355983260278862&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/883355983260278862'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/883355983260278862'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/11/ejecucion-de-tareas-asincronas-en-c-con.html' title='Ejecución de tareas asíncronas en C++ con QT'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-2062188855450298607</id><published>2010-11-10T20:38:00.004+01:00</published><updated>2010-11-10T20:50:02.914+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='QT'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Compilación de ejecutable con Qt Creator</title><content type='html'>Cuando creamos una aplicación con Qt Creator en Windows es necesario incluir los ficheros dll de Qt para que la aplicación funcione correctamente.&lt;br /&gt;&lt;br /&gt;En ocasiones este no es el comportamiento deseado, se puede generar un fichero ejecutable autónomo (sin necesidad de ninguna librería dll externa) ejecutando el siguiente comando:&lt;br /&gt;&lt;pre name="code" class="c"&gt;&lt;br /&gt;qmake -nodepend -o Makefile project.pro&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Si no se encuentra el programa qmake hay que añadirlo al PATH, la instalación por defecto de QT Creator no lo hace. &lt;br /&gt;Una vez ejecutado el comando anterior, al compilar obtendremos un ejecutable con toda la funcionalidad incluida, sin necesidad de incluir ningún fichero dll.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-2062188855450298607?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/2062188855450298607/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=2062188855450298607&amp;isPopup=true' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/2062188855450298607'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/2062188855450298607'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/11/compilacion-de-ejecutable-con-qt.html' title='Compilación de ejecutable con Qt Creator'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-3814363808538462091</id><published>2010-10-17T10:48:00.004+02:00</published><updated>2010-10-17T11:06:58.900+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Anidamiento de módulos en ruby</title><content type='html'>Tal y como ocurre en python con los decoradores, cuando se programa un módulo en ruby debería dejarse la puerta abierta a que no fuera el único.&lt;br /&gt;&lt;br /&gt;En el siguiente ejemplo tenemos dos módulos (&lt;span style="font-style:italic;"&gt;Printable&lt;/span&gt; y &lt;span style="font-style:italic;"&gt;Serializable&lt;/span&gt;), ambos métodos se deben poder combinar en cualquier orden y pudiendo aparecer uno, ninguno o ambos.&lt;br /&gt;&lt;br /&gt;La clave para que un mismo método se ejecute en la clase y en cada uno de sus módulos, es la llamada a &lt;span style="font-style:italic;"&gt;super&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;En otros lenguajes esto no sería correcto, puesto que los módulos &lt;span style="font-style:italic;"&gt;Printable&lt;/span&gt; y &lt;span style="font-style:italic;"&gt;Serializable&lt;/span&gt; no son superclase de la clase &lt;span style="font-style:italic;"&gt;Test&lt;/span&gt;, pero en ruby, &lt;span style="font-style:italic;"&gt;super&lt;/span&gt; no llama exactamente a la superclase, sino que repite el mismo método que se está ejecutando obviando la definición actual.&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;&lt;br /&gt;module Printable&lt;br /&gt; def print_method&lt;br /&gt;  super&lt;br /&gt;  puts "I'm printable"&lt;br /&gt; end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;module Serializable&lt;br /&gt; def print_method&lt;br /&gt;  super&lt;br /&gt;  puts "I'm serializable"&lt;br /&gt; end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;class Test    &lt;br /&gt; include Printable&lt;br /&gt; include Serializable&lt;br /&gt;&lt;br /&gt; def method_missing(method, *args, &amp;block)&lt;br /&gt;  super if method.to_s != 'print_method'&lt;br /&gt; end&lt;br /&gt;&lt;br /&gt; def print_method&lt;br /&gt;  super&lt;br /&gt;  puts "I'm object of Test class"&lt;br /&gt; end&lt;br /&gt; &lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;t = Test.new&lt;br /&gt;t.print_method&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Con este planteamiento hay un problema añadido, al final de la cadena de llamadas a &lt;span style="font-style:italic;"&gt;print_method&lt;/span&gt; estará la clase de la que hereda &lt;span style="font-style:italic;"&gt;Test&lt;/span&gt;, y esta clase no tiene porqué tener implementado &lt;span style="font-style:italic;"&gt;print_method&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Para solucionarlo en este caso se redefine el &lt;span style="font-style:italic;"&gt;method_missing&lt;/span&gt;, cuando llegue el momento de ejecutar el método en alguna clase/módulo que no lo entienda, se corta la cadena de ejecuciones.&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;&lt;br /&gt;I'm printable&lt;br /&gt;I'm serializable&lt;br /&gt;I'm object of Test class&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-3814363808538462091?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/3814363808538462091/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=3814363808538462091&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3814363808538462091'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3814363808538462091'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/10/anidamiento-de-modulo-en-ruby.html' title='Anidamiento de módulos en ruby'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-2829951397625324353</id><published>2010-09-17T19:35:00.002+02:00</published><updated>2010-09-17T19:47:46.789+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><title type='text'>Conversión implícita de tipos</title><content type='html'>Es común escribir nuevas clases que expandan a las básicas del lenguaje.&lt;br /&gt;&lt;br /&gt;Uno de los problemas que nos podemos encontrar cuando hacemos esto es la conversión de tipos.&lt;br /&gt;&lt;br /&gt;Si por ejemplo creamos una nueva clase para manejar cadenas, el código se llenará rápidamente de castings para convertir las cadenas nativas del lenguaje a nuestra implementación. Esto ocurre sobre todo en lenguajes fuertemente tipados.&lt;br /&gt;&lt;br /&gt;C# provee una solución bastante elegante, la conversión implícita de tipos.&lt;br /&gt;&lt;br /&gt;Para mostrar el uso de esta característica se muestra una clase con dos tipos, una cadena y un entero y sus declaraciones de conversiones implícitas.&lt;br /&gt;&lt;pre name="code" class="c"&gt;&lt;br /&gt;public class MyClass&lt;br /&gt;{&lt;br /&gt;    private string str { get; set; }&lt;br /&gt;    private int number { get; set; }&lt;br /&gt;&lt;br /&gt;    public static implicit operator MyClass(string s)&lt;br /&gt;    {&lt;br /&gt;        MyClass ms = new MyClass();&lt;br /&gt;        ms.str = s;&lt;br /&gt;        return ms;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static implicit operator MyClass(int i)&lt;br /&gt;    {&lt;br /&gt;        MyClass ms = new MyClass();&lt;br /&gt;        ms.number = i;&lt;br /&gt;        return ms;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public string getStr()&lt;br /&gt;    {&lt;br /&gt;        return str;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public int getNumber()&lt;br /&gt;    {&lt;br /&gt;        return number;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Declarando un operador estático, implícito y público se consigue la sintaxis siguiente para la conversión de tipos.&lt;br /&gt;&lt;pre name="code" class="c"&gt;&lt;br /&gt;MyClass ms1 = "hello";&lt;br /&gt;MyClass ms2 = 2;&lt;br /&gt;&lt;br /&gt;Console.WriteLine(ms1.getStr());&lt;br /&gt;Console.WriteLine(ms2.getNumber());&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;En el ejemplo se puede ver que no es necesaria ninguna conversión, y se pasan tanto la cadena "hello" como el entero 2 a tipo &lt;span style="font-style:italic;"&gt;MyClass&lt;/span&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-2829951397625324353?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/2829951397625324353/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=2829951397625324353&amp;isPopup=true' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/2829951397625324353'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/2829951397625324353'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/09/conversion-implicita-de-tipos.html' title='Conversión implícita de tipos'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-7042193525480833774</id><published>2010-09-12T10:32:00.004+02:00</published><updated>2010-09-12T11:04:52.742+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><title type='text'>Extension methods en c#</title><content type='html'>En algunos lenguajes dinámicos como ruby las clases se denominan "abiertas". &lt;br /&gt;Esto significa que a cualquier clase se le puede añadir nuevos métodos o funcionalidades en tiempo de ejecución.&lt;br /&gt;&lt;br /&gt;Los lenguajes fuertemente tipados no suelen ofrecer tanta libertad, pero se disponen de otras herramientas.&lt;br /&gt;&lt;br /&gt;En C#, se pueden definir clases parciales, lo que significa que se puede definir el comportamiento de la clase en varias etapas.&lt;br /&gt;&lt;pre name="code" class="c"&gt;&lt;br /&gt;public partial class PartialClass&lt;br /&gt;{&lt;br /&gt;    public static void method1()&lt;br /&gt;    {&lt;br /&gt;        Console.WriteLine("method1"); &lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;...&lt;br /&gt;public partial class PartialClass&lt;br /&gt;{&lt;br /&gt;    public static void method2()&lt;br /&gt;    {&lt;br /&gt;        Console.WriteLine("method2");&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Manteniendo las clases como parciales en cualquier momento se puede añadir funcionalidad a una clase existente fuera de su definición original.&lt;br /&gt;&lt;br /&gt;Este método es útil tan solo para las clases que programamos, pero si queremos extender una librería externa o las clases del propio lenguaje las clases parciales no son de gran ayuda.&lt;br /&gt;&lt;br /&gt;C# tiene en cambio una posibilidad más interesante, los "extension methods".&lt;br /&gt;&lt;pre name="code" class="c"&gt;&lt;br /&gt;public static class ExtensionMethods&lt;br /&gt;{&lt;br /&gt;    public static string withDot(this string str)&lt;br /&gt;    {&lt;br /&gt;        return str + ".";&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;...&lt;br /&gt;string str = "text ";&lt;br /&gt;str.withDot();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Con el código anterior se le añade a la clase string el nuevo método (&lt;span style="font-style:italic;"&gt;withDot&lt;/span&gt;). &lt;br /&gt;Para hacer lo mismo sin "extension methods" habría sido necesario crear una nueva clase que heredara de &lt;span style="font-style:italic;"&gt;string &lt;/span&gt;y añadirle el método &lt;span style="font-style:italic;"&gt;withDot&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Gracias a los "extension methods" se puede evitar crear clases intermedias para extender funcionalidades de las ya existentes.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-7042193525480833774?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/7042193525480833774/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=7042193525480833774&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/7042193525480833774'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/7042193525480833774'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/09/extension-methods-en-c.html' title='Extension methods en c#'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-6574087711264916451</id><published>2010-08-28T17:09:00.003+02:00</published><updated>2010-08-28T17:22:04.952+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><title type='text'>Implementación explícita de interfaces en C#</title><content type='html'>Por diversas razones como la colisión de nombres o simplemente por diseño, puede que necesitemos mayor granularidad para distinguir que método de que interfaz estamos definiendo.&lt;br /&gt;&lt;br /&gt;Supongamos que tenemos el caso de una clase que implementa dos interfaces tal y como sigue:&lt;br /&gt;&lt;pre name="code" class="c"&gt;&lt;br /&gt;public interface IInterface1&lt;br /&gt;{&lt;br /&gt;    int method();&lt;br /&gt;    int method1();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public interface IInterface2&lt;br /&gt;{&lt;br /&gt;    int method();&lt;br /&gt;    int method2();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class ExampleClass : IInterface1, IInterface2&lt;br /&gt;{&lt;br /&gt;    public int method() { return 1; }&lt;br /&gt;    public int method1() { return 1; }&lt;br /&gt;    public int method2() { return 2; }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;En este caso, el método &lt;span style="font-style:italic;"&gt;method&lt;/span&gt; está presente en las dos interfaces y lo definimos en la clase.&lt;br /&gt;&lt;br /&gt;Si necesitáramos distinguir alguno de los casos se podría usar la implementación explícita de interfaces.&lt;br /&gt;&lt;pre name="code" class="c:nocontrols"&gt;&lt;br /&gt;public class ExampleClass : IInterface1, IInterface2&lt;br /&gt;{&lt;br /&gt;    public int method() { return 1; }&lt;br /&gt;    public int method1() { return 1; }&lt;br /&gt;    public int method2() { return 2; }&lt;br /&gt;&lt;br /&gt;    int IInterface1.method() { return 1; }&lt;br /&gt;    int IInterface2.method() { return 2; }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;public partial class Form1 : Form&lt;br /&gt;{&lt;br /&gt;    public Form1()&lt;br /&gt;    {&lt;br /&gt;        InitializeComponent();&lt;br /&gt;&lt;br /&gt;        ExampleClass example = new ExampleClass();&lt;br /&gt;        IInterface1 i1 = (IInterface1)example;&lt;br /&gt;        IInterface2 i2 = (IInterface2)example;&lt;br /&gt;&lt;br /&gt;        MessageBox.Show("Interface 1: " + i1.method());&lt;br /&gt;        MessageBox.Show("Interface 2: " + i2.method());&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Esto devolvería como resultados 1 y 2 respectivamente. Como vemos, a pesar de realizar la implementación explícita de ambas interfaces se sigue pudiendo implementar de la forma tradicional como caso base.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-6574087711264916451?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/6574087711264916451/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=6574087711264916451&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/6574087711264916451'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/6574087711264916451'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/08/implementacion-explicita-de-interfaces.html' title='Implementación explícita de interfaces en C#'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-7635868257260505466</id><published>2010-07-21T22:30:00.001+02:00</published><updated>2010-07-21T22:32:36.794+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='QT'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Internacionalización con QT</title><content type='html'>La librería QT está desarrollada de tal forma que las aplicaciones&lt;br /&gt;que estén hechas usando su API pueden internacionalizarse de forma bastante&lt;br /&gt;fácil.&lt;br /&gt;&lt;br /&gt;En primer lugar todas las cadenas de la aplicación deben sustituirse por llamadas&lt;br /&gt;a la función &lt;span style="font-style:italic;"&gt;tr&lt;/span&gt;.&lt;br /&gt;&lt;pre name="code" class="c"&gt;&lt;br /&gt;QObject::tr("cadena");&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;La cadena que pasemos a la función &lt;span style="font-style:italic;"&gt;tr&lt;/span&gt; servirá de índice para las cadenas&lt;br /&gt;definitivas en los distintos idiomas.&lt;br /&gt;&lt;br /&gt;Después se debe añadir una entrada en el fichero de proyecto (.pro) con los ficheros&lt;br /&gt;que se deben generar para cada idioma de las traducciones, con extensión .ts.&lt;br /&gt;&lt;pre name="code" class="c"&gt;&lt;br /&gt;TRANSLATIONS = en.ts es.ts&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Los ficheros se generarán al ejecutar el comando:&lt;br /&gt;&lt;pre name="code" class="c"&gt;&lt;br /&gt;lupdate proyecto.pro&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Estos ficheros .ts se pueden editar con QT Linguist, una vez introducidas todas las&lt;br /&gt;traducciones, se pueden exportar mediante la opción &lt;i&gt;Release&lt;/i&gt;, esto generaráa&lt;br /&gt;unos ficheros .qm.&lt;br /&gt;&lt;br /&gt;Posteriormente hay que crear un fichero de recursos que contenga los ficheros .qm&lt;br /&gt;de traducciones.&lt;br /&gt;&lt;br /&gt;Para obtener el idioma del equipo en el que se está ejecutándo la aplicación se puede&lt;br /&gt;hacer lo siguiente&lt;br /&gt;&lt;pre name="code" class="c"&gt;&lt;br /&gt;QString locale = QLocale::system().name();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Para que las traducciones se carguen hay que instanciar la clase &lt;span style="font-style:italic;"&gt;QTranslator&lt;/span&gt; y pasársela&lt;br /&gt;a la aplicación.&lt;br /&gt;&lt;pre name="code" class="c"&gt;&lt;br /&gt;QTranslator translator;&lt;br /&gt;translator.load(locale, ":/");&lt;br /&gt;a.installTranslator(&amp;amp;translator);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;La ruta ":/" se refiere al prefijo introducido en el fichero de recursos.&lt;br /&gt;&lt;br /&gt;Tras estos pasos las cadenas de la aplicación aparecerán traducidas dependiendo del idioma&lt;br /&gt;del equipo en el que se esté ejecutándo.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-7635868257260505466?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/7635868257260505466/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=7635868257260505466&amp;isPopup=true' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/7635868257260505466'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/7635868257260505466'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/07/internacionalizacion-con-qt.html' title='Internacionalización con QT'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-5591191681674354054</id><published>2010-07-15T22:18:00.002+02:00</published><updated>2010-07-15T22:37:00.106+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Como implementar interfaces en C++</title><content type='html'>C++ por si solo no trata las interfaces como un concepto diferenciado. Sin embargo se puede trabajar con interfaces tipo Java o C# aprovechándose de la heréncia múltiple creando clases abstractas.&lt;br /&gt;&lt;br /&gt;En el siguiente ejemplo las clases &lt;span style="font-style:italic;"&gt;ClassA&lt;/span&gt; y &lt;span style="font-style:italic;"&gt;ClassB&lt;/span&gt; implementan la interfaz &lt;span style="font-style:italic;"&gt;Interface&lt;/span&gt;, para ello tan solo tienen que redefinir el método &lt;span style="font-style:italic;"&gt;method&lt;/span&gt;.&lt;br /&gt;&lt;pre name="code" class="c"&gt;&lt;br /&gt;class Interface{&lt;br /&gt;    public:&lt;br /&gt;        virtual int method(int param) = 0;&lt;br /&gt;        virtual ~Interface(){};&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;class ClassA : public Interface{&lt;br /&gt;    public:&lt;br /&gt;        int method(int param){return param+1;}&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;class ClassB : public Interface{&lt;br /&gt;    public:&lt;br /&gt;        int method(int param){return param+2;}&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Todos los usos que se le dan normalmente a las interfaces siguen siendo válidos con esta aproximación, con una salvedad, si queremos pasar la interfaz como parámetro a una función normalmente se haría como sigue.&lt;br /&gt;&lt;pre name="code" class="c"&gt;&lt;br /&gt;std::string function(Interface i){&lt;br /&gt;    std::string str;&lt;br /&gt;&lt;br /&gt;    int number = i.method(1);&lt;br /&gt;    if(number==2){str = "ClassA";}&lt;br /&gt;    else if(number==3){str = "ClassB";}&lt;br /&gt;&lt;br /&gt;    return str;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Sin embargo, si hacemos esos el compilador protestará con un error similar a: "&lt;span style="font-style:italic;"&gt;cannot declare parameter 'i' to be of abstract type 'interface'&lt;/span&gt;". &lt;br /&gt;&lt;br /&gt;¿Por qué?&lt;br /&gt;Esto ocurre porque por defecto en C++ los parámetros se pasan por valor, el objeto 'i' es imposible de crear ya que es de un tipo abstracto, el compilador no puede instanciarlo.&lt;br /&gt;&lt;br /&gt;¿Qué solución hay?&lt;br /&gt;Pasarlo como referencia, con una definición como la siguiente.&lt;br /&gt;&lt;pre name="code" class="c"&gt;&lt;br /&gt;std::string function(Interface &amp;i)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Si queremos asegurarnos que el parámetro no se modifica, habría que pasarlo como referencia constante.&lt;br /&gt;&lt;pre name="code" class="c"&gt;&lt;br /&gt;std::string function(const Interface &amp;i)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Esto plantea un nuevo problema, generando un error de compilación similar a: "&lt;span style="font-style:italic;"&gt;passing 'const Interface' as 'this' argument of 'virtual int Interface::method(int)' discards qualifiers&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;No se puede llamar a una función no constante desde un objeto constante. Para solucionarlo los métodos de la interfaz deberían ser constantes, quedando como sigue.&lt;br /&gt;&lt;pre name="code" class="c"&gt;&lt;br /&gt;class Interface{&lt;br /&gt;    public:&lt;br /&gt;        virtual int method(int param) const = 0;&lt;br /&gt;        virtual ~Interface(){};&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;class ClassA : public Interface{&lt;br /&gt;    public:&lt;br /&gt;        int method(int param) const{return param+1;};&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;class ClassB : public Interface{&lt;br /&gt;    public:&lt;br /&gt;        int method(int param) const{return param+2;};&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-5591191681674354054?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/5591191681674354054/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=5591191681674354054&amp;isPopup=true' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/5591191681674354054'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/5591191681674354054'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/07/como-implementar-interfaces-en-c.html' title='Como implementar interfaces en C++'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-919766647834839617</id><published>2010-07-05T21:06:00.003+02:00</published><updated>2010-07-05T21:16:49.350+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Definición de funciones parciales</title><content type='html'>La definición de funciones parciales (&lt;a href="http://es.wikipedia.org/wiki/Currificaci%C3%B3n"&gt;currificación&lt;/a&gt;) es una técnica de la programación funcional poco extendida.&lt;br /&gt;&lt;br /&gt;A una función parcial con dos parámetros, se le puede pasar tan solo una variable, obteniendo como resultado de la ejecución otra función con una variable a la que ya se le a aplicado el primer parámetro. Por ejemplo, scala tiene una sintaxis muy simple para llevar a cabo esta técnica.&lt;br /&gt;&lt;pre name="code" class="c"&gt;&lt;br /&gt;def function(x:Int)(y:Int) = x+y&lt;br /&gt;&lt;br /&gt;val partial = function(3)_&lt;br /&gt;&lt;br /&gt;partial(4)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Como resultado de la evaluación parcial (es obligatorio en scala acabarla con '_') se obtiene una función que solo necesita el segundo parámetro para ser evaluada.&lt;br /&gt;&lt;br /&gt;Esta técnica puede servir para ahorrar código, modelar inyección de dependencia o reducir interfaces de un conjunto de funciones haciéndolas más sencillas.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-919766647834839617?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/919766647834839617/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=919766647834839617&amp;isPopup=true' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/919766647834839617'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/919766647834839617'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/07/definicion-de-funciones-parciales.html' title='Definición de funciones parciales'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-5898490034307587509</id><published>2010-06-30T22:26:00.002+02:00</published><updated>2010-06-30T22:39:34.030+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='redes'/><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Creación de servidores en javascript</title><content type='html'>Aunque javascript está diseñado para ejecutarse en el cliente al cargar páginas web, no está limitado a este ámbito.&lt;br /&gt;Existe un proyecto llamado &lt;a href="http://en.wikipedia.org/wiki/CommonJS"&gt;CommonJS&lt;/a&gt; que amplia la funcionalidad del lenguaje haciéndole poder interactuar con el sistema como un lenguaje más.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://nodejs.org/"&gt;node.js&lt;/a&gt; es un framework para la creación de servidores que se apoya en la librería CommonJS.&lt;br /&gt;Está construido completamente siguiendo la filosofía "event-loop" y todas las operaciones I/O se realizan de manera asíncrona para una buen aprovechamiento de la concurrencia del sistema.&lt;br /&gt;&lt;br /&gt;Así pues, node.js permite crear servidores optimizados de forma sencilla desde un lenguaje dinámico como javascript, un ejemplo muy simple de un servidor creado con node.js es el siguiente:&lt;br /&gt;&lt;pre name="code" class="javascript"&gt;&lt;br /&gt;var sys = require('sys');&lt;br /&gt;var net = require('net');&lt;br /&gt;&lt;br /&gt;var acc = 0;&lt;br /&gt;&lt;br /&gt;net.createServer(function (socket) {&lt;br /&gt; socket.setEncoding("utf8");&lt;br /&gt; socket.addListener("connect", function () {&lt;br /&gt;  socket.write("Accumulator server\r\n");&lt;br /&gt;  socket.write("Accumulator value: " + acc + '\n');&lt;br /&gt; });&lt;br /&gt; socket.addListener("data", function (data) {&lt;br /&gt;  var input = parseInt(data);&lt;br /&gt;  if(!isNaN(input)){acc += parseInt(data);}&lt;br /&gt;  socket.write("Accumulator value: " + acc + '\n');&lt;br /&gt; });&lt;br /&gt; socket.addListener("end", function () {&lt;br /&gt;     socket.end();&lt;br /&gt;   });&lt;br /&gt;}).listen(8888, "127.0.0.1");&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Se  puede consultar en mayor profundidad el &lt;a href="http://nodejs.org/api.html"&gt;API&lt;/a&gt; oficial.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-5898490034307587509?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/5898490034307587509/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=5898490034307587509&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/5898490034307587509'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/5898490034307587509'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/06/creacion-de-servidores-en-javascript.html' title='Creación de servidores en javascript'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-2345199071078928298</id><published>2010-06-16T22:25:00.004+02:00</published><updated>2010-06-16T22:43:17.596+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Nuevos tipos de formularios en html5</title><content type='html'>Con el salto a la nueva versión de html se van añadir nuevos tipos de entradas posibles a los formularios.&lt;br /&gt;Por ejemplo, crear un 'slider' para seleccionar un rango se limitará a dar el tipo &lt;span style="font-style:italic;"&gt;range&lt;/span&gt; a un &lt;span style="font-style:italic;"&gt;input&lt;/span&gt;.&lt;br /&gt;&lt;pre name="code" class="c"&gt;&lt;br /&gt;&amp;lt;input type="range" min="0" max="100" step="2"&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Este componente enriquece la interfaz de usuario, hay otros aún más útiles, por ejemplo el siguiente indica que la entrada debe ser de tipo numérico, esto puede ayudar a dispositivos móviles con pantallas reducidas a desplegar tan solo un teclado con números, aprovechando mejor el espacio.&lt;br /&gt;&lt;pre name="code" class="c"&gt;&lt;br /&gt;&amp;lt;input required type="number" min="0" step="1" &amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;También sirve el tipo email para idénticos propósitos. Además de esta forma los navegadores pueden añadir mayor integración (si conocen que el tipo de entrada es email pueden sugerir los de nuestra libreta de direcciones).&lt;br /&gt;&lt;br /&gt;Otro tipo de entradas muy comunes son las de fecha, en buscadores de reservas de hoteles, vuelos, etc. La mayoría de webmaster solucionan el problema de mostrar un calendario con javascript.&lt;br /&gt;En html5 se deja este la responsabilidad de representar estos tipos de entradas a los navegadores, habiendo &lt;span style="font-style:italic;"&gt;inputs&lt;/span&gt; de tipo &lt;span style="font-style:italic;"&gt;date, month, week, time&lt;/span&gt;...&lt;br /&gt;&lt;br /&gt;Para más &lt;a href="http://www.w3.org/TR/html5/forms.html"&gt;información&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-2345199071078928298?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/2345199071078928298/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=2345199071078928298&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/2345199071078928298'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/2345199071078928298'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/06/nuevos-tipos-de-formularios-en-html5.html' title='Nuevos tipos de formularios en html5'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-4494158848422635488</id><published>2010-06-13T11:03:00.004+02:00</published><updated>2010-06-13T11:20:13.960+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Hot swapping en erlang</title><content type='html'>Hot swapping en un entorno con múltiples procesos distribuidos se refiere a la actualización de uno de esos procesos sin parar en ningún momento el sistema.&lt;br /&gt;&lt;br /&gt;Si se encuentra algún error en el software, o se necesita añadir nueva funcionalidad, el proceso afectado encola las peticiones nuevas que van llegando, actualiza su código y con el nuevo código sigue atendiendo a las peticiones que tenía encoladas. Los demás procesos del sistema no notan nada de este cambio.&lt;br /&gt;&lt;br /&gt;En muchas de las tecnologías usadas hoy en día, todo este proceso es bastante complejo, sin embargo, en erlang es trivial ya que lo soporta de forma nativa el lenguaje.&lt;br /&gt;&lt;br /&gt;Supongamos dos procesos, uno que sirve datos.&lt;br /&gt;&lt;pre name="code" class="c"&gt;&lt;br /&gt;-module(data).&lt;br /&gt;-export([get/0, version/0]).&lt;br /&gt;&lt;br /&gt;get() -&amp;gt; 42.&lt;br /&gt;&lt;br /&gt;version() -&amp;gt; 1.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Y otro que los consume.&lt;br /&gt;&lt;pre name="code" class="c"&gt;&lt;br /&gt;-module(consumer).&lt;br /&gt;-compile(export_all).&lt;br /&gt;&lt;br /&gt;start() -&amp;gt; spawn(fun() -&amp;gt; loop() end).&lt;br /&gt;&lt;br /&gt;loop() -&amp;gt;&lt;br /&gt; sleep(),&lt;br /&gt; io:format("Value: ~p at version: ~p~n", [data:get(), data:version()]),&lt;br /&gt; loop().&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;sleep() -&amp;gt;&lt;br /&gt; receive&lt;br /&gt;  after 1000 -&amp;gt; true&lt;br /&gt; end.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;El proceso consumidor irá mostrando cada segundo los datos que le manda el otro proceso. En el momento que se necesite cambiar la funcionalidad del proceso creador de datos, simplemente se recompila y el consumidor el único cambio que notará es el valor que tienen los nuevos datos.&lt;br /&gt;&lt;pre name="code" class="c"&gt;&lt;br /&gt;1&gt; c(data).&lt;br /&gt;{ok,data}&lt;br /&gt;2&gt; c(consumer).&lt;br /&gt;{ok,consumer}&lt;br /&gt;3&gt; consumer:start().&lt;br /&gt;&lt;0.53.0&gt;&lt;br /&gt;Value: 42 at version: 1&lt;br /&gt;Value: 42 at version: 1&lt;br /&gt;Value: 42 at version: 1&lt;br /&gt;Value: 42 at version: 1&lt;br /&gt;Value: 42 at version: 1&lt;br /&gt;...&lt;br /&gt;c(data).&lt;br /&gt;{ok,data}&lt;br /&gt;Value: 43 at version: 2&lt;br /&gt;Value: 43 at version: 2&lt;br /&gt;Value: 43 at version: 2&lt;br /&gt;Value: 43 at version: 2&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;En entornos críticos o en los que el sistema completo tarda mucho tiempo en arrancar, esto permite actualizar código sin que haya que mantener el servicio parado mientras se actualilza.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-4494158848422635488?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/4494158848422635488/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=4494158848422635488&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/4494158848422635488'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/4494158848422635488'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/06/hot-swapping-en-erlang.html' title='Hot swapping en erlang'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-5092015042019566599</id><published>2010-06-10T22:46:00.003+02:00</published><updated>2010-06-10T23:07:26.934+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Código Thread-Safe vs Código reentrante</title><content type='html'>Estos dos conceptos son habitualmente confundidos y, aunque están relacionados se corresponden a propiedades distintas.&lt;br /&gt;&lt;br /&gt;Una función es thread-safe cuando se le puede llamar desde múltiples hilos concurrentemente, la ejecución terminará correctamente sin que unos hilos interfieran con otros.&lt;br /&gt;&lt;br /&gt;Una función reentrante es aquella a la que se le pasa como parámetro todos los valores que usa, no utiliza ningún objeto global (variable global, singleton), no tiene efectos secundarios y no llama a ninguna función no reentrante.&lt;br /&gt;&lt;br /&gt;Una función reentrante será siempre thread-safe, si no hace ningún cambio en el estado global de un programa no hay posibilidad que interceda con el código de otra hebra.&lt;br /&gt;&lt;br /&gt;¿Y al contrario? Una función thread-safe no tiene porqué ser reentrante, ya que puede modificar el estado global del programa siempre que lo haga ordenadamente mediante exclusión mutua.&lt;br /&gt;&lt;br /&gt;Una función reentrante cumplirá además con la transparencia referencial. Transparencia referencial es una propiedad que se cumple cuando, al cambiar una función con sus parámetros por el valor que devuelve, el programa se comporta de la misma forma.&lt;br /&gt;&lt;br /&gt;Este tipo de funciones (reentrantes) tienen la ventaja de que se puede seguir su funcionamiento matemáticamente y que admiten &lt;a href="http://en.wikipedia.org/wiki/Memoization"&gt;memoization&lt;/a&gt; como  optimización. Un ejemplo &lt;a href="http://javiyu.blogspot.com/2008/11/memoization-en-ruby.html"&gt;aquí&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-5092015042019566599?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/5092015042019566599/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=5092015042019566599&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/5092015042019566599'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/5092015042019566599'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/06/codigo-thread-safety-vs-codigo.html' title='Código Thread-Safe vs Código reentrante'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-3202649434522347601</id><published>2010-06-06T10:03:00.004+02:00</published><updated>2010-06-06T10:22:24.187+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Ejecución de código remoto con ruby</title><content type='html'>Existe una librería llamada &lt;a href="http://msgpack.sourceforge.net/"&gt;msgpack&lt;/a&gt; que permite la ejecución remota de código ruby (entre otros lenguajes), lo que más destaca de esta librería es su sencillez y la poca configuración necesaria para funcionar.&lt;br /&gt;&lt;br /&gt;En un ejemplo cliente/servidor, el servidor es una instancia de una clase que contiene los métodos que queremos ejecutar de forma remota. Además de eso tan solo tenemos que elegir a qué clientes escuchamos y en qué puerto.&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;&lt;br /&gt;require 'rubygems'&lt;br /&gt;require 'msgpack/rpc'&lt;br /&gt;&lt;br /&gt;class RemoteServer&lt;br /&gt; def printer(arg)&lt;br /&gt;  puts "Printing: #{arg}..."&lt;br /&gt;  return true&lt;br /&gt; end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;server = MessagePack::RPC::Server.new&lt;br /&gt;server.listen('0.0.0.0', 8888, RemoteServer.new)&lt;br /&gt;server.run&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Un cliente que se conecte al servidor anterior sería el siguiente.&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;&lt;br /&gt;require 'rubygems'&lt;br /&gt;require 'msgpack/rpc'&lt;br /&gt;  &lt;br /&gt;client = MessagePack::RPC::Client.new('127.0.0.1', 8888)  &lt;br /&gt;called = client.call_async(:printer, 'message')&lt;br /&gt;result = called.get&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;La llamada &lt;span style="font-style:italic;"&gt;call_async&lt;/span&gt; hace que se ejecute el método de forma asíncrona, si necesitamos el valor devuelto por la función será necesario llamar a &lt;span style="font-style:italic;"&gt;get&lt;/span&gt; que se asegura de la terminación del método y de recoger el resultado. &lt;br /&gt;También se puede ejecutar código de forma síncrona con &lt;span style="font-style:italic;"&gt;call&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Además, la librería permite crear sesiones para reaprovechar las conexiones con el servidor.&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;&lt;br /&gt;require 'rubygems'&lt;br /&gt;require 'msgpack/rpc'&lt;br /&gt;  &lt;br /&gt;session_pool = MessagePack::RPC::SessionPool.new&lt;br /&gt;client = session_pool.get_session('127.0.0.1', 8888)&lt;br /&gt;result = client.call(:printer, 'message')&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-3202649434522347601?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/3202649434522347601/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=3202649434522347601&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3202649434522347601'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3202649434522347601'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/06/ejecucion-de-codigo-remoto-con-ruby.html' title='Ejecución de código remoto con ruby'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-3898650113675334465</id><published>2010-06-03T22:25:00.002+02:00</published><updated>2010-06-03T22:31:53.612+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Solución al problema de la inclusión cíclica en C++</title><content type='html'>En aplicaciones complejas se puede dar el caso de que una clase(&lt;span style="font-style:italic;"&gt;Class1&lt;/span&gt;) haga uso de otra(&lt;span style="font-style:italic;"&gt;Class2&lt;/span&gt;), pero a su vez esta última haga uso de la primera.&lt;br /&gt;&lt;br /&gt;En este caso estamos ante un problema de definición cíclica, para definir una clase se necesita la otra y viceversa. Se ejemplifica en el siguiente código.&lt;br /&gt;&lt;pre name="code" class="c"&gt;&lt;br /&gt;#ifndef CLASS1_H&lt;br /&gt;#define CLASS1_H&lt;br /&gt;&lt;br /&gt;#include "class2.h"&lt;br /&gt;&lt;br /&gt;class Class1{&lt;br /&gt; void method(Class2* param);&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;#endif&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre name="code" class="c"&gt;&lt;br /&gt;#ifndef CLASS2_H&lt;br /&gt;#define CLASS2_H&lt;br /&gt;&lt;br /&gt;#include "class1.h"&lt;br /&gt;&lt;br /&gt;class Class2{&lt;br /&gt; void method(Class1* param);&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;#endif&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Para solucionar este problema, podemos indicarle al compilador que la clase existe y será definida más adelante, así, aún teniendo dependencia cíclica se puede generar el código correctamente.&lt;br /&gt;Para indicarselo al compilador tan solo hay que definir &lt;span style="font-style:italic;"&gt;class Clase&lt;/span&gt; antes de usarla.&lt;br /&gt;&lt;pre name="code" class="c"&gt;&lt;br /&gt;#ifndef CLASS1_H&lt;br /&gt;#define CLASS1_H&lt;br /&gt;&lt;br /&gt;#include "class2.h"&lt;br /&gt;&lt;br /&gt;class Class2;&lt;br /&gt;&lt;br /&gt;class Class1{&lt;br /&gt; void method(Class2* param);&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;#endif&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre name="code" class="c"&gt;&lt;br /&gt;#ifndef CLASS2_H&lt;br /&gt;#define CLASS2_H&lt;br /&gt;&lt;br /&gt;#include "class1.h"&lt;br /&gt;&lt;br /&gt;class Class1;&lt;br /&gt;&lt;br /&gt;class Class2{&lt;br /&gt; void method(Class1* param);&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;#endif&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-3898650113675334465?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/3898650113675334465/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=3898650113675334465&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3898650113675334465'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3898650113675334465'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/06/solucion-al-problema-de-la-inclusion.html' title='Solución al problema de la inclusión cíclica en C++'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-986311292538799411</id><published>2010-06-02T22:51:00.002+02:00</published><updated>2010-06-02T23:02:27.761+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='bases de datos'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Web SQL en html 5</title><content type='html'>Con la llegada de html 5 los navegadores pondrán a disposición de los programadores web la tecnología &lt;a href="http://www.w3.org/TR/webdatabase/"&gt;web SQL&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Esta tecnología consiste básicamente en una base de datos local a los navegadores accesible desde javascript. Permitirá que las aplicaciones web puedan hacer mayor trabajo offline y sincronizarse cada cierto tiempo con el servidor.&lt;br /&gt;&lt;br /&gt;El acceso a estas bases de datos se hace mediante SQL.&lt;br /&gt;Para abrir una base de datos se necesita ejecutar lo siguiente.&lt;br /&gt;&lt;pre name="code" class="c:nocontrols"&gt;&lt;br /&gt;function openDB(dbName){&lt;br /&gt; var version = 1;&lt;br /&gt; var db = window.openDatabase(dbName, version, dbName, 2*1024);&lt;br /&gt; return db;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Una vez abierta la base de datos para ejecutar SQL podemos disponer de las siguientes funciones.&lt;br /&gt;&lt;pre name="code" class="c:nocontrols"&gt;&lt;br /&gt;function executeSQL(db, sqlString, args){&lt;br /&gt;  db.transaction(function(t){&lt;br /&gt;    t.executeSql(sqlString, args);&lt;br /&gt;  }); &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function executeSQL(db, sqlString, args, callback){&lt;br /&gt;  db.transaction(function(t){&lt;br /&gt;    t.executeSql(sqlString, args, callback);&lt;br /&gt;  }); &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Se puede pasar opcionalmente un callback a la función &lt;span style="font-style:italic;"&gt;executeSQL&lt;/span&gt;, es especialmente útil en las consultas para tratar el resultado. Un ejemplo de callback para consultas es &lt;span style="font-style:italic;"&gt;showEntries&lt;/span&gt; definida más adelante.&lt;br /&gt;Este es un ejemplo típico de uso de web SQL.&lt;br /&gt;&lt;pre name="code" class="c:nocontrols"&gt;&lt;br /&gt;function insertEntry(db, name){&lt;br /&gt; executeSQL(db, "INSERT INTO entries(name) VALUES (?)", [name]);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function selectAllEntries(db, callback){&lt;br /&gt; executeSQL(db, "SELECT * FROM entries", [], callback);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function showEntries(t, rs){&lt;br /&gt; var entry;&lt;br /&gt; &lt;br /&gt; for(var i=0; i&amp;lt;rs.rows.length; i++){&lt;br /&gt;  entry = rs.rows.item(i);&lt;br /&gt;  alert(entry['name']);&lt;br /&gt;    } &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;var db = openDB("example");&lt;br /&gt;executeSQL(db, "CREATE TABLE IF NOT EXISTS entries(id INTEGER PRIMARY KEY, name TEXT)", []);&lt;br /&gt;&lt;br /&gt;for(var i=0; i&amp;lt;10; i++){&lt;br /&gt; insertEntry(db, "test"+i);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;selectAllEntries(db, showEntries);&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-986311292538799411?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/986311292538799411/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=986311292538799411&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/986311292538799411'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/986311292538799411'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/06/web-sql-en-html-5.html' title='Web SQL en html 5'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-1083758970461017681</id><published>2010-05-25T22:23:00.003+02:00</published><updated>2010-05-25T22:31:29.094+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Modificar bases de datos en android</title><content type='html'>Casi todas las apliaciones android guardan información en bases de datos, el propio teléfono soporta nativamente &lt;a href="http://en.wikipedia.org/wiki/SQLite3"&gt;SQLite3&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Las bases de datos se guardan en el directorio &lt;span style="font-style:italic;"&gt;/data/data/nombre.paquete.programa/databases/&lt;/span&gt;&lt;br /&gt;Para copiar una base de datos del teléfono al ordenador tan solo hay que hacer (tras tener el android SDK instalado).&lt;br /&gt;&lt;pre name="code" class="c:nocontrols"&gt;&lt;br /&gt;adb pull /data/data/nombre.paquete.programa/databases/example_database.db .&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Una vez en el ordenador se pueden hacer las comprobaciones que se necesiten con cualquier cliente sqlite3.&lt;br /&gt;&lt;br /&gt;Para pasar de nuevo la base de datos modificada al móvil se puede hacer con el siguiente comando.&lt;br /&gt;&lt;pre name="code" class="c:nocontrols"&gt;&lt;br /&gt;adb push example_database.db /data/data/nombre.paquete.programa/databases/&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-1083758970461017681?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/1083758970461017681/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=1083758970461017681&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/1083758970461017681'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/1083758970461017681'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/05/modificacion-de-bases-de-datos-en.html' title='Modificar bases de datos en android'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-1427275765202737141</id><published>2010-05-22T17:50:00.004+02:00</published><updated>2010-05-22T18:18:39.815+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Functors en C++</title><content type='html'>Los &lt;span style="font-style:italic;"&gt;functors&lt;/span&gt; se definen como '&lt;span style="font-style:italic;"&gt;objetos función&lt;/span&gt;'.&lt;br /&gt;Son la evolución natural de los punteros a función de C, un ejemplo de la sintaxis para definir un functor es el siguiente.&lt;br /&gt;&lt;pre name="code" class="c:nocontrols"&gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;#include &amp;lt;string&amp;gt;&lt;br /&gt;#include &amp;lt;cmath&amp;gt;&lt;br /&gt;&lt;br /&gt;using namespace std;&lt;br /&gt;&lt;br /&gt;class PrinterFunctor{&lt;br /&gt;    private:&lt;br /&gt;     string msg;&lt;br /&gt;&lt;br /&gt;    public:&lt;br /&gt;     PrinterFunctor(string _msg){&lt;br /&gt;         msg = _msg;&lt;br /&gt;    }&lt;br /&gt;  &lt;br /&gt;     void operator()(){&lt;br /&gt;        cout &amp;lt;&amp;lt; msg &amp;lt;&amp;lt; endl; &lt;br /&gt;    }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;int main() {&lt;br /&gt;    PrinterFunctor pf("Printing from printer functor");&lt;br /&gt;    pf();&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Para crear un functor simplemente hay que redefinir el operador (), tras eso podremos llamar al functor como si fuera una función más.&lt;br /&gt;&lt;br /&gt;Con un functor podemos implementar una función &lt;span style="font-style:italic;"&gt;'resumible'&lt;/span&gt;, es decir, una función que recuerde el estado anterior para producir el siguiente. Por ejemplo.&lt;br /&gt;&lt;pre name="code" class="c:nocontrols"&gt;&lt;br /&gt;class PrimeGenerator{&lt;br /&gt; private:&lt;br /&gt;  int currentPrime;&lt;br /&gt;&lt;br /&gt; public:&lt;br /&gt;  PrimeGenerator(int _prime){&lt;br /&gt;   currentPrime = _prime;&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  bool isPrime(int n){&lt;br /&gt;   int root = (int) sqrt(n);&lt;br /&gt;   &lt;br /&gt;   for(int i=2; i&amp;lt;root+1; i++){&lt;br /&gt;    if(n%i==0) return false;&lt;br /&gt;   }&lt;br /&gt;   &lt;br /&gt;   return true;&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  int operator()(){&lt;br /&gt;   int n = currentPrime;&lt;br /&gt;   &lt;br /&gt;   while(1){&lt;br /&gt;    n++;    &lt;br /&gt;    if(isPrime(n)){&lt;br /&gt;     currentPrime = n;&lt;br /&gt;     return currentPrime;&lt;br /&gt;    }&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Esta clase devolverá el siguiente número primo cada vez que la llamemos, si hacemos lo siguiente generará los 100 primeros números primos empezando por 5.&lt;br /&gt;&lt;pre name="code" class="c:nocontrols"&gt;&lt;br /&gt;int main() {&lt;br /&gt;    PrimeGenerator primeGenerator(5);&lt;br /&gt;    for(int i=0; i&amp;lt;100; i++){&lt;br /&gt;         cout &amp;lt;&amp;lt; primeGenerator() &amp;lt;&amp;lt; endl;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-1427275765202737141?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/1427275765202737141/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=1427275765202737141&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/1427275765202737141'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/1427275765202737141'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/05/functors-en-c.html' title='Functors en C++'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-4151176601725256241</id><published>2010-05-16T16:45:00.004+02:00</published><updated>2010-05-16T16:56:45.315+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='proyectos'/><title type='text'>Wingedbox</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://wingedbox.com"&gt;&lt;img style="fmargin:10px;cursor:pointer; cursor:hand;width: 300px; height: 227px;" src="http://3.bp.blogspot.com/_bzWVuOyZiKo/S-sldffkDTI/AAAAAAAAF7g/HuSBmduJDf8/s320/logo.png" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;Este post es para anunciar la salida de un nuevo proyecto, &lt;a href="http://www.wingedbox.com"&gt;wingedbox&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Es un proyecto lanzado por &lt;a href="http://kikorb.blogspot.com"&gt;kikorb&lt;/a&gt; y por mí (javiyu). El concepto detrás de esta nueva web es compartir ficheros de una forma más ágil con tus amigos, no encontramos nada que encajara con nuestras necesidades así que decidimos hacerlo nosotros mismos.&lt;br /&gt;&lt;br /&gt;Se le ha llamado "twitter de ficheros" de forma bastante acertada, ya que describe bastante bien la funcionalidad básica. Aún está en fase alpha pero realmente está teniendo muy buena acogida.&lt;br /&gt;&lt;br /&gt;Pronto saldrá tanto el API público entre otras novedades, ya están disponible la visualización online de imágenes y fotos y el streaming de música.&lt;br /&gt;&lt;br /&gt;Aún no tenemos buzón de sugerencias en la web, así que si tenéis algún tipo de duda o sugerencia podéis escribir un email tanto a kikorb como a mí.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-4151176601725256241?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/4151176601725256241/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=4151176601725256241&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/4151176601725256241'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/4151176601725256241'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/05/wingedbox.html' title='Wingedbox'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_bzWVuOyZiKo/S-sldffkDTI/AAAAAAAAF7g/HuSBmduJDf8/s72-c/logo.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-8123630622857173668</id><published>2010-05-15T11:26:00.003+02:00</published><updated>2010-05-15T11:48:58.343+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Bloques with de python</title><content type='html'>En Java es muy común la combinación de bloques &lt;span style="font-style:italic;"&gt;try catch finally&lt;/span&gt; para obtener/liberar recursos de forma segura.&lt;br /&gt;&lt;br /&gt;En python hay otra forma más elegante de hacerlo.&lt;br /&gt;&lt;pre name="code" class="c:nocontrols"&gt;&lt;br /&gt;class database_connection:&lt;br /&gt;        def __enter__(self):&lt;br /&gt;                print("Open database connection")&lt;br /&gt;                return 1&lt;br /&gt;        def __exit__(self, type, value, traceback):&lt;br /&gt;                print("Close database connection")&lt;br /&gt;&lt;br /&gt;with database_connection() as db:&lt;br /&gt; print(db)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Al definirnos una clase con los métodos &lt;span style="font-style:italic;"&gt;__enter__&lt;/span&gt; y &lt;span style="font-style:italic;"&gt;__exit__&lt;/span&gt; y ejecutarla en un bloque with se nos asegura que:&lt;br /&gt;&lt;br /&gt;1) Al entrar al bloque se ha ejecutado el método &lt;span style="font-style:italic;"&gt;__enter__&lt;/span&gt;.&lt;br /&gt;2) Tanto si hay un error en el bloque with como si termina correctamente, los recursos serán liberados (llamada a la función &lt;span style="font-style:italic;"&gt;__exit__&lt;/span&gt;).&lt;br /&gt;3) Opcionalemente se puede devolver un valor para usarlo dentro del bloque (en este caso db), aunque no es obligatorio.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-8123630622857173668?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/8123630622857173668/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=8123630622857173668&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/8123630622857173668'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/8123630622857173668'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/05/en-java-es-muy-comun-la-combinacion-de.html' title='Bloques with de python'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-7925296872572289625</id><published>2010-05-03T23:15:00.002+02:00</published><updated>2010-05-03T23:25:30.121+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Web Storage, sessionStorage y localStorage en html 5</title><content type='html'>Con el nuevo estándar html 5 se ha introducido el concepto de &lt;a href="http://dev.w3.org/html5/webstorage/"&gt;&lt;span style="font-style:italic;"&gt;web storage&lt;/span&gt;&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Mediante el objeto &lt;span style="font-style:italic;"&gt;sessionStorage&lt;/span&gt; se puede guardar información relativa solo a la ventana actual, es decir, a diferencia de las cookies, aunque tengamos dos ventanas del navegador abiertas en una pagina del mismo dominio, la variable &lt;span style="font-style:italic;"&gt;sessionStorage&lt;/span&gt; será única para cada ventana.&lt;br /&gt;La sintaxis es muy sencilla, para guardar el email del usuario se puede hacer algo como lo siguiente.&lt;br /&gt;&lt;pre name="code" class="c:nocontrols"&gt;&lt;br /&gt;sessionStorage.email='mail@sever.com'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Para recuperarlo después tan solo hay que ejecutar:&lt;br /&gt;&lt;pre name="code" class="c:nocontrols"&gt;&lt;br /&gt;sessionStorage.email&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Con el objeto &lt;span style="font-style:italic;"&gt;localStorage&lt;/span&gt; se guarda información en local de forma permanente, entre ventanas del navegador, de forma global y por dominio. La sintaxis para utilizarlo es similar a la de &lt;span style="font-style:italic;"&gt;sessionStorage&lt;/span&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-7925296872572289625?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/7925296872572289625/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=7925296872572289625&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/7925296872572289625'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/7925296872572289625'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/05/web-storage-sessionstorage-y.html' title='Web Storage, sessionStorage y localStorage en html 5'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-151270480777161900</id><published>2010-05-01T16:19:00.003+02:00</published><updated>2010-05-01T16:31:50.010+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><category scheme='http://www.blogger.com/atom/ns#' term='ensamblador'/><title type='text'>Compilar a código ensamblador en formato intel con gcc</title><content type='html'>Aunque por defecto &lt;span style="font-style:italic;"&gt;gcc&lt;/span&gt; produce código ensamblador con sintaxis AT&amp;T al pasar la opción &lt;span style="font-style:italic;"&gt;-S&lt;/span&gt; también es posible hacer que la salida sea con formato Intel.&lt;br /&gt;&lt;br /&gt;Tan solo hay que ejecutar el siguiente comando.&lt;br /&gt;&lt;pre name="code" class="c:nocontrols"&gt;&lt;br /&gt;gcc -S -masm=intel proc.c&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Realizar las modificaciones que sean necesarias y después para hacer el enlazado.&lt;br /&gt;&lt;pre name="code" class="c:nocontrols"&gt;&lt;br /&gt;gcc prog.s -o prog&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-151270480777161900?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/151270480777161900/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=151270480777161900&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/151270480777161900'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/151270480777161900'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/05/compilar-codigo-ensamblador-en-formato.html' title='Compilar a código ensamblador en formato intel con gcc'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-2472467631023416839</id><published>2010-04-24T23:29:00.002+02:00</published><updated>2010-04-24T23:47:33.844+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><category scheme='http://www.blogger.com/atom/ns#' term='c'/><category scheme='http://www.blogger.com/atom/ns#' term='ensamblador'/><title type='text'>Ensamblador inline en código C</title><content type='html'>Para incluir código ensamblador en un programa escrito en C la sintaxis es la siguiente.&lt;br /&gt;&lt;pre name="code" class="c:nocontrols"&gt;&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;&lt;br /&gt;int main(){&lt;br /&gt; int var1 = 1;&lt;br /&gt; int var2;&lt;br /&gt; int var3;&lt;br /&gt; &lt;br /&gt; __asm__(&lt;br /&gt;  "inc %%eax \n\t"&lt;br /&gt;  "movl %%eax, %%ecx \n\t"&lt;br /&gt;  "inc %%ecx \n\t"&lt;br /&gt;  :"=a" (var2), "=c" (var3)&lt;br /&gt;  :"a" (var1)&lt;br /&gt; );&lt;br /&gt;&lt;br /&gt; printf("Value1: %d\n", var1);&lt;br /&gt; printf("Value2: %d\n", var2);&lt;br /&gt; printf("Value3: %d\n", var3);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Los paréntesis se escriben dobles para escapar el carácter '%' ya que en C es un modificador de cadena.&lt;br /&gt;&lt;br /&gt;Todas las líneas acaban en '\n\t' para que el código en ensamblador quede formateado igual que el resto.&lt;br /&gt;&lt;br /&gt;Los registros no se usan con el nombre como tal para las entrada/salida, se usan alias del tipo "a=eax, b=ebx, c=ecx...".&lt;br /&gt;&lt;br /&gt;En el primer apartado &lt;span style="font-style:italic;"&gt;"=a" (var2), "=c" (var3)&lt;/span&gt; se les está diciendo que el contenido final de eax lo lleve a &lt;span style="font-style:italic;"&gt;var2&lt;/span&gt; y el contenido de &lt;span style="font-style:italic;"&gt;ecx&lt;/span&gt; lo lleve a &lt;span style="font-style:italic;"&gt;var3&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;En el segundo apartado &lt;span style="font-style:italic;"&gt;"a" (var1)&lt;/span&gt; se le dice que se comience el bloque copiando el valor de &lt;span style="font-style:italic;"&gt;var1&lt;/span&gt; a &lt;span style="font-style:italic;"&gt;eax&lt;/span&gt;, actuará como entrada.&lt;br /&gt;&lt;br /&gt;El compilador da por hecho que los registros usados para entrada/salida del bloque en ensamblador no los puede reutilizar, pero si se utilizan más registros se pueden poner en un tercer apartado de forma opcional.&lt;br /&gt;&lt;br /&gt;El bloque ensamblador escrito antes, hará lo siguiente:&lt;br /&gt;&lt;br /&gt;1. Copia el valor de &lt;span style="font-style:italic;"&gt;var1&lt;/span&gt; a &lt;span style="font-style:italic;"&gt;eax&lt;/span&gt;.&lt;br /&gt;2. Incrementa el valor de &lt;span style="font-style:italic;"&gt;eax&lt;/span&gt; en 1.&lt;br /&gt;3. Copia el contenido de &lt;span style="font-style:italic;"&gt;eax&lt;/span&gt; a &lt;span style="font-style:italic;"&gt;ecx&lt;/span&gt;.&lt;br /&gt;4. Aumenta el valor de &lt;span style="font-style:italic;"&gt;ecx&lt;/span&gt; en 1.&lt;br /&gt;5. Copia el valor de &lt;span style="font-style:italic;"&gt;eax&lt;/span&gt; a &lt;span style="font-style:italic;"&gt;var2&lt;/span&gt;.&lt;br /&gt;6. Copia el valor de &lt;span style="font-style:italic;"&gt;ecx&lt;/span&gt; a &lt;span style="font-style:italic;"&gt;var3&lt;/span&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-2472467631023416839?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/2472467631023416839/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=2472467631023416839&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/2472467631023416839'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/2472467631023416839'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/04/ensamblador-inline-en-codigo-c.html' title='Ensamblador inline en código C'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-651965872360548937</id><published>2010-04-20T22:28:00.005+02:00</published><updated>2010-04-20T22:57:44.505+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c'/><category scheme='http://www.blogger.com/atom/ns#' term='ensamblador'/><title type='text'>Position Independent Code</title><content type='html'>El &lt;span style="font-style:italic;"&gt;&lt;a href="http://en.wikipedia.org/wiki/Position-independent_code"&gt;position independent code&lt;/a&gt;&lt;/span&gt; o código no dependiente de posición es aquel que se puede reubicar en memoria y aún así seguirá funcionando correctamente.&lt;br /&gt;&lt;br /&gt;Por defecto, en Mac el código producido por gcc es &lt;span style="font-style:italic;"&gt;PIC&lt;/span&gt;, pero se puede forzar a que produzca código no &lt;span style="font-style:italic;"&gt;PIC&lt;/span&gt; con la opción &lt;span style="font-style:italic;"&gt;-fno-pic&lt;/span&gt;.&lt;br /&gt;Si tomamos por ejemplo el siguiente código en C.&lt;br /&gt;&lt;pre name="code" class="c:nocontrols"&gt;&lt;br /&gt;#include&amp;lt;stdio.h&amp;gt;&lt;br /&gt;&lt;br /&gt;void func(){&lt;br /&gt; printf("Hello again\n");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main(){&lt;br /&gt; printf("Hello world\n");&lt;br /&gt; func();&lt;br /&gt; &lt;br /&gt; return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Y lo compilamos como no PIC con la siguiente instrucción.&lt;br /&gt;&lt;pre name="code" class="c:nocontrols"&gt;&lt;br /&gt;gcc -fno-pic -S program.c -o nopic.asm&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Se obtiene.&lt;br /&gt;&lt;pre name="code" class="c:nocontrols"&gt;&lt;br /&gt; .cstring&lt;br /&gt;LC0:&lt;br /&gt; .ascii "Hello again\0"&lt;br /&gt; .text&lt;br /&gt;.globl _func&lt;br /&gt;_func:&lt;br /&gt; pushl %ebp&lt;br /&gt; movl %esp, %ebp&lt;br /&gt; subl $24, %esp&lt;br /&gt; movl $LC0, (%esp)&lt;br /&gt; call _puts&lt;br /&gt; leave&lt;br /&gt; ret&lt;br /&gt; .cstring&lt;br /&gt;LC1:&lt;br /&gt; .ascii "Hello world\0"&lt;br /&gt; .text&lt;br /&gt;.globl _main&lt;br /&gt;_main:&lt;br /&gt; pushl %ebp&lt;br /&gt; movl %esp, %ebp&lt;br /&gt; subl $24, %esp&lt;br /&gt; movl $LC1, (%esp)&lt;br /&gt; call _puts&lt;br /&gt; call _func&lt;br /&gt; movl $0, %eax&lt;br /&gt; leave&lt;br /&gt; ret&lt;br /&gt; .subsections_via_symbols&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Se puede ver que la cadena almacenada en la línea 3 se referencia en la línea 10 de forma absoluta. Si cambia la ubicación del programa en memoria LC0 seguirá referenciando a la misma posición, pero allí ya no estará la cadena que se esperaba.&lt;br /&gt;&lt;br /&gt;Por el contrario, si dejamos al compilador con las opciones por defecto, producirá código &lt;span style="font-style:italic;"&gt;PIC&lt;/span&gt;, quedando de la siguiente forma.&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="c:nocontrols"&gt;&lt;br /&gt; .cstring&lt;br /&gt;LC0:&lt;br /&gt; .ascii "Hello again\0"&lt;br /&gt; .text&lt;br /&gt;.globl _func&lt;br /&gt;_func:&lt;br /&gt; pushl %ebp&lt;br /&gt; movl %esp, %ebp&lt;br /&gt; pushl %ebx&lt;br /&gt; subl $20, %esp&lt;br /&gt; call L3&lt;br /&gt;"L00000000001$pb":&lt;br /&gt;L3:&lt;br /&gt; popl %ebx&lt;br /&gt; leal LC0-"L00000000001$pb"(%ebx), %eax&lt;br /&gt; movl %eax, (%esp)&lt;br /&gt; call L_puts$stub&lt;br /&gt; addl $20, %esp&lt;br /&gt; popl %ebx&lt;br /&gt; leave&lt;br /&gt; ret&lt;br /&gt; .cstring&lt;br /&gt;LC1:&lt;br /&gt; .ascii "Hello world\0"&lt;br /&gt; .text&lt;br /&gt;.globl _main&lt;br /&gt;_main:&lt;br /&gt; pushl %ebp&lt;br /&gt; movl %esp, %ebp&lt;br /&gt; pushl %ebx&lt;br /&gt; subl $20, %esp&lt;br /&gt; call L6&lt;br /&gt;"L00000000002$pb":&lt;br /&gt;L6:&lt;br /&gt; popl %ebx&lt;br /&gt; leal LC1-"L00000000002$pb"(%ebx), %eax&lt;br /&gt; movl %eax, (%esp)&lt;br /&gt; call L_puts$stub&lt;br /&gt; call _func&lt;br /&gt; movl $0, %eax&lt;br /&gt; addl $20, %esp&lt;br /&gt; popl %ebx&lt;br /&gt; leave&lt;br /&gt; ret&lt;br /&gt; .section __IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5&lt;br /&gt;L_puts$stub:&lt;br /&gt; .indirect_symbol _puts&lt;br /&gt; hlt ; hlt ; hlt ; hlt ; hlt&lt;br /&gt; .subsections_via_symbols&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;En esta ocasión se puede ver que en la línea 15 se carga la cadena, pero de forma relativa, usando la diferencia entre la posición actual y la de la cadena. Además, se puede ver que hay unas nuevas directivas al incluir la función &lt;span style="font-style:italic;"&gt;puts&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;¿Por qué puede preferirse la generación de código no &lt;span style="font-style:italic;"&gt;PIC&lt;/span&gt;? Pues observando los ejemplos se puede ver que generar código no dependiente de la posición del programa requiere más instrucciones en ensamblador y por tanto mayor tiempo a la hora de ejecutarse.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-651965872360548937?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/651965872360548937/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=651965872360548937&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/651965872360548937'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/651965872360548937'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/04/position-independent-code.html' title='Position Independent Code'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-9006354315148277633</id><published>2010-04-19T22:34:00.003+02:00</published><updated>2010-04-19T23:01:56.057+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ingenieria inversa'/><category scheme='http://www.blogger.com/atom/ns#' term='windows'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><title type='text'>Paso de mensajes entre procesos en windows</title><content type='html'>En la plataforma Windows tanto para la comunicación entre procesos como para el manejo de eventos se usa un sistema de mensajes.&lt;br /&gt;&lt;br /&gt;Una de las características del sistema de mensajes de Windows es no disponer de autentificación, se puede aprovechar este hecho para simular eventos en los programas que se están ejecutando y de esta forma controlarlos desde el API de mensajes.&lt;br /&gt;&lt;br /&gt;Se puede por tanto manejar un programa de forma automática desde otro, con las posibilidades que ello ofrece. Orientándolo a la ingeniería inversa se puede hacer &lt;a href="http://en.wikipedia.org/wiki/Fuzz_testing"&gt;fuzzing&lt;/a&gt; a programas que tan solo admiten entradas desde la interfaz gráfica.&lt;br /&gt;&lt;br /&gt;Supongamos que tenemos un programa cuya ventana principal se llama "Form1" y un botón con el texto "Boton" en el cual al hacer click en un botón muestra un mensaje.&lt;br /&gt;&lt;pre name="code" class="c:nocontrols"&gt;&lt;br /&gt;...&lt;br /&gt;private void button_Click(object sender, EventArgs e){&lt;br /&gt;    MessageBox.Show("Wow!", "Clicked", MessageBoxButtons.OK, MessageBoxIcon.Information);&lt;br /&gt;}&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Podemos simular que hacemos click en ese botón si desde otro programa hacemos lo siguiente.&lt;br /&gt;&lt;pre name="code" class="c:nocontrols"&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.ComponentModel;&lt;br /&gt;using System.Data;&lt;br /&gt;using System.Drawing;&lt;br /&gt;using System.Linq;&lt;br /&gt;using System.Text;&lt;br /&gt;using System.Windows.Forms;&lt;br /&gt;using System.Runtime.InteropServices;&lt;br /&gt;&lt;br /&gt;namespace WFuzzing{&lt;br /&gt;    public partial class Form2 : Form{&lt;br /&gt;        [DllImport("user32.dll", CharSet = CharSet.Auto)]&lt;br /&gt;        public static extern IntPtr FindWindow(string strClassName, string strWindowName);&lt;br /&gt;&lt;br /&gt;        [DllImport("user32.dll", CharSet = CharSet.Auto)]&lt;br /&gt;        public static extern int SendMessage(int hWnd, uint Msg, long wParam, long lParam);&lt;br /&gt;&lt;br /&gt;        [DllImport("user32.dll", CharSet = CharSet.Auto)]&lt;br /&gt;        [return: MarshalAs(UnmanagedType.Bool)]&lt;br /&gt;        static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam);&lt;br /&gt;        public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr parameter);&lt;br /&gt;&lt;br /&gt;        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]&lt;br /&gt;        static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);&lt;br /&gt;&lt;br /&gt;        public const int WM_LBUTTONDOWN = 0x0201;&lt;br /&gt;        public const int WM_LBUTTONUP = 0x0202;&lt;br /&gt;&lt;br /&gt;        public Form2(){&lt;br /&gt;            InitializeComponent();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private void fuzzbutton_Click(object sender, EventArgs e){&lt;br /&gt;            IntPtr wHandle = FindWindow(null, "Form1");&lt;br /&gt;            List&amp;lt;IntPtr&amp;gt; result = new List&amp;lt;IntPtr&amp;gt;();&lt;br /&gt;            GCHandle listHandle = GCHandle.Alloc(result);&lt;br /&gt;            EnumWindowsProc childProc = new EnumWindowsProc(EnumWindow);&lt;br /&gt;            EnumChildWindows(wHandle, childProc, GCHandle.ToIntPtr(listHandle));&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private static bool EnumWindow(IntPtr handle, IntPtr pointer){&lt;br /&gt;            StringBuilder text = new StringBuilder(256); ;&lt;br /&gt;            GetWindowText(handle, text, text.Capacity);&lt;br /&gt;            &lt;br /&gt;            if(text.ToString() == "Boton"){&lt;br /&gt;                long lngResult = SendMessage(handle.ToInt32(), WM_LBUTTONDOWN, 0, 0);&lt;br /&gt;                long lngResult2 = SendMessage(handle.ToInt32(), WM_LBUTTONUP, 0, 0);&lt;br /&gt;            }&lt;br /&gt;            return true;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Se le mandan dos mensajes, el primero el de hacer click con el ratón y el segúndo el de levantar el dedo del ratón.&lt;br /&gt;&lt;br /&gt;Al ejecutar ese código el primer programa debería mostrar el mismo mensaje que si hacemos click en el botón.&lt;br /&gt;&lt;br /&gt;De forma similar, se puede automatizar la búsqueda de fallos en programas de los cuales no disponemos del código fuente, tan solo manipulando la interfaz, rellenando campos de texto, activando y desactivando controles, todo de forma automática.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-9006354315148277633?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/9006354315148277633/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=9006354315148277633&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/9006354315148277633'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/9006354315148277633'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/04/paso-de-mensajes-entre-procesos-en.html' title='Paso de mensajes entre procesos en windows'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-5051743254075372465</id><published>2010-04-07T22:30:00.004+02:00</published><updated>2010-04-07T22:53:44.811+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><title type='text'>Metaprogramación en c#</title><content type='html'>Aunque c# no proporcione demasiadas ayudas sintácticas a la metaprogramación si que se pueden aprovechar sus estructuras y tipos de datos para generar métodos de fórma dinámica.&lt;br /&gt;&lt;br /&gt;En el siguiente código hay un ejemplo.&lt;br /&gt;&lt;pre name="code" class="c:nocontrols"&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.Linq;&lt;br /&gt;using System.Linq.Expressions;&lt;br /&gt;using System.Text;&lt;br /&gt;using System.Collections;&lt;br /&gt;using System.Runtime.InteropServices;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;namespace example1{&lt;br /&gt;    class Program{&lt;br /&gt;        [DllImport("msvcrt.dll")]&lt;br /&gt;        static extern bool system(string str);&lt;br /&gt;&lt;br /&gt;        static void Main(string[] args){&lt;br /&gt;            Dictionary&amp;lt;string, Action&amp;lt;string&amp;gt;&amp;gt; method = new Dictionary&amp;lt;string, Action&amp;lt;string&amp;gt;&amp;gt;();&lt;br /&gt;            Expression&amp;lt;Action&amp;lt;string&amp;gt;&amp;gt; exp;&lt;br /&gt;&lt;br /&gt;            for (int i = 0; i &amp;lt; 100; i++)&lt;br /&gt;            {&lt;br /&gt;                var number = i;&lt;br /&gt;                exp = (p =&amp;gt; Console.WriteLine("Parametro: " +p+"\nMetodo numero: "+number));&lt;br /&gt;                method["print_" + i] = exp.Compile();&lt;br /&gt;&lt;br /&gt;                exp = (p =&amp;gt; Console.WriteLine(p + number));&lt;br /&gt;                method["concat_" + i] = exp.Compile();&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            method["print_17"]("test");&lt;br /&gt;            method["concat_35"]("Concatenando el numero -&amp;gt; ");&lt;br /&gt;            &lt;br /&gt;&lt;br /&gt;            system("pause");&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;En primer lugar se crea un diccionario llamado &lt;span style="font-style:italic;"&gt;method&lt;/span&gt; para contener todas las funciones generadas automáticamente.&lt;br /&gt;&lt;br /&gt;Luego, en el bucle se crean 200 métodos, tanto dependientes de parámetro como de su posición en el bucle, sin embargo, para esto es necesario un pequeño &lt;span style="font-style:italic;"&gt;hack&lt;/span&gt;. &lt;br /&gt;Se le asigna a &lt;span style="font-style:italic;"&gt;number&lt;/span&gt; el valor del contador, creando un objeto en cada iteración, en caso contrario todos los métodos creados tendrán como valor de &lt;span style="font-style:italic;"&gt;i&lt;/span&gt; el último que ha tomado en el bucle, es decir, 100.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-5051743254075372465?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/5051743254075372465/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=5051743254075372465&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/5051743254075372465'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/5051743254075372465'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/04/metaprogramacion-en-c.html' title='Metaprogramación en c#'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-9116611949102033542</id><published>2010-04-06T23:50:00.003+02:00</published><updated>2010-04-07T00:04:35.634+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><category scheme='http://www.blogger.com/atom/ns#' term='boost'/><title type='text'>Expresiones regular en C++ con boost</title><content type='html'>La mayoría lenguajes de programación modernos proporcionan la posibilidad de usar expresiones regulares de forma nativa desde el propio lenguaje, sin embargo, en C++ es necesario recurrir a alguna librería como &lt;span style="font-style:italic;"&gt;&lt;a href="http://www.boost.org/doc/libs/1_42_0/libs/regex/doc/html/index.html"&gt;Boost.Regex&lt;/a&gt;&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Boost.Regex ofrece la mayoría de funciones comunes de las expresiones regulares.&lt;br /&gt;&lt;pre name="code" class="c:nocontrols"&gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;#include &amp;lt;string&amp;gt;&lt;br /&gt;#include &amp;lt;boost/regex.hpp&amp;gt;&lt;br /&gt;&lt;br /&gt;int main(){ &lt;br /&gt; std::string s = "BEGIN-&amp;gt;Cadena_entre_delimitadores&amp;lt;-END"; &lt;br /&gt; std::string s2 = "Cadena de texto con 3 numeros para sustituir 1, 4 por incognitas"; &lt;br /&gt; boost::regex r("BEGIN-&amp;gt;(\\w+)&amp;lt;-END"); &lt;br /&gt; boost::regex r2("\\d"); &lt;br /&gt; boost::smatch result; &lt;br /&gt;&lt;br /&gt; if (boost::regex_search(s, result, r)){ &lt;br /&gt;  for(int i=0; i&amp;lt;result.size(); i++){&lt;br /&gt;   std::cout &amp;lt;&amp;lt; "Ocurrencia n " &amp;lt;&amp;lt; i+1 &amp;lt;&amp;lt; ": "&amp;lt;&amp;lt; result[i] &amp;lt;&amp;lt; std::endl; &lt;br /&gt;  }  &lt;br /&gt; }&lt;br /&gt; else{&lt;br /&gt;  std::cout &amp;lt;&amp;lt; "Ninguna coincidencia" &amp;lt;&amp;lt; std::endl;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; std::cout &amp;lt;&amp;lt; "---" &amp;lt;&amp;lt; std::endl;&lt;br /&gt; std::string number("X"); &lt;br /&gt; std::cout &amp;lt;&amp;lt; "Cadena modificada con una expresion regular: ";&lt;br /&gt; std::cout &amp;lt;&amp;lt; boost::regex_replace(s2, r2, number) &amp;lt;&amp;lt; std::endl; &lt;br /&gt; &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Con &lt;span style="font-style:italic;"&gt;regex_search&lt;/span&gt; se pueden encontrar coincidencias de una expresión regular &lt;span style="font-style:italic;"&gt;r&lt;/span&gt; dentro de una cadena &lt;span style="font-style:italic;"&gt;s&lt;/span&gt;. Como resultado también tendrá en cuenta los grupos de captura.&lt;br /&gt;&lt;br /&gt;Con &lt;span style="font-style:italic;"&gt;regex_replace&lt;/span&gt; se pueden hacer sustituciones, cambiando las ocurrencias encontradas en la cadena &lt;span style="font-style:italic;"&gt;s2&lt;/span&gt; según el patrón &lt;span style="font-style:italic;"&gt;r2&lt;/span&gt;, sustituyéndolas por &lt;span style="font-style:italic;"&gt;number&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Papra compilar es necesario incluir tanto los headers como la librería correspondiente, en mi caso.&lt;br /&gt;&lt;pre name="code" class="c:nocontrols"&gt;&lt;br /&gt;g++ -lboost_regex-mt -I/opt/local/include/ -L/opt/local/lib/ regex.cpp -o regex&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-9116611949102033542?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/9116611949102033542/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=9116611949102033542&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/9116611949102033542'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/9116611949102033542'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/04/expresiones-regular-en-c-con-boost.html' title='Expresiones regular en C++ con boost'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-4665097258833045070</id><published>2010-03-19T12:15:00.005+01:00</published><updated>2010-03-19T12:29:12.884+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><category scheme='http://www.blogger.com/atom/ns#' term='boost'/><title type='text'>Programación de callbacks con Boost</title><content type='html'>Usando las librerías Boost.Function y Boost.Bind se pueden crear fácilmente callbacks en c++ sin necesidad de usar punteros a función.&lt;br /&gt;&lt;br /&gt;Un ejemplo.&lt;br /&gt;&lt;pre class="c:nocontrols" name="code"&gt;&lt;br /&gt;#include &amp;lt;boost/function.hpp&amp;gt;&lt;br /&gt;#include &amp;lt;boost/bind.hpp&amp;gt;&lt;br /&gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;using namespace boost;&lt;br /&gt;&lt;br /&gt;class Example{&lt;br /&gt; private:&lt;br /&gt;  int a;&lt;br /&gt; public:&lt;br /&gt;  function&amp;lt;void(std::string)&amp;gt; callback; &lt;br /&gt;  &lt;br /&gt;  void setA(int value){&lt;br /&gt;   a = value;&lt;br /&gt;   changeA();&lt;br /&gt;   if(callback){callback("setA");}&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  void changeA(){&lt;br /&gt;   a++;&lt;br /&gt;   if(callback){callback("changeA");}   &lt;br /&gt;  }  &lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;void debug(std::string s){&lt;br /&gt; std::cout &amp;lt;&amp;lt; "Method called: " &amp;lt;&amp;lt; s &amp;lt;&amp;lt; std::endl;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main(){&lt;br /&gt; Example e;&lt;br /&gt; e.callback = bind(&amp;debug, _1); &lt;br /&gt; e.setA(123);   &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Siguiendo el planteamiento anterior obtendríamos la cadena de llamadas a las funciones de la clase &lt;span style="font-style:italic;"&gt;Example&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Si no establecemos el callback (en este caso se hace en la segunda línea de &lt;span style="font-style:italic;"&gt;main&lt;/span&gt;) el comportamiento será el normal, sin embargo, en caso de necesidad se le puede hacer un &lt;span style="font-style:italic;"&gt;bind&lt;/span&gt; al objeto que queramos con una función de debug.&lt;br /&gt;&lt;br /&gt;La programación usando callbacks es especialmente útil en programación concurrente, para más información en la página de &lt;a href="http://www.boost.org/doc/libs/1_42_0/doc/html/function.html"&gt;Boost.Function&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-4665097258833045070?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/4665097258833045070/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=4665097258833045070&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/4665097258833045070'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/4665097258833045070'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/03/programacion-de-callbacks-con-boost.html' title='Programación de callbacks con Boost'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-4322883686991427096</id><published>2010-03-14T13:02:00.002+01:00</published><updated>2010-03-14T13:09:41.166+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><category scheme='http://www.blogger.com/atom/ns#' term='opengl'/><title type='text'>Usar OpenGL desde ruby</title><content type='html'>Es interesante poder crear demos o escenarios en 3D desde un lenguaje dinámico como ruby (cuando el rendimiento no sea un problema).&lt;br /&gt;&lt;br /&gt;Hay unos bindings para opengl llamados &lt;a href="http://ruby-opengl.rubyforge.org/index.html"&gt;ruby-opengl&lt;/a&gt; que nos permiten acceder directamente a la API de OpenGL desde ruby.&lt;br /&gt;&lt;br /&gt;Os dejo un ejemplo (inspirado en los tutoriales de &lt;a href="http://nehe.gamedev.net/"&gt;NeHe&lt;/a&gt;) para que os hagáis una idea de la sintaxis.&lt;br /&gt;&lt;pre class="ruby:nocontrols" name="code"&gt;&lt;br /&gt;require 'rubygems'&lt;br /&gt;require 'opengl'&lt;br /&gt;&lt;br /&gt;require "gl"&lt;br /&gt;require "glu"&lt;br /&gt;require "glut"&lt;br /&gt;require "mathn"&lt;br /&gt;&lt;br /&gt;include Gl, Glu, Glut&lt;br /&gt;&lt;br /&gt;window = ""&lt;br /&gt;&lt;br /&gt;def init_gl_window(width = 640, height = 480)&lt;br /&gt;    glClearColor(0.0, 0.0, 0.0, 0)&lt;br /&gt;    glClearDepth(1.0)&lt;br /&gt;    glDepthFunc(GL_LEQUAL)&lt;br /&gt;    glEnable(GL_DEPTH_TEST)&lt;br /&gt;    glShadeModel(GL_SMOOTH)&lt;br /&gt;&lt;br /&gt;    glMatrixMode(GL_PROJECTION)&lt;br /&gt;    glLoadIdentity&lt;br /&gt;    gluPerspective(45.0, width / height, 0.1, 100.0)&lt;br /&gt;&lt;br /&gt;    glMatrixMode(GL_MODELVIEW)&lt;br /&gt;&lt;br /&gt;    draw_gl_scene&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def reshape(width, height)&lt;br /&gt;    height = 1 if height == 0&lt;br /&gt;&lt;br /&gt;    glViewport(0, 0, width, height)&lt;br /&gt;&lt;br /&gt;    glMatrixMode(GL_PROJECTION)&lt;br /&gt;    glLoadIdentity&lt;br /&gt;&lt;br /&gt;    gluPerspective(45.0, width / height, 0.1, 100.0)&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;$color1_intensity = 0&lt;br /&gt;$color2_intensity = 0&lt;br /&gt;$color3_intensity = 0&lt;br /&gt;&lt;br /&gt;$rotation = 0&lt;br /&gt;&lt;br /&gt;def draw_gl_scene&lt;br /&gt;    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)&lt;br /&gt;&lt;br /&gt;    glMatrixMode(GL_MODELVIEW)&lt;br /&gt;    glLoadIdentity&lt;br /&gt;    glTranslatef(0, 0, -6)&lt;br /&gt;    &lt;br /&gt;    # Draw a triangle&lt;br /&gt;    glBegin(GL_POLYGON)&lt;br /&gt;        glColor3f($color1_intensity, $color2_intensity, $color3_intensity)&lt;br /&gt;        glVertex3f( 0.0,  1.0, 0.0)&lt;br /&gt;        glColor3f($color3_intensity, $color1_intensity, $color2_intensity)        &lt;br /&gt;        glVertex3f( 1.0, -1.0, 0.0)&lt;br /&gt;        glColor3f($color2_intensity, $color3_intensity, $colo1r_intensity)&lt;br /&gt;        glVertex3f(-1.0, -1.0, 0.0)&lt;br /&gt;    glEnd&lt;br /&gt;&lt;br /&gt;    $color1_intensity += 0.0005 if($color1_intensity %gt; 0.5)&lt;br /&gt;    $color2_intensity += 0.0005 if($color2_intensity %gt; 0.5)&lt;br /&gt;    $color3_intensity += 0.0010 if($color3_intensity %gt; 1)&lt;br /&gt;&lt;br /&gt;    glutSwapBuffers&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def idle&lt;br /&gt;    glutPostRedisplay&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;# Keyboard handler to exit when ESC is typed&lt;br /&gt;keyboard = lambda do |key, x, y|&lt;br /&gt;  if(key == 27) then&lt;br /&gt;    GLUT.DestroyWindow($window)&lt;br /&gt;    exit(0)  &lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;glutInit&lt;br /&gt;glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH)&lt;br /&gt;glutInitWindowSize(640, 480)&lt;br /&gt;glutInitWindowPosition(0, 0)&lt;br /&gt;window = glutCreateWindow("Example")&lt;br /&gt;glutDisplayFunc(method(:draw_gl_scene).to_proc)&lt;br /&gt;glutReshapeFunc(method(:reshape).to_proc)&lt;br /&gt;glutIdleFunc(method(:idle).to_proc)&lt;br /&gt;glutKeyboardFunc(keyboard)&lt;br /&gt;init_gl_window(640, 480)&lt;br /&gt;glutMainLoop()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Quizá sería interesante aportar un grado más de abstracción para hacer aún más sencillo la elaboración de gráficos desde este tipo de lenguajes.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-4322883686991427096?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/4322883686991427096/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=4322883686991427096&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/4322883686991427096'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/4322883686991427096'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/03/usar-opengl-desde-ruby.html' title='Usar OpenGL desde ruby'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-7559365373136344886</id><published>2010-03-03T23:53:00.005+01:00</published><updated>2010-03-04T00:04:43.850+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Unit Testing en C++ con Igloo</title><content type='html'>La realización de test unitarios aún siendo una buena práctica de programación puede ser muy tediosa si no se utiliza alguna librería que nos descargue de trabajo.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://igloo-testing.org/"&gt;Igloo&lt;/a&gt; para C++ nos provee de una API muy sencilla, además tiene la ventaja de que no necesita instalación ya que Igloo es simplemente un conjunto de ficheros de cabecera.&lt;br /&gt;&lt;br /&gt;Lo único que necesitamos para usar Igloo es bajarnos la última versión y compilar nuestro test incluyendo sus cabeceras:&lt;br /&gt;&lt;pre class="c:nocontrols" name="code"&gt;&lt;br /&gt;g++ tests.cpp -o tests -I/path/de/igloo/&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Dejo un ejemplo de como quedaría un conjunto de test unitarios a una clase.&lt;br /&gt;&lt;pre class="c:nocontrols" name="code"&gt;&lt;br /&gt;#include &amp;lt;igloo/igloo.h&amp;gt;&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;&lt;br /&gt;using namespace igloo;&lt;br /&gt;&lt;br /&gt;class Example{&lt;br /&gt; private:&lt;br /&gt;  int atrib1;&lt;br /&gt;  int atrib2;&lt;br /&gt;  &lt;br /&gt; public:&lt;br /&gt;  Example(int a1, int a2){&lt;br /&gt;   atrib1 = a1;&lt;br /&gt;   atrib2 = a2;&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  int getAtrib1(){return atrib1;}&lt;br /&gt;  int getAtrib2(){return atrib2;}&lt;br /&gt;&lt;br /&gt;  static int sum(int n){&lt;br /&gt;   int result = 0;&lt;br /&gt;   for(int i=1; i&amp;lt;=n; i++){result+=i;}&lt;br /&gt;   return result;&lt;br /&gt;  } &lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;TestFixture(Assertions){&lt;br /&gt; TestMethod(ShouldHandleIntegerEquality){&lt;br /&gt;  Assert::That(Example::sum(5), Is().EqualTo(15));  &lt;br /&gt; }&lt;br /&gt;  &lt;br /&gt; TestMethod(ShouldHandleStrings){&lt;br /&gt;  Example e(5,6);&lt;br /&gt;  char c1[100];&lt;br /&gt;&lt;br /&gt;  sprintf(c1, "%d", e.getAtrib1());&lt;br /&gt;  std::string a1(c1);&lt;br /&gt;  sprintf(c1, "%d", e.getAtrib2());  &lt;br /&gt;  std::string a2(c1);  &lt;br /&gt;  &lt;br /&gt;  Assert::That(a1, Is().Not().EqualTo(a2));&lt;br /&gt; }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;int main(){&lt;br /&gt;  return TestRunner::RunAllTests();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Al ejecutar el programa anterior obtendríamos la salida: &lt;span style="font-style:italic;"&gt;Test run complete. 2 tests run, 2 succeeded, 0 failed&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-7559365373136344886?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/7559365373136344886/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=7559365373136344886&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/7559365373136344886'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/7559365373136344886'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/03/unit-testing-en-c-con-igloo.html' title='Unit Testing en C++ con Igloo'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-6874989408678515030</id><published>2010-02-19T00:15:00.005+01:00</published><updated>2010-02-19T00:36:20.768+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><category scheme='http://www.blogger.com/atom/ns#' term='boost'/><title type='text'>Smart pointers de la librería Boost</title><content type='html'>Una de las ventajas que tiene la programación en Java sobre C++ es la recolección de basura.&lt;br /&gt;&lt;br /&gt;Cuando escribimos un programa en Java no nos tenemos que preocupar de liberar la memoria que vamos usando, hay un recolector de la máquina virtual que lo hace por nosotros. De esta forma se reduce el número de &lt;span style="font-style:italic;"&gt;&lt;a href="http://en.wikipedia.org/wiki/Memory_leak"&gt;memory leaks&lt;/a&gt;&lt;/span&gt; y se facilita la programación.&lt;br /&gt;&lt;br /&gt;En C++ sin embargo la gestión de memoria debe realizarla el desarrollador, proporcionando más potencia pero también dificultando el desarrollo.&lt;br /&gt;&lt;br /&gt;Para facilitar la programación en este apartado, la librería &lt;a href="http://www.boost.org/"&gt;Boost&lt;/a&gt; cuenta con un concepto llamado &lt;span style="font-style:italic;"&gt;smart pointers&lt;/span&gt; que liberan de complejidad a la hora de gestionar la memoria al programador.&lt;br /&gt;&lt;br /&gt;Por ejemplo, usando el tipo &lt;span style="font-style:italic;"&gt;scoped_ptr&lt;/span&gt;.&lt;br /&gt;&lt;pre class="c:nocontrols" name="code"&gt;&lt;br /&gt;#include &amp;lt;boost/smart_ptr.hpp&amp;gt;&lt;br /&gt;&lt;br /&gt;class Example{&lt;br /&gt; public:&lt;br /&gt;  int a;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;void scoped_pointer(){&lt;br /&gt; boost::scoped_ptr&amp;lt;Example&amp;gt; ptr(new Example);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void pointer(){&lt;br /&gt; Example *ptr = new Example;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;int main(){&lt;br /&gt; while(1){&lt;br /&gt;  pointer();&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Al ejecutar este programa se irá reservando memoria constantemente hasta agotar la memoria total del sistema, puesto que en ningún momento se libera.&lt;br /&gt;&lt;br /&gt;Sin embargo, si se modifica la llamada &lt;span style="font-style:italic;"&gt;pointer&lt;/span&gt; por &lt;span style="font-style:italic;"&gt;scoped_pointer&lt;/span&gt; el programa se ejecutará de forma estable, dado que al terminar el método, el &lt;span style="font-style:italic;"&gt;scoped pointer&lt;/span&gt; libera la memoria utilizada de forma automática.&lt;br /&gt;&lt;br /&gt;Hay &lt;span style="font-style:italic;"&gt;smart pointers&lt;/span&gt; con otras políticas de gestión de memoria, para elegir cual nos conviene en la &lt;a href="http://www.boost.org/doc/libs/1_42_0/libs/smart_ptr/smart_ptr.htm"&gt;documentación&lt;/a&gt; de boost se detalla cada uno.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-6874989408678515030?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/6874989408678515030/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=6874989408678515030&amp;isPopup=true' title='2 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/6874989408678515030'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/6874989408678515030'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/02/smart-pointers-de-la-libreria-boost.html' title='Smart pointers de la librería Boost'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-7791104063152216289</id><published>2010-01-24T10:23:00.003+01:00</published><updated>2010-01-24T10:47:59.049+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Profiling de peticiones en ruby on rails</title><content type='html'>Ruby es un lenguaje dinámico muy potente pero por ello también muy díficil de depurar en ocasiones. En ruby on rails con los &lt;span style="font-style:italic;"&gt;named_scope&lt;/span&gt;, &lt;span style="font-style:italic;"&gt;before_filter&lt;/span&gt;, &lt;span style="font-style:italic;"&gt;plugins&lt;/span&gt;, &lt;span style="font-style:italic;"&gt;gems&lt;/span&gt;, etc puede ser todavía peor.&lt;br /&gt;&lt;br /&gt;Sin embargo, en los sistemas operativos que soportan &lt;a href="http://hub.opensolaris.org/bin/view/Community+Group+dtrace/WebHome"&gt;DTrace&lt;/a&gt; tenemos una ayuda para encontrar los cuellos de botella de la aplicación, por ejemplo, usando el script que hay en: &lt;a href="http://dl.getdropbox.com/u/478290/blog/dtrace/rb_linetime.d"&gt;http://dl.getdropbox.com/u/478290/blog/dtrace/rb_linetime.d&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Simulo un &lt;span style="font-style:italic;"&gt;before_filter&lt;/span&gt; muy lento que se ejecute para todas las request como éste:&lt;br /&gt;&lt;pre class="ruby:nocontrols" name="code"&gt;&lt;br /&gt;22  def takes_too_long&lt;br /&gt;23    i = 0&lt;br /&gt;24    100.times{&lt;br /&gt;25      100000.times{i+=1}&lt;br /&gt;26      100000.times{i-=1}&lt;br /&gt;27    }&lt;br /&gt;28  end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Después arrancamos el servidor de ruby on rails y obtenemos su PID (vía &lt;span style="font-style:italic;"&gt;passenger-status&lt;/span&gt;, &lt;span style="font-style:italic;"&gt;ps&lt;/span&gt;, &lt;span style="font-style:italic;"&gt;top&lt;/span&gt;...)&lt;br /&gt;&lt;br /&gt;Ejecutamos:&lt;br /&gt;&lt;pre class="ruby:nocontrols" name="code"&gt;&lt;br /&gt;sudo dtrace -s rb_linetime.d -p pid_del_servidor &gt; request.log&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Hacemos una petición a la aplicación ruby on rails, después paramos DTrace con Ctrl+C y en &lt;span style="font-style:italic;"&gt;request.log&lt;/span&gt; podemos ver los ficheros ruby que se van cargando y cuanto tarda cada uno, en concreto, nos fijamos en las líneas:&lt;br /&gt;&lt;pre class="ruby:nocontrols" name="code"&gt;&lt;br /&gt;FILE                                                                                                                      LINE  COUNT    AVG(us)      SUM(us)&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;/Users/javiyu/projects/rails/prueba/vendor/rails/activesupport/lib/active_support/core_ext/module/introspection.rb          86    849        188       160330&lt;br /&gt;/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/gems/1.8/gems/mongrel-1.1.4/lib/mongrel/configurator 285     83      30374      2521066&lt;br /&gt;/Users/javiyu/projects/rails/prueba/app/controllers/application.rb 26 600000         16      9690835&lt;br /&gt;/Users/javiyu/projects/rails/prueba/app/controllers/application.rb   25 681051         16     11087871&lt;br /&gt;/Users/javiyu/projects/rails/prueba/vendor/rails/railties/lib/commands/servers/base.rb 14     69     974199     67219750&lt;br /&gt;....&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Vemos que &lt;span style="font-style:italic;"&gt;application.rb&lt;/span&gt; tarda mucho más de lo normal, e incluso detecta el número de línea en el que está el cuello de botella, en este caso la 25 y la 26.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-7791104063152216289?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/7791104063152216289/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=7791104063152216289&amp;isPopup=true' title='3 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/7791104063152216289'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/7791104063152216289'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/01/profiling-de-peticiones-en-ruby-on.html' title='Profiling de peticiones en ruby on rails'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-5648330800705451491</id><published>2010-01-11T22:51:00.003+01:00</published><updated>2010-01-11T23:01:52.993+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><category scheme='http://www.blogger.com/atom/ns#' term='c'/><category scheme='http://www.blogger.com/atom/ns#' term='ensamblador'/><title type='text'>Obtención de información relativa al procesador</title><content type='html'>Para la generación de código optimizado puede ser necesario conocer sobre que tipo de procesador se está ejecutando nuestro programa y que instrucciones soporta.&lt;br /&gt;&lt;br /&gt;La instrucción &lt;span style="font-style:italic;"&gt;cpuid&lt;/span&gt; proporciona información relativa al procesador. &lt;br /&gt;Por ejemplo.&lt;br /&gt;&lt;pre class="c:nocontrols" name="code"&gt;&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;&lt;br /&gt;typedef unsigned int uint;&lt;br /&gt;&lt;br /&gt;void print_register_str(reg){&lt;br /&gt; int i;&lt;br /&gt; &lt;br /&gt; for(i=0; i&amp;lt;4; i++){&lt;br /&gt;  printf("%c", reg &amp;gt;&amp;gt; (i*8) );&lt;br /&gt; } &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void cpuid(uint *eax, uint *ebx, uint *ecx, uint *edx, uint service){&lt;br /&gt; __asm__ (&lt;br /&gt;  "pushl %%ebx \n\t"&lt;br /&gt;  "cpuid \n\t"&lt;br /&gt;  "movl %%ebx, %1 \n\t"&lt;br /&gt;  "popl %%ebx \n\t"&lt;br /&gt;  : "=a" (*eax),&lt;br /&gt;  "=S" (*ebx),&lt;br /&gt;  "=c" (*ecx),&lt;br /&gt;  "=d" (*edx)&lt;br /&gt;  :"a" (service)&lt;br /&gt; );&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main(){&lt;br /&gt; uint eax, ebx, ecx, edx;&lt;br /&gt; &lt;br /&gt; printf("VendorString: ");&lt;br /&gt; cpuid(&amp;amp;eax, &amp;amp;ebx, &amp;amp;ecx, &amp;amp;edx, 0);&lt;br /&gt; print_register_str(ebx);&lt;br /&gt; print_register_str(edx);&lt;br /&gt; print_register_str(ecx);&lt;br /&gt; printf("\n");&lt;br /&gt;&lt;br /&gt; &lt;br /&gt; cpuid(&amp;amp;eax, &amp;amp;ebx, &amp;amp;ecx, &amp;amp;edx, 1);&lt;br /&gt; printf("MMX support: %d\n", (edx &amp;gt;&amp;gt; 23) &amp;amp; 1); &lt;br /&gt; printf("SSE support: %d\n", (edx &amp;gt;&amp;gt; 25) &amp;amp; 1);&lt;br /&gt; printf("SSE2 support: %d\n", (edx &amp;gt;&amp;gt; 26) &amp;amp; 1);&lt;br /&gt; printf("HyperTransport: %d\n", (edx &amp;gt;&amp;gt; 28) &amp;amp; 1);&lt;br /&gt; printf("SSE3 support: %d\n", (ecx) &amp;amp; 1);&lt;br /&gt;&lt;br /&gt; return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Este programa tiene como resultado para mi cpu.&lt;br /&gt;&lt;pre class="c:nocontrols" name="code"&gt;&lt;br /&gt;VendorString: GenuineIntel&lt;br /&gt;MMX support: 1&lt;br /&gt;SSE support: 1&lt;br /&gt;SSE2 support: 1&lt;br /&gt;HyperTransport: 1&lt;br /&gt;SSE3 support: 1&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Se puede obtener más información específica, aquí vienen algunos ejemplos más: &lt;a href="http://softpixel.com/~cwright/programming/simd/cpuid.php"&gt;http://softpixel.com/~cwright/programming/simd/cpuid.php&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-5648330800705451491?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/5648330800705451491/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=5648330800705451491&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/5648330800705451491'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/5648330800705451491'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2010/01/obtencion-de-informacion-relativa-al.html' title='Obtención de información relativa al procesador'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-3681309253270905693</id><published>2009-12-28T23:27:00.002+01:00</published><updated>2009-12-28T23:48:43.707+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><category scheme='http://www.blogger.com/atom/ns#' term='c'/><title type='text'>Implementación de malloc en glibc</title><content type='html'>malloc es una función de C que sirve para reservar &lt;span style="font-style:italic;"&gt;n&lt;/span&gt; bytes consecutivos en memoria y devuelve un puntero a ese array.&lt;br /&gt;&lt;br /&gt;¿Qué pasa cuando se agota la memoria? En teoría la función malloc debería devolver un puntero nulo y establecer la variable &lt;span style="font-style:italic;"&gt;errno&lt;/span&gt; a &lt;span style="font-style:italic;"&gt;ENOMEM&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;¿Qué ocurre en realidad? En la librería de C de Linux (glibc) se usa un algoritmo de reserva de memoria optimista, no contempla el caso de haber agotado la memoria y siempre se devuelve un puntero válido. Según la &lt;span style="font-style:italic;"&gt;manpage&lt;/span&gt; "uno o varios procesos pueden morir en estas situaciones llegándoles el mensaje 'out of memory'".&lt;br /&gt;&lt;br /&gt;Hay una forma de solucionar esto, cambiar el comportamiento del algoritmo estableciendo a 2 la variable &lt;span style="font-style:italic;"&gt;overcommit_memory&lt;/span&gt; con el comando:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;echo 2 &gt; /proc/sys/vm/overcommit_memory&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Fuentes:&lt;br /&gt;&lt;a href="http://www.manpagez.com/man/3/malloc/"&gt;manpagez.com&lt;/a&gt;&lt;br /&gt;&lt;a href="http://linux.die.net/man/3/malloc"&gt;linux.die.net&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-3681309253270905693?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/3681309253270905693/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=3681309253270905693&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3681309253270905693'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3681309253270905693'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2009/12/implementacion-de-malloc-en-glibc.html' title='Implementación de malloc en glibc'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-6947572343609038088</id><published>2009-11-01T16:46:00.006+01:00</published><updated>2009-11-03T22:26:58.242+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Ejecución asíncrona de javascript con web workers</title><content type='html'>Tal y como anunciaba Google en la &lt;a href="http://code.google.com/events/io/2009/"&gt;Google IO&lt;/a&gt; de este año han estado trabajando junto a la fundación Mozilla en la definición e implementación de los llamados web workers.&lt;br /&gt;&lt;br /&gt;Los web workers permiten carga y ejecución asíncrona de javascript, tienen algunas limitaciones ya que no se puede acceder al DOM entre otras funciones, usa threads a nivel de sistema operativo y usa como método de sincronización paso de mensajes.&lt;br /&gt;&lt;br /&gt;Un ejemplo de sincronización sencillo.&lt;br /&gt;&lt;br /&gt;long_work.js&lt;br /&gt;&lt;pre class="javascript:nocontrols" name="code"&gt;&lt;br /&gt;var j=1;&lt;br /&gt;for(var i=0; i&amp;lt;999999999; i++){j=j*7+2;j=1}&lt;br /&gt;this.postMessage('Done');&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;index.html&lt;br /&gt;&lt;pre class="javascript:nocontrols" name="code"&gt;&lt;br /&gt;&amp;lt;script type="text/javascript"&amp;gt;&lt;br /&gt;     var worker = new Worker("/javascripts/long_work.js");&lt;br /&gt;     worker.onmessage = function(event){&lt;br /&gt;       alert(event.data);&lt;br /&gt;     };&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;a href="https://developer.mozilla.org/En/Using_web_workers"&gt;Ejemplo&lt;/a&gt; de uso en la web de la fundación Mozilla.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-6947572343609038088?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/6947572343609038088/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=6947572343609038088&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/6947572343609038088'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/6947572343609038088'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2009/11/ejecucion-asincrona-de-javascript-con.html' title='Ejecución asíncrona de javascript con web workers'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-2556226747489023050</id><published>2009-08-15T22:50:00.002+02:00</published><updated>2009-08-15T22:59:44.015+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><category scheme='http://www.blogger.com/atom/ns#' term='symbian'/><title type='text'>Como hacer copias de seguridad de tu agenda en symbian</title><content type='html'>Ya que tenemos acceso al API de symbian desde python (gracias al proyecto &lt;a href="http://sourceforge.net/projects/pys60/"&gt;pys60&lt;/a&gt;) podemos aprovecharnos para hacer algunas cosas útiles con unos scripts simples en python.&lt;br /&gt;&lt;br /&gt;Por ejemplo, para hacer una copia de seguridad de la agenda serviría el siguiente script.&lt;br /&gt;&lt;pre class="python:nocontrols" name="code"&gt;&lt;br /&gt;from contacts import ContactsDb&lt;br /&gt;&lt;br /&gt;contacts = ContactsDb().values()&lt;br /&gt;&lt;br /&gt;filename = 'e:\\agenda.txt'&lt;br /&gt;f = open(filename, "w")&lt;br /&gt;&lt;br /&gt;for c in contacts:&lt;br /&gt; f.write(c.as_vcard())&lt;br /&gt;&lt;br /&gt;f.close()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Este programa exporta a un fichero toda la agenda en formato &lt;a href="http://en.wikipedia.org/wiki/VCard"&gt;VCard&lt;/a&gt; para posteriormente transferirlo a otro dispositivo.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-2556226747489023050?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/2556226747489023050/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=2556226747489023050&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/2556226747489023050'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/2556226747489023050'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2009/08/como-hacer-copias-de-seguridad-de-tu.html' title='Como hacer copias de seguridad de tu agenda en symbian'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-1690351813704892276</id><published>2009-07-18T16:54:00.003+02:00</published><updated>2009-07-18T17:05:36.750+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Conectar una aplicación rails a varias bases de datos simultáneamente</title><content type='html'>Se puede conectar una aplicación rails a varias bases de datos a la vez, eso sí, hay que tener un especial cuidado con el rendimiento de la aplicación, aunque ActiveRecord nos provee una interfaz transparente a la hora de acceder a los modelos.&lt;br /&gt;&lt;br /&gt;Suponiendo como ejemplo que tenemos dos modelos (&lt;span style="font-style:italic;"&gt;Post&lt;/span&gt; y &lt;span style="font-style:italic;"&gt;Comment&lt;/span&gt;) y este último está localizado en una base de datos externa, se puede configurar rails de la siguiente forma:&lt;br /&gt;&lt;br /&gt;1) Primero, creamos un fichero de configuración para la conexión a la nueva base de datos (&lt;span style="font-style:italic;"&gt;config/external_database.yml&lt;/span&gt;).&lt;br /&gt;&lt;pre class="ruby:nocontrols" name="code"&gt;&lt;br /&gt;development:&lt;br /&gt;    adapter: mysql&lt;br /&gt;    database: test&lt;br /&gt;    username: root&lt;br /&gt;    password:&lt;br /&gt;&lt;br /&gt;production:&lt;br /&gt;    adapter: mysql&lt;br /&gt;    database: test&lt;br /&gt;    username: root&lt;br /&gt;    password:&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;2) Después, creamos un módulo para encapsular la lectura del fichero y la nueva conexión.&lt;br /&gt;&lt;pre class="ruby:nocontrols" name="code"&gt;&lt;br /&gt;module ExternalDatabase&lt;br /&gt;  def self.included(base)&lt;br /&gt;    config = YAML.load(File.open('config/external_database.yml'))    &lt;br /&gt;    &lt;br /&gt;    if config and ENV['RAILS_ENV']&lt;br /&gt;      base.establish_connection(config[ENV['RAILS_ENV']])&lt;br /&gt;    else&lt;br /&gt;      raise 'External Database not configured'&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;3) Por último, incluimos en los modelos que van a la base de datos externa el módulo que hemos creado.&lt;br /&gt;&lt;pre class="ruby:nocontrols" name="code"&gt;&lt;br /&gt;class Comment &lt; ActiveRecord::Base&lt;br /&gt;  include ExternalDatabase&lt;br /&gt;  &lt;br /&gt;  belongs_to :post&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Con esto ya podemos utilizar los modelos aunque cada uno esté en una base de datos diferente.&lt;br /&gt;&lt;pre class="ruby:nocontrols" name="code"&gt;&lt;br /&gt;Comment.find(:all, :include =&gt; :post)&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-1690351813704892276?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/1690351813704892276/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=1690351813704892276&amp;isPopup=true' title='4 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/1690351813704892276'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/1690351813704892276'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2009/07/conectar-una-aplicacion-rails-varias.html' title='Conectar una aplicación rails a varias bases de datos simultáneamente'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-1927731191029545735</id><published>2009-07-11T15:55:00.002+02:00</published><updated>2009-07-11T16:06:29.358+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Diferencias de rendimiento entre eval y send</title><content type='html'>La metaprogramación en ruby permite mucha expresividad y flexibilidad, aún así hace caer bastante el rendimiento.&lt;br /&gt;&lt;br /&gt;A pesar de eso, lo más importante es evitar en la medida de lo posible &lt;span style="font-style:italic;"&gt;eval&lt;/span&gt; ya que es bastante más lento.&lt;br /&gt;&lt;br /&gt;Al hacer una llamada a &lt;span style="font-style:italic;"&gt;send&lt;/span&gt; la máquina virtual de ruby tiene que buscar el nombre del método que se le pasa como parámetro y ejecutarlo.&lt;br /&gt;&lt;br /&gt;En cambio, al hacer un &lt;span style="font-style:italic;"&gt;eval&lt;/span&gt; además de lo anterior la máquina virtual necesita parsear la cadena y después ejecutar el código.&lt;br /&gt;&lt;br /&gt;&lt;pre class="ruby:nocontrols" name="code"&gt;&lt;br /&gt;Benchmark.bm{|x| x.report{100000.times{eval('Post.scopes')}}}&lt;br /&gt;    user     system      total        real&lt;br /&gt;0.410000   0.000000   0.410000 (  0.410306)&lt;br /&gt;&lt;br /&gt;Benchmark.bm{|x| x.report{100000.times{Post.send('scopes')}}}&lt;br /&gt;    user     system      total        real&lt;br /&gt;0.140000   0.000000   0.140000 (  0.144820)&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-1927731191029545735?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/1927731191029545735/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=1927731191029545735&amp;isPopup=true' title='2 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/1927731191029545735'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/1927731191029545735'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2009/07/diferencias-de-rendimiento-entre-eval-y.html' title='Diferencias de rendimiento entre eval y send'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-3092663322700887521</id><published>2009-06-26T18:39:00.005+02:00</published><updated>2009-06-26T19:03:41.208+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Optimización de consultas en rails</title><content type='html'>Cuando en rails se hace una consulta a la base de datos sobre una tabla que contiene mucha información, no todo el tiempo se pierde en la consulta. Una parte importante del tiempo se pierde en la creación de cada objeto ActiveRecord.&lt;br /&gt;&lt;br /&gt;Usando directamente el método &lt;span style="font-style:italic;"&gt;select_all&lt;/span&gt; de la conexión ActiveRecord devolverá un array de hash, ahorrando el tiempo de construcción de objetos.&lt;br /&gt;&lt;pre class="ruby:nocontrols" name="code"&gt;&lt;br /&gt;Benchmark.bm{|x| x.report{100.times{BigTable.find(:all)}}}&lt;br /&gt;    user     system      total        real&lt;br /&gt;10.090000   2.090000  12.180000 ( 19.199150)&lt;br /&gt;&lt;br /&gt;Benchmark.bmbm{|x| x.report{100.times{BigTable.connection.select_all('select * from big_table')}}}&lt;br /&gt;    user     system      total        real&lt;br /&gt;7.350000   2.080000   9.430000 ( 16.646406)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;En general, no es buena idea guardar todos los elementos de una tabla grande en un array, pero aún seleccionando tan solo el índice se obtiene una mejora sustancial. &lt;br /&gt;&lt;pre class="ruby:nocontrols" name="code"&gt;&lt;br /&gt;Benchmark.bm{|x| x.report{100.times{BigTable.find(:all, :select =&gt; :id)}}}&lt;br /&gt;    user     system      total        real&lt;br /&gt;0.610000   0.010000   0.620000 (  0.707702)&lt;br /&gt;&lt;br /&gt;Benchmark.bmbm{|x| x.report{100.times{BigTable.connection.select_all('select id from big_table')}}}&lt;br /&gt;    user     system      total        real&lt;br /&gt;0.080000   0.000000   0.080000 (  0.161878)&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-3092663322700887521?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/3092663322700887521/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=3092663322700887521&amp;isPopup=true' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3092663322700887521'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3092663322700887521'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2009/06/optimizacion-de-consultas-en-rails.html' title='Optimización de consultas en rails'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-3620678915219738821</id><published>2009-06-20T23:19:00.006+02:00</published><updated>2009-06-20T23:39:04.415+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><category scheme='http://www.blogger.com/atom/ns#' term='c'/><title type='text'>Crear extensiones de ruby en c</title><content type='html'>Crear extensiones en C del lenguaje ruby es bastante sencillo.&lt;br /&gt;&lt;br /&gt;En primer lugar hay que crear un fichero para extconf, este nos generará el fichero makefile de forma automática.&lt;br /&gt;&lt;br /&gt;En el fichero extconf.rb debería haber algo como:&lt;br /&gt;&lt;pre name="code" class="c:nocontrols"&gt;&lt;br /&gt;#!/usr/bin/env ruby&lt;br /&gt;&lt;br /&gt;require 'mkmf'&lt;br /&gt;create_makefile("ruby1")&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Donde &lt;span style="font-style:italic;"&gt;ruby1&lt;/span&gt; es el nombre de la extensión.&lt;br /&gt;&lt;br /&gt;En segundo lugar hay que crear la extensión en código C, simplemente hay que incluir la cabecera &lt;span style="font-style:italic;"&gt;ruby.h&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;La función Init_ruby1 es la que se ejecutará al importar la extensión desde código ruby.&lt;br /&gt;&lt;pre name="code" class="c:nocontrols"&gt;&lt;br /&gt;#include "ruby.h"&lt;br /&gt;&lt;br /&gt;static VALUE c_printf(VALUE self, VALUE anObject){&lt;br /&gt; printf("%s\n", STR2CSTR(anObject));&lt;br /&gt; return Qnil;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;static VALUE c_init(VALUE self){&lt;br /&gt;  return self;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;VALUE FromC;&lt;br /&gt;&lt;br /&gt;void Init_ruby1() {&lt;br /&gt; rb_define_global_function("printfc", c_printf, 1);&lt;br /&gt; FromC = rb_define_class("FromC", rb_cObject);&lt;br /&gt; rb_define_method(FromC, "initialize", c_init, 0);&lt;br /&gt; rb_define_method(FromC, "printfc", c_printf, 1);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;En este ejemplo se define una función global &lt;span style="font-style:italic;"&gt;printfc&lt;/span&gt;, se define la clase &lt;span style="font-style:italic;"&gt;FromC&lt;/span&gt;, el método de instancia &lt;span style="font-style:italic;"&gt;printfc&lt;/span&gt; de esa clase.&lt;br /&gt;&lt;br /&gt;Para compilar e instalar este código hay que ejecutar &lt;span style="font-style:italic;"&gt;ruby extconf.rb&lt;/span&gt;, &lt;span style="font-style:italic;"&gt;make &lt;/span&gt;y &lt;span style="font-style:italic;"&gt;make install&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Ya deberíamos tener disponible la librería &lt;span style="font-style:italic;"&gt;ruby1&lt;/span&gt;, al ejecutar &lt;span style="font-style:italic;"&gt;require 'ruby1'&lt;/span&gt; podremos ejecutar las funciones de nuestro código en C.&lt;br /&gt;&lt;br /&gt;Hay una gran cantidad de funciones disponibles para crear extensiones en la siguiente dirección: &lt;a href="http://www.rubycentral.com/book/ext_ruby.html"&gt;http://www.rubycentral.com/book/ext_ruby.html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-3620678915219738821?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/3620678915219738821/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=3620678915219738821&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3620678915219738821'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3620678915219738821'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2009/06/crear-extensiones-de-ruby-en-c.html' title='Crear extensiones de ruby en c'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-3809434356642226237</id><published>2009-06-03T23:42:00.005+02:00</published><updated>2009-06-04T00:01:39.100+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Definición de named_scopes dependientes del tiempo actual</title><content type='html'>Si tenemos una clase ActiveRecord como la siguiente:&lt;br /&gt;&lt;pre name="code" class="ruby:nocontrols"&gt;&lt;br /&gt;class Post &lt; ActiveRecord::Base&lt;br /&gt;  named_scope :test, :conditions =&gt; ['updated_at &lt; ?', Time.now]&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;En modo development funciona sin problemas, sin embargo en modo production la consulta que se genera no es la esperada.&lt;br /&gt;&lt;br /&gt;Al arrancar rails en modo production se cachean las clases, al cargar este modelo en concreto se evalúa &lt;span style="font-style:italic;"&gt;Time.now&lt;/span&gt; haciendo que para todas las consultas se coja como fecha la hora en la que se ha cargado el modelo.&lt;br /&gt;&lt;br /&gt;El descrito anteriormente no es el comportamiento que esperaríamos al definir el named_scope, sino que debería obtener la fecha y hora actual para cada consulta, no en la definición.&lt;br /&gt;&lt;br /&gt;Revisando la definición de los named_scopes nos encontramos lo siguiente:&lt;br /&gt;&lt;pre name="code" class="ruby:nocontrols"&gt;&lt;br /&gt;      def named_scope(name, options = {}, &amp;block)&lt;br /&gt;        name = name.to_sym&lt;br /&gt;        scopes[name] = lambda do |parent_scope, *args|&lt;br /&gt;          Scope.new(parent_scope, case options&lt;br /&gt;            when Hash&lt;br /&gt;              options&lt;br /&gt;            when Proc&lt;br /&gt;              options.call(*args)&lt;br /&gt;          end, &amp;block)&lt;br /&gt;        end&lt;br /&gt;        (class &lt;&lt; self; self end).instance_eval do&lt;br /&gt;          define_method name do |*args|&lt;br /&gt;            scopes[name].call(self, *args)&lt;br /&gt;          end&lt;br /&gt;        end&lt;br /&gt;      end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;En nuestro caso pasamos un hash como opciones, por lo que efectivamente se evaluará el &lt;span style="font-style:italic;"&gt;Time.now&lt;/span&gt; solo en la definición de dicho hash.&lt;br /&gt;&lt;br /&gt;Si en lugar de eso definimos un objeto de tipo &lt;span style="font-style:italic;"&gt;Proc&lt;/span&gt; se evaluará cada vez.&lt;br /&gt;&lt;br /&gt;Por lo tanto para arreglar el comportamiento del primer ejemplo deberíamos escribirlo como:&lt;br /&gt;&lt;pre name="code" class="ruby:nocontrols"&gt;&lt;br /&gt;class Post &lt; ActiveRecord::Base&lt;br /&gt;  named_scope :test, lambda{{:conditions =&gt; ['updated_at &lt; ?', Time.now]}}&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-3809434356642226237?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/3809434356642226237/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=3809434356642226237&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3809434356642226237'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3809434356642226237'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2009/06/si-tenemos-una-clase-activerecord-como.html' title='Definición de named_scopes dependientes del tiempo actual'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-9076827714660331168</id><published>2009-05-10T23:20:00.004+02:00</published><updated>2009-05-10T23:42:59.260+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='proyectos'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Aplicación de consola para twitter</title><content type='html'>Acabo de lanzar un proyecto en github para interaccionar con twitter desde consola.&lt;br /&gt;&lt;br /&gt;Por ahora incluye la funcionalidad básica: cambio de estado, consulta de estado de amigos, login y mensajería.&lt;br /&gt;&lt;br /&gt;La interfaz de comandos es muy similar al clásico IRC.&lt;br /&gt;&lt;br /&gt;La url del proyecto es la siguiente: &lt;a href="http://github.com/javiyu/twit/tree/master"&gt;twit&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-9076827714660331168?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/9076827714660331168/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=9076827714660331168&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/9076827714660331168'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/9076827714660331168'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2009/05/aplicacion-de-consola-para-twitter.html' title='Aplicación de consola para twitter'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-3958758805931905466</id><published>2009-05-01T13:32:00.003+02:00</published><updated>2009-05-01T13:46:33.925+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='jquery'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Añadiendo estado a los elementos del DOM</title><content type='html'>En aplicaciones complejas con javascript para guardar el estado de cada elemento se suele modificar alguna propiedad del elemento que queramos manipular.&lt;br /&gt;&lt;br /&gt;Sin embargo esta práctica es poco adecuada y no demasiado flexible, ya que no podemos guardar tipos de datos complejos.&lt;br /&gt;&lt;br /&gt;jQuery ya prevee que podemos necesitar esta funcionalidad y nos proporciona la función data para guardar información de cada elemento.&lt;br /&gt;&lt;br /&gt;Por ejemplo:&lt;br /&gt;&lt;pre class="javascript:nocontrols" name="code"&gt;&lt;br /&gt;$('a').data('activated_links', false);&lt;br /&gt;....&lt;br /&gt;var footer_links = $('.footer_links');&lt;br /&gt;if(!footer_links.data('activated_links')){&lt;br /&gt;  footer_links.data('activated_links', true);&lt;br /&gt;  ...&lt;br /&gt;}&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-3958758805931905466?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/3958758805931905466/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=3958758805931905466&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3958758805931905466'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3958758805931905466'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2009/05/anadiendo-estado-los-elementos-del-dom.html' title='Añadiendo estado a los elementos del DOM'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-4025227692892532891</id><published>2009-03-28T12:30:00.002+01:00</published><updated>2009-03-28T12:48:33.760+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Combinación de named_scopes en rails</title><content type='html'>Cuando hay que realizar un filtrado de resultados en una web con muchas posibles combinaciones podemos acabar con muchas líneas de código para obtener una funcionalidad no demasiado compleja.&lt;br /&gt;&lt;br /&gt;En rails, la mayoría de los filtrados se hacen con named_scopes, queda parcialmente resuelto el problema, aún así quedan resolver como aplicar cada combinación de named_scopes según el filtrado que necesite el usuario.&lt;br /&gt;&lt;br /&gt;Suponiendo que tenemos un modelo Post como el siguiente:&lt;br /&gt;&lt;pre class="ruby:nocontrols" name="code"&gt;&lt;br /&gt;class Post &lt; ActiveRecord::Base&lt;br /&gt;  named_scope :all&lt;br /&gt;  named_scope :published, :conditions =&gt; {:published =&gt; true}&lt;br /&gt;  named_scope :from_user, :conditions =&gt; {:kind =&gt; 'user'}&lt;br /&gt;  named_scope :from_admin, :conditions =&gt; {:kind =&gt; 'admin'}&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Podemos resolver el problema de aplicar filtros combinados de la siguiente forma usando &lt;span style="font-style:italic;"&gt;inject&lt;/span&gt;:&lt;br /&gt;&lt;pre class="ruby:nocontrols" name="code"&gt;&lt;br /&gt;class PostsController &lt; ApplicationController&lt;br /&gt;  def index&lt;br /&gt;    filter = (params[:filter] or String.new)&lt;br /&gt;    filter = filter.split(',').map(&amp;:to_sym).select{|f| Post.scopes.include?(f)}&lt;br /&gt;    filter &lt;&lt; :all&lt;br /&gt;&lt;br /&gt;    @posts = filter.inject(Post){|model, nscope| model.send(nscope)}&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;En primer lugar obtenemos la lista de named_scopes a aplicar y filtramos los no válidos, en segundo con &lt;span style="font-style:italic;"&gt;inject&lt;/span&gt; se los aplicamos al modelo.&lt;br /&gt;&lt;br /&gt;Con ese código tan simple podemos usar rutas del tipo:&lt;br /&gt;&lt;br /&gt;http://server/posts&lt;br /&gt;http://server/posts?filter=published&lt;br /&gt;http://server/posts?filter=published,from_user&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-4025227692892532891?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/4025227692892532891/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=4025227692892532891&amp;isPopup=true' title='2 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/4025227692892532891'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/4025227692892532891'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2009/03/combinacion-de-namedscopes-en-rails.html' title='Combinación de named_scopes en rails'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-892146013650285857</id><published>2009-03-01T14:58:00.003+01:00</published><updated>2009-03-01T15:23:47.497+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Optimización del tiempo de carga de webs</title><content type='html'>Dentro del tiempo total desde que se hace una petición a una página web hasta que se termina de dibujar en el navegador, gran parte corresponde a los distintos recursos externos que hay que recuperar: javascript, css e imágenes.&lt;br /&gt;&lt;br /&gt;Los ficheros javascript y css tienen una propiedad interesante, si se concatenan varios y se envían en un solo fichero no debe influir en el resultado final. &lt;br /&gt;Sin embargo, si se concatenan, se pueden cargar con una sola petición, con el consiguiente aumento de rendimiento.&lt;br /&gt;&lt;br /&gt;El método que rails proporciona para hacer esto de forma automática es el siguiente (solo en  modo producción):&lt;br /&gt;&lt;pre class="ruby:nocontrols" name="code"&gt;&lt;br /&gt;&amp;lt;%= javascript_include_tag 'first.js', 'second.js', :cache =&gt; '1_2' %&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Sin embargo esto tiene un problema, normalmente en una aplicación según la página se carga unos ficheros u otros, no es muy práctico ir dándole claves a todas las combinaciones.&lt;br /&gt;&lt;br /&gt;Se pueden programar dos helpers para dar las claves de forma automática:&lt;br /&gt;&lt;pre class="ruby:nocontrols" name="code"&gt;&lt;br /&gt;&amp;lt;%= cached_javascript_include_tag 'first.js', 'second.js' %&amp;gt;&lt;br /&gt;&amp;lt;%= cached_stylesheet_link_tag 'first.css', 'second.css' %&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Es importante que las versiones cacheadas tanto de css como de javascript no estén en el svn, a la hora de hacer un despliegue se regenerarán usando la nueva versión de los ficheros.&lt;br /&gt;&lt;br /&gt;Aún así, si se quiere que se genere de nuevo la versión cacheada para una página sin desplegar la aplicación ni borrar los ficheros antiguos, se puede usar un sistema de versiones.&lt;br /&gt;&lt;pre class="ruby:nocontrols" name="code"&gt;&lt;br /&gt;&amp;lt;%= cached_javascript_include_tag 'first.js?v=1', 'second.js?v=3' %&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;El código de los helpers es el siguiente:&lt;br /&gt;&lt;pre class="ruby:nocontrols" name="code"&gt;&lt;br /&gt;module ApplicationHelper&lt;br /&gt;  def cached_javascript_include_tag(*args)&lt;br /&gt;    cached_args!(*args)&lt;br /&gt;    javascript_include_tag(*args)&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def cached_stylesheet_link_tag(*args)&lt;br /&gt;    cached_args!(*args)&lt;br /&gt;    stylesheet_link_tag(*args)&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def cached_args!(*args)&lt;br /&gt;    options = args.extract_options!.stringify_keys&lt;br /&gt;&lt;br /&gt;    cache_entry = args.map(&amp;:to_s).sort.join('_').gsub!('?', '_')&lt;br /&gt;    options[:cache] = cache_entry&lt;br /&gt;&lt;br /&gt;    args &amp;lt;&amp;lt; options&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-892146013650285857?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/892146013650285857/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=892146013650285857&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/892146013650285857'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/892146013650285857'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2009/03/optimizacion-del-tiempo-de-carga-de.html' title='Optimización del tiempo de carga de webs'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-2782165044622791157</id><published>2009-01-11T11:43:00.002+01:00</published><updated>2009-01-11T11:52:45.762+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Observadores personalizables en rails</title><content type='html'>En rails hay unas clases llamadas observadores que sirven para redefinir los métodos que necesitemos en el ciclo de vida de los objetos (&lt;span style="font-style:italic;"&gt;after&lt;/span&gt;_update, before_&lt;span style="font-style:italic;"&gt;create&lt;/span&gt;, etc...).&lt;br /&gt;&lt;br /&gt;El problema es que en ocasiones con los métodos del ciclo de vida no es suficiente, una situación muy común es redefinir el método after_&lt;span style="font-style:italic;"&gt;save&lt;/span&gt;, y cada vez que se guarde un objeto comprobar una condición y actuar si es necesario.&lt;br /&gt;&lt;br /&gt;Afortunadamente existe un método en ActiveRecord para notificar a los observadores exactamente cuando queramos y de lo que queramos, de la siguiente forma.&lt;br /&gt;&lt;br /&gt;En el modelo:&lt;br /&gt;&lt;pre class="ruby:nocontrols" name="code"&gt;&lt;br /&gt;class Post &lt; ActiveRecord::Base&lt;br /&gt; def just_created&lt;br /&gt;  notify :manage_task&lt;br /&gt; end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;En el observador:&lt;br /&gt;&lt;pre class="ruby:nocontrols" name="code"&gt;&lt;br /&gt;class GlobalObserver &lt; ActiveRecord::Observer&lt;br /&gt; observe Post&lt;br /&gt; &lt;br /&gt; def manage_task(object)&lt;br /&gt;  #do something&lt;br /&gt; end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-2782165044622791157?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/2782165044622791157/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=2782165044622791157&amp;isPopup=true' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/2782165044622791157'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/2782165044622791157'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2009/01/observadores-personalizables-en-rails.html' title='Observadores personalizables en rails'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-1601596932754077655</id><published>2009-01-02T18:33:00.002+01:00</published><updated>2009-01-02T18:39:56.300+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>Carga de css dinámica</title><content type='html'>Es habitual en webs en las que cada usuario tiene una página personal permitirle cambiar la apariencia mediante temas (skins).&lt;br /&gt;&lt;br /&gt;Para cargar un css nuevo de forma dinámica se puede usar la siguiente función javascript o algún variante.&lt;br /&gt;&lt;pre class="ruby:nocontrols" name="code"&gt;&lt;br /&gt;function loadCSS(cssFile){&lt;br /&gt; var cssLink=document.createElement("link");&lt;br /&gt; cssLink.setAttribute("rel", "stylesheet");&lt;br /&gt; cssLink.setAttribute("type", "text/css");&lt;br /&gt; cssLink.setAttribute("href", cssFile);&lt;br /&gt; document.getElementsByTagName("head")[0].appendChild(cssLink);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Lo que hace esta función es crear un elemento link que apunta a un css y lo inserta en el head de la página.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-1601596932754077655?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/1601596932754077655/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=1601596932754077655&amp;isPopup=true' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/1601596932754077655'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/1601596932754077655'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2009/01/carga-de-css-dinmica.html' title='Carga de css dinámica'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-4614402475376996117</id><published>2008-12-28T00:03:00.003+01:00</published><updated>2009-07-15T11:21:33.027+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Crear demonios en ruby</title><content type='html'>Para crear un demonio hay que duplicar el proceso actual (hacer un fork) y distinguir a cada una de las instancias para la que instancia hija se encargue del trabajo en background que queremos realizar.&lt;br /&gt;&lt;br /&gt;En ruby todo este proceso se puede realizar automáticamente utilizando el módulo ruby daemon de la siguiente forma.&lt;br /&gt;&lt;pre class="ruby:nocontrols" name="code"&gt;&lt;br /&gt;require 'daemons'&lt;br /&gt;&lt;br /&gt;class Demonio&lt;br /&gt; def initialize&lt;br /&gt;  Daemons.daemonize&lt;br /&gt;  loop do&lt;br /&gt;   f = File.new('/tmp/timestamp', 'a')&lt;br /&gt;   f.write("#{Time.now}\n")&lt;br /&gt;   f.close&lt;br /&gt;   sleep(3)&lt;br /&gt;  end&lt;br /&gt; end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;Demonio.new&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-4614402475376996117?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/4614402475376996117/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=4614402475376996117&amp;isPopup=true' title='3 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/4614402475376996117'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/4614402475376996117'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/12/crear-demonios-en-ruby.html' title='Crear demonios en ruby'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-4003535662469725820</id><published>2008-12-26T23:44:00.004+01:00</published><updated>2008-12-27T00:02:29.580+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Redefinir el método de comparación con expresiones regulares</title><content type='html'>Para mejorar la búsqueda en los datos de los objetos se puede aprovechar que en ruby se puede redefinir el método de comparación con expresiones regulares (=~).&lt;br /&gt;&lt;br /&gt;Un ejemplo.&lt;br /&gt;&lt;pre class="ruby:nocontrols" name="code"&gt;&lt;br /&gt;class Persona&lt;br /&gt; attr_accessor :nombre, :apellidos, :direccion&lt;br /&gt; &lt;br /&gt; def initialize(nombre, apellidos, direccion)&lt;br /&gt;  self.nombre = nombre&lt;br /&gt;  self.apellidos = apellidos&lt;br /&gt;  self.direccion = direccion&lt;br /&gt; end &lt;br /&gt; &lt;br /&gt; def =~(re)&lt;br /&gt;  "#{self.nombre} #{self.apellidos} #{self.direccion}" =~ re&lt;br /&gt; end&lt;br /&gt; &lt;br /&gt; def self.search(ciudad, input)&lt;br /&gt;  query = Regexp.new(input, 'i')&lt;br /&gt;  ciudad.select{|p| p =~ query} &lt;br /&gt; end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;p1 = Persona.new('Jose', 'Gonzalez', 'Sol')&lt;br /&gt;p2 = Persona.new('Francisco', 'Martinez', 'Preciados')&lt;br /&gt;p3 = Persona.new('Fernando', 'Solano', 'Serrano')&lt;br /&gt;&lt;br /&gt;Madrid = [p1, p2, p3]&lt;br /&gt;&lt;br /&gt;puts Persona.search(Madrid, 'sol').map(&amp;:nombre)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;El modificador &lt;span style="font-style:italic;"&gt;'i'&lt;/span&gt; del constructor de expresiones regulares hace que no distinga entre mayúsculas y minúsculas.&lt;br /&gt;Concatenando los campos en los que queremos buscar se obtiene un &lt;span style="font-style:italic;"&gt;matching&lt;/span&gt; más completo.&lt;br /&gt;&lt;br /&gt;Con el &lt;span style="font-style:italic;"&gt;map&lt;/span&gt; final se imprimen los nombres de las personas que hayan coincidido con la búsqueda.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-4003535662469725820?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/4003535662469725820/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=4003535662469725820&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/4003535662469725820'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/4003535662469725820'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/12/redefinir-el-mtodo-de-comparacin-con.html' title='Redefinir el método de comparación con expresiones regulares'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-3561711464856743611</id><published>2008-12-14T13:09:00.004+01:00</published><updated>2008-12-14T13:31:11.886+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Recuperación automática de procesos erlang</title><content type='html'>La mayor ventaja que proporciona erlang es la gran potencia que tiene para la programación de procesos concurrentes.&lt;br /&gt;&lt;br /&gt;Cuando se diseña software que va a ser programado en erlang suele dividirse el trabajo en múltiples procesos, además provee de mecanismos para comprobar fácilmente entre procesos si alguno se ha colgado y restaurarlo o ejecutar cualquier otra acción.&lt;br /&gt;&lt;br /&gt;En el siguiente ejemplo.&lt;br /&gt;&lt;pre class="ruby:nocontrols" name="code"&gt;&lt;br /&gt;-module(lib_misc).&lt;br /&gt;-export([link_p/1, start/0, loop/0]).&lt;br /&gt;&lt;br /&gt;start() -&amp;gt; &lt;br /&gt; Pid = spawn(fun loop/0),&lt;br /&gt; register(divisor, Pid),&lt;br /&gt; spawn(lib_misc, link_p, [Pid]),&lt;br /&gt; Pid.&lt;br /&gt;&lt;br /&gt;loop() -&amp;gt;&lt;br /&gt; receive&lt;br /&gt;  {A, B} -&amp;gt;&lt;br /&gt;   io:format("~nDivision: ~p", [A/B]),&lt;br /&gt;   loop()&lt;br /&gt; end.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;link_p(Pid) -&amp;gt;&lt;br /&gt; process_flag(trap_exit, true),&lt;br /&gt; link(Pid),&lt;br /&gt; receive&lt;br /&gt;  {'EXIT', Pid, _} -&amp;gt; &lt;br /&gt;   NewPid = spawn_link(lib_misc, loop, []),&lt;br /&gt;   register(divisor, NewPid),&lt;br /&gt;   link_p(NewPid)&lt;br /&gt; end.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Al compilar la librería y arrancarla se ejecutan dos procesos, el principal &lt;span style="font-style:italic;"&gt;loop&lt;/span&gt; y otro llamado &lt;span style="font-style:italic;"&gt;link_p&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;El bucle principal simplemente recibe una tupla con dos números y los divide. Tiene al menos un error conocido y es que no comprueba cuando el divisor es cero.&lt;br /&gt;&lt;br /&gt;El proceso &lt;span style="font-style:italic;"&gt;link_p&lt;/span&gt; se enlaza al principal, la tarea de este proceso es esperar a que el principal se cuelgue (por ejemplo, división entre cero).&lt;br /&gt;En el momento en el que el programa principal se ha colgado, recibe el mensaje de salida, restaura el proceso y se enlaza al nuevo.&lt;br /&gt;&lt;br /&gt;Hay un detalle más, al iniciar un nuevo proceso el pid del antiguo no nos sirve para mandarle mensajes, así que se registra el átomo &lt;span style="font-style:italic;"&gt;divisor&lt;/span&gt; para tener siempre una referencia global.&lt;br /&gt;&lt;br /&gt;Registrar un nombre global estático no es la mejor solución, ya que no se pueden iniciar múltiples instancias del proceso divisor, debería ser un parámetro, lo he dejado así por que el ejemplo fuera más sencillo.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-3561711464856743611?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/3561711464856743611/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=3561711464856743611&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3561711464856743611'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3561711464856743611'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/12/recuperacin-automtica-de-procesos.html' title='Recuperación automática de procesos erlang'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-9009091976061616304</id><published>2008-12-08T11:24:00.002+01:00</published><updated>2008-12-08T11:37:03.795+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Funciones anónimas recursivas en Erlang</title><content type='html'>En erlang se pueden definir funciones anónimas con la palabra reservada &lt;span style="font-style:italic;"&gt;fun&lt;/span&gt;, aunque se pueden guardar en una variable para referenciarlas posteriormente.&lt;br /&gt;&lt;br /&gt;La sintaxis es la siguiente:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;IsZero = fun(0) -&gt; 1; (N) -&gt; 0 end.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Esta función devuelve 1 (verdad) si el parámetro es 0, falso en cualquier otro caso.&lt;br /&gt;&lt;br /&gt;El problema es que de esta forma no se pueden definir funciones recursivas, ya que al no estar definida la función dentro de su definición, no podemos referenciarla, para solucionarlo se puede pasar un parámetro extra, que sea la propia función.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Factorial = fun(1, F) -&gt; 1; (N, F) -&gt; N * F(N-1, F) end.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;En este último caso habría que llamar a la función como &lt;span style="font-style:italic;"&gt;Factorial(número, Factorial)&lt;/span&gt;, lo que queda poco intuitivo, se puede mejorar creando dos funciones en lugar de una.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Fact = fun(1, F) -&gt; 1; (N, F) -&gt; N * F(N-1, F) end.&lt;br /&gt;Factorial = fun(N) -&gt; Fact(N, Fact) end.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-9009091976061616304?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/9009091976061616304/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=9009091976061616304&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/9009091976061616304'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/9009091976061616304'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/12/funciones-annimas-recursivas-en-erlang.html' title='Funciones anónimas recursivas en Erlang'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-3373393185136560940</id><published>2008-11-30T19:03:00.002+01:00</published><updated>2008-11-30T19:28:09.801+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>Terminales virtuales en linux</title><content type='html'>Regularmente cuando administramos equipos unix necesitamos varios terminales, por ejemplo, en el caso de estar administrando un equipo linux remoto por ssh.&lt;br /&gt;&lt;br /&gt;Para poder tener varios terminales podemos loguearnos varias veces y usar cada conexión como un terminal, sin embargo esto está lejos de ser óptimo, una sola conexión es más que suficiente para tener abiertas varios terminales.&lt;br /&gt;&lt;br /&gt;El comando &lt;span style="font-style:italic;"&gt;screen&lt;/span&gt; de linux permite crear terminales virtuales, por lo que este problema lo tendríamos resuelto, su funcionamiento es muy simple.&lt;br /&gt;&lt;br /&gt;Ejecutando:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;sreen bash&lt;/span&gt;, abrimos una instancia nueva de bash en otro terminal.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Ctrl+A "&lt;/span&gt;, muestra una lista de los terminales virtuales.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Ctr+A 2&lt;/span&gt;, va a la tercera consola virtual (numeradas desde 0).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Ctrl+A Ctrl+A&lt;/span&gt;, va a la consola mostrada anteriormente.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Ctrl+A d&lt;/span&gt;, deja ejecutando las tareas en background (detach).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-3373393185136560940?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/3373393185136560940/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=3373393185136560940&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3373393185136560940'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3373393185136560940'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/11/terminales-virtuales-en-linux.html' title='Terminales virtuales en linux'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-2193556984653707423</id><published>2008-11-30T12:49:00.005+01:00</published><updated>2008-11-30T13:07:18.602+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><title type='text'>Expiration time en fragment caching</title><content type='html'>Cuando se usa el sistema de caché de rails se pueden elegir donde guardar los items cacheados, la mejor opción es la mayoría de los casos es memcached, pero no siempre tenemos posibilidad de instalar un demonio en la máquina que da hosting.&lt;br /&gt;&lt;br /&gt;Otra posibilidad es guardar los items en el sistema de ficheros, para ello hay que añadir en el environment.rb lo siguiente.&lt;br /&gt;&lt;pre name="code" class="ruby:nocontrols"&gt;&lt;br /&gt;config.cache_store = :file_store, '/path_to_cache'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;El problema que tiene usar el sistema de ficheros como soporte para la cache es que no soporta la opción de expiración por tiempo, sin embargo memcached sí que lo hace.&lt;br /&gt;&lt;br /&gt;Se puede solucionar añadiendo el siguiente parche al environment.rb&lt;br /&gt;&lt;pre name="code" class="ruby:nocontrols"&gt;&lt;br /&gt;module ActiveSupport&lt;br /&gt;  module Cache&lt;br /&gt;    class FileStore &amp;lt; Store&lt;br /&gt;      def read(name, options = nil)&lt;br /&gt;        super&lt;br /&gt;        timestamp = File.open("#{real_file_path(name)}.timestamp", 'rb') { |f| f.read } rescue nil&lt;br /&gt;        if !timestamp or (timestamp and timestamp.to_i &amp;gt; Time.now.to_i)&lt;br /&gt;          File.open(real_file_path(name), 'rb') { |f| f.read } rescue nil&lt;br /&gt;        else&lt;br /&gt;          nil&lt;br /&gt;        end&lt;br /&gt;      end&lt;br /&gt;&lt;br /&gt;      def write(name, value, options = nil)&lt;br /&gt;        super&lt;br /&gt;        ensure_cache_path(File.dirname(real_file_path(name)))&lt;br /&gt;        if options and options[:expires_in] &lt;br /&gt;          File.open("#{real_file_path(name)}.timestamp", "wb+") { |f| f.write(Time.now.to_i + options[:expires_in].to_i) } &lt;br /&gt;        end&lt;br /&gt;        File.open(real_file_path(name), "wb+") { |f| f.write(value) }&lt;br /&gt;      rescue =&gt; e&lt;br /&gt;        RAILS_DEFAULT_LOGGER.error "Couldn't create cache directory: #{name} (#{e.message})" if RAILS_DEFAULT_LOGGER&lt;br /&gt;      end&lt;br /&gt;&lt;br /&gt;      def delete(name, options = nil)&lt;br /&gt;        super&lt;br /&gt;        File.delete("#{real_file_path(name)}.timestamp") rescue  nil &lt;br /&gt;        File.delete(real_file_path(name)) rescue nil&lt;br /&gt;      end&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Se puede utilizar al igual que la opción expires_in en memcached.&lt;br /&gt;&lt;pre name="code" class="ruby:nocontrols"&gt;&lt;br /&gt;&amp;lt;% cache 'something', :expires_in =&gt; 5.minutes do %&amp;gt;&lt;br /&gt; Hello, just saying hello from cache&lt;br /&gt;&amp;lt;% end %&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Lo he desarrollado teniendo en cuenta la implementación de rails 2.1.2, y solo soporta fragment caching.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-2193556984653707423?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/2193556984653707423/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=2193556984653707423&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/2193556984653707423'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/2193556984653707423'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/11/expiration-time-en-fragment-caching.html' title='Expiration time en fragment caching'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-1192810205120246433</id><published>2008-11-26T22:16:00.003+01:00</published><updated>2008-11-26T22:31:06.059+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='memcached'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><title type='text'>Fragment caching en rails</title><content type='html'>Usando memcached y fragment caching se puede acelerar mucho la reconstrucción de las vistas en rails.&lt;br /&gt;&lt;br /&gt;Para ello, una vez instalado memcached lo ejecutamos:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;memcached -d&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Por defecto estará en el puerto 11211.&lt;br /&gt;&lt;br /&gt;En el environment.rb hay que configurar la caché para que utilice memcached.&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="ruby:nocontrols"&gt;&lt;br /&gt;config.cache_store = :mem_cache_store&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Tras eso en las vistas podemos hacer lo siguiente:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="ruby:nocontrols"&gt;&lt;br /&gt;&amp;lt;% cache 'key', :expires_in =&gt; 300 do %&amp;gt;&lt;br /&gt;  texto html...&lt;br /&gt;&amp;lt;% end %&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;300 es el número de segundos que este trozo estará vigente en caché, si no se indica nada el fragmento no expirará a no ser que lo indiquemos manualmente con &lt;a href="http://api.rubyonrails.org/classes/ActionController/Caching/Fragments.html"&gt;expire_fragment&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;key&lt;/span&gt; es la clave que tiene el fragmento dentro de la vista, es necesario para distinguir los distintos fragmentos.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-1192810205120246433?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/1192810205120246433/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=1192810205120246433&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/1192810205120246433'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/1192810205120246433'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/11/fragment-caching-en-rails.html' title='Fragment caching en rails'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-6278067135345712775</id><published>2008-11-15T23:37:00.009+01:00</published><updated>2008-11-16T01:18:38.340+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Memoization en ruby</title><content type='html'>La &lt;span style="font-style: italic;"&gt;memoization&lt;/span&gt; es una técnica de optimización que consiste en recordar los resultados para anteriores llamadas a una función.&lt;br /&gt;&lt;br /&gt;Si para una llamada anterior a una función se han pasado los parámetros x=2 e y=3, la próxima vez se devolverá el mismo resultado al obtenido, sin repetir cálculos.&lt;br /&gt;&lt;br /&gt;La implementación es muy sencilla y se pueden obtener mejoras muy significativas en funciones con cálculos pesados, basta con tener una tabla en la que utilicemos los parámetros de entrada como índices y el resultado de la función como valor.&lt;br /&gt;&lt;br /&gt;Si ya de por sí es sencillo implementar la memoization en ruby se puede usar también la gema que hay específica para &lt;a href="http://raa.ruby-lang.org/project/memoize/"&gt;ello&lt;/a&gt;, esta gema implementa la memoization automática, por lo que ni siquiera es necesario mantener una tabla para los valores, la gema se encarga de ello.&lt;br /&gt;&lt;br /&gt;Es necesario recordar que en la memoization solo se tienen en cuenta los parámetros de entrada, por lo que a las funciones que produzcan resultados a partir de otras entradas (ficheros, hora actual...) no se les debe aplicar esta técnica.&lt;br /&gt;&lt;br /&gt;En el siguiente ejemplo se implementa la función de fibonacci recursiva (fib1), la misma función aplicándole la memoization (fib2) y por último la memoization automática a fib1. En mi máquina para este ejemplo se obtienen ganancias de 30 a 40 veces en las versiones memoizadas.&lt;br /&gt;&lt;pre name="code" class="ruby:nocontrols"&gt;&lt;br /&gt;require 'rubygems'&lt;br /&gt;require 'memoize'&lt;br /&gt;&lt;br /&gt;include Memoize&lt;br /&gt;&lt;br /&gt;def fib1(n)&lt;br /&gt; return n if n &lt; 2&lt;br /&gt; return fib1(n-1) + fib1(n-2)&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;@mm = {}&lt;br /&gt;def fib2(n)&lt;br /&gt; return @mm[n] if @mm[n]&lt;br /&gt; return n if n &lt; 2&lt;br /&gt; &lt;br /&gt; @mm[n] = fib2(n-1) + fib2(n-2)&lt;br /&gt; return @mm[n]&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;puts fib1(30)&lt;br /&gt;puts fib2(30)&lt;br /&gt;&lt;br /&gt;memoize(:fib1)&lt;br /&gt;puts fib1(30)&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-6278067135345712775?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/6278067135345712775/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=6278067135345712775&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/6278067135345712775'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/6278067135345712775'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/11/memoization-en-ruby.html' title='Memoization en ruby'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-8764275380724963253</id><published>2008-11-09T15:28:00.002+01:00</published><updated>2008-11-09T15:40:56.143+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><title type='text'>Ocultar parámetros del log de rails</title><content type='html'>Al igual que se suelen encriptar las contraseñas al guardarlas en las bases de datos de las aplicaciones con autentificación, también se deberían omitir este tipo de campos en el log de rails.&lt;br /&gt;&lt;br /&gt;Cuando se despliega rails en un entorno en producción normalmente guarda el log de todas las peticiones en &lt;span style="font-style:italic;"&gt;log/production.log&lt;/span&gt;, ahí se pueden ver todos los parámetros que se pasan a la aplicación, incluyendo contraseñas, números de tarjetas de crédito, etc.&lt;br /&gt;&lt;br /&gt;Hay una forma de hacer que determinados parámetros no aparezcan, llamando a &lt;span style="font-style:italic;"&gt;filter_parameter_logging&lt;/span&gt; en el controlador.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 1px solid black; padding: 5px; background-color: rgb(51, 102, 153); color: rgb(0, 0, 0);"&gt;&lt;pre wrap=""&gt;class AccountsController &lt; ApplicationController&lt;br /&gt;  filter_parameter_logging :card_number&lt;br /&gt;&lt;br /&gt;  def index&lt;br /&gt;    @accounts = Account.find(:all)&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;En el log aparecerá algo así.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Parameters: {"card_number"=&gt;"[FILTERED]"...&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-8764275380724963253?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/8764275380724963253/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=8764275380724963253&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/8764275380724963253'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/8764275380724963253'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/11/ocultar-parmetros-del-log-de-rails.html' title='Ocultar parámetros del log de rails'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-5515866228815204143</id><published>2008-11-02T21:56:00.002+01:00</published><updated>2008-11-02T22:05:41.599+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Generacion dinámica de métodos en ruby</title><content type='html'>Una característica que puede añadir mucha potencia a los módulos que creamos en ruby es la generación automática de métodos.&lt;br /&gt;&lt;br /&gt;Se usa intensivamente en rails, tanto en la implementación de ActiveRecord como de la mayoría de plugins.&lt;br /&gt;&lt;br /&gt;Para definir métodos de forma dinámica tan solo hay que redefinir &lt;span style="font-style:italic;"&gt;method_missing&lt;/span&gt;, este método se llama cada vez que se llama a una función no definida, recibe como primer parámetro el nombre del método y como segundo parámetro la lista de argumentos.&lt;br /&gt;&lt;br /&gt;Dejo un ejemplo.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 1px solid black; padding: 5px; background-color: rgb(51, 102, 153); color: rgb(0, 0, 0);"&gt;&lt;pre wrap=""&gt;#!/usr/bin/ruby&lt;br /&gt;&lt;br /&gt;def method_missing(method, *args)&lt;br /&gt; if method.to_s =~ /saludo_(\w+)/&lt;br /&gt;  generar_saludo($1)&lt;br /&gt; else&lt;br /&gt;  super(method, *args)&lt;br /&gt; end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def generar_saludo(msg)&lt;br /&gt; puts "hola #{msg}"&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;saludo_mundo&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-5515866228815204143?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/5515866228815204143/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=5515866228815204143&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/5515866228815204143'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/5515866228815204143'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/11/generacion-dinmica-de-mtodos-en-ruby.html' title='Generacion dinámica de métodos en ruby'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-7916707219428312417</id><published>2008-11-01T21:58:00.002+01:00</published><updated>2008-11-01T22:09:16.810+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Crear clases dinámicas en ruby</title><content type='html'>La sintaxis de ruby para crear clases u objetos es muy sencilla, pero lo es más aún para definirlos dinámicamente.&lt;br /&gt;&lt;br /&gt;Para ello disponemos de la clase &lt;a href="http://www.ruby-doc.org/core/classes/Struct.html"&gt;Struct&lt;/a&gt;, veamos un ejemplo en el siguiente código.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 1px solid black; padding: 5px; background-color: rgb(51, 102, 153); color: rgb(0, 0, 0);"&gt;&lt;pre wrap=""&gt;Clase = Struct.new :campo1, :campo2&lt;br /&gt;objeto = Clase.new('valor1', 'valor2')&lt;br /&gt;puts objeto.campo1&lt;br /&gt;puts objeto.campo2&lt;br /&gt;puts objeto.members&lt;br /&gt;puts objeto.values&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;En la primera línea con &lt;span style="font-style:italic;"&gt;Struct&lt;/span&gt; se crea la clase &lt;span style="font-style:italic;"&gt;Clase&lt;/span&gt; con dos campos, esos campos ya están disponibles en los objetos que creemos a partir de la clase. Adicionalmente, &lt;span style="font-style:italic;"&gt;Struct&lt;/span&gt; añade algunos métodos como &lt;span style="font-style:italic;"&gt;members&lt;/span&gt; y &lt;span style="font-style:italic;"&gt;values&lt;/span&gt; para inspeccionar el contenido de los objetos creados.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-7916707219428312417?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/7916707219428312417/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=7916707219428312417&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/7916707219428312417'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/7916707219428312417'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/11/crear-clases-dinmicas-en-ruby.html' title='Crear clases dinámicas en ruby'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-3626569721371624764</id><published>2008-10-26T22:05:00.002+01:00</published><updated>2008-10-26T22:32:54.373+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><category scheme='http://www.blogger.com/atom/ns#' term='php'/><title type='text'>Metaprogramación en php</title><content type='html'>En php5 han entrado nuevas posibilidades en lo que a metaprogramación se refiere, revisando el siguiente trozo de código nos encontramos un ejemplo de que construcciones se pueden realizar.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 1px solid black; padding: 5px; background-color: rgb(51, 102, 153); color: rgb(0, 0, 0);"&gt;&lt;pre wrap=""&gt;&amp;lt;?php&lt;br /&gt;&lt;br /&gt;function saludo(){&lt;br /&gt;        return "hello";&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;$cadena = "saludo";&lt;br /&gt;$cadena_funcion = "cadena";&lt;br /&gt;?&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;?= $cadena() ?&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;br/&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;?= $$cadena_funcion() ?&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Primero podemos ver que si guardamos en una cadena el nombre de una función, y luego llamamos a la cadena con una lista de parámetros (en este caso vacía), se invoca dicha función. Esto puede ser bastante útil para elegir que acción ejecutar ante una entrada por parámetro.&lt;br /&gt;&lt;br /&gt;En segundo lugar se muestra como utilizar las variables con doble '$', es decir, las variables de variables. Por cada '$' delante del nombre de la variable se hace una evaluación de la variable.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;$cadena_funcion&lt;/span&gt; contiene la cadena "cadena", si por el contrario se referencia a &lt;span style="font-style:italic;"&gt;$$cadena_funcion&lt;/span&gt;, se evaluará la variable &lt;span style="font-style:italic;"&gt;$cadena&lt;/span&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-3626569721371624764?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/3626569721371624764/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=3626569721371624764&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3626569721371624764'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3626569721371624764'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/10/metaprogramacin-en-php.html' title='Metaprogramación en php'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-7151897446483310684</id><published>2008-10-21T21:00:00.002+02:00</published><updated>2008-10-21T21:06:17.096+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Programación funcional con javascript</title><content type='html'>En programación funcional se usa las funciones &lt;span style="font-style:italic;"&gt;map&lt;/span&gt;, &lt;span style="font-style:italic;"&gt;filter&lt;/span&gt; y &lt;span style="font-style:italic;"&gt;reduce&lt;/span&gt; para manipular colecciones.&lt;br /&gt;&lt;br /&gt;En javascript se pueden implementar fácilmente de la siguiente manera.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 1px solid black; padding: 5px; background-color: rgb(51, 102, 153); color: rgb(0, 0, 0);"&gt;&lt;pre wrap=""&gt;function map(f, a){&lt;br /&gt; var r=new Array();&lt;br /&gt; for(var i=0;i&amp;lt;a.length;i++){&lt;br /&gt;  r.push(f(a[i]));&lt;br /&gt; }&lt;br /&gt; return r;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function filter(f, a){&lt;br /&gt; var r=new Array();&lt;br /&gt; for(var i=0;i&amp;lt;a.length;i++){&lt;br /&gt;  if(f(a[i])){&lt;br /&gt;   r.push(a[i])&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt; return r;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function reduce(f, a){&lt;br /&gt; if(a.length&amp;lt;1){&lt;br /&gt;  return a&lt;br /&gt; }&lt;br /&gt; else{&lt;br /&gt;  var r=a[0].__proto__;&lt;br /&gt;  for(var i=0;i&amp;lt;a.length;i++){&lt;br /&gt;   r=f(r, a[i])&lt;br /&gt;  }&lt;br /&gt;  return r;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-7151897446483310684?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/7151897446483310684/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=7151897446483310684&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/7151897446483310684'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/7151897446483310684'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/10/programacin-funcional-con-javascript.html' title='Programación funcional con javascript'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-8614299931165016738</id><published>2008-10-19T13:21:00.002+02:00</published><updated>2008-10-19T13:37:15.007+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><category scheme='http://www.blogger.com/atom/ns#' term='c'/><title type='text'>Implementación de un memory pool</title><content type='html'>En aplicaciones en las que se reserva y libera memoria con mucha frecuencia se puede sufrir &lt;a href="http://en.wikipedia.org/wiki/Memory_fragmentation"&gt;fragmentación de memoria&lt;/a&gt;. Cuando el rendimiento no es demasiado importante este comportamiento puede ser aceptable, en cambio, si esto se produce en una aplicación de tiempo real es necesario solucionarlo.&lt;br /&gt;&lt;br /&gt;Para evitar la fragmentación de memoria existe una técnica llamada memory pool, básicamente consiste en crear un espacio fijo de memoria para que la aplicación lo administe.&lt;br /&gt;&lt;br /&gt;En el siguiente ejemplo se crea un pool para un conjunto de threads que lo comparten.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 1px solid black; padding: 5px; background-color: rgb(51, 102, 153); color: rgb(0, 0, 0);"&gt;&lt;pre wrap=""&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;#include &amp;lt;string.h&amp;gt;&lt;br /&gt;#include &amp;lt;pthread.h&amp;gt;&lt;br /&gt;&lt;br /&gt;#define BUF_SIZE 128&lt;br /&gt;#define POOL_SIZE 36&lt;br /&gt;#define NUM_THREADS 10&lt;br /&gt;&lt;br /&gt;typedef struct dataStruct{&lt;br /&gt; int id;&lt;br /&gt; char cadena[BUF_SIZE];&lt;br /&gt;} data;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;&lt;br /&gt;&lt;br /&gt;data **dataPool;&lt;br /&gt;int next_data = 0;&lt;br /&gt;&lt;br /&gt;int get_next_memory_position(){&lt;br /&gt; pthread_mutex_lock(&amp;mutex); &lt;br /&gt; next_data = (next_data + 1) % POOL_SIZE;&lt;br /&gt; pthread_mutex_unlock(&amp;mutex);&lt;br /&gt; return next_data;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;data **allocate_pool(){&lt;br /&gt; int i; &lt;br /&gt; data **d = (data**) malloc(sizeof(data*) * POOL_SIZE);&lt;br /&gt; &lt;br /&gt; for(i = 0;i &amp;lt; POOL_SIZE; i++){&lt;br /&gt;  d[i] = malloc(sizeof(data));&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; return d;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void *thread(){&lt;br /&gt; data *param = dataPool[get_next_memory_position()];&lt;br /&gt; &lt;br /&gt; param-&amp;gt;id = next_data;&lt;br /&gt; strcpy(param-&amp;gt;cadena, "hello");&lt;br /&gt; &lt;br /&gt; printf("%d: %s \n", param-&amp;gt;id, param-&amp;gt;cadena);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main(){&lt;br /&gt; pthread_t t[NUM_THREADS];&lt;br /&gt; dataPool = allocate_pool();&lt;br /&gt; int i;&lt;br /&gt; &lt;br /&gt; for(i = 0;i &amp;lt; NUM_THREADS; i++){&lt;br /&gt;  pthread_create(&amp;t[i], NULL, thread, NULL);&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; for(i = 0;i &amp;lt; NUM_THREADS; i++){&lt;br /&gt;  pthread_join(t[i], NULL);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;En este ejemplo se asigna automáticamente memoria a los threads conforme la piden circularmente, este planteamiento no vale siempre, para cambiar la política de asignación de bloques libres solo hay que cambiar el método &lt;span style="font-style:italic;"&gt;get_next_memory_position&lt;/span&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-8614299931165016738?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/8614299931165016738/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=8614299931165016738&amp;isPopup=true' title='2 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/8614299931165016738'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/8614299931165016738'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/10/implementacin-de-un-memory-pool.html' title='Implementación de un memory pool'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-6446879445239046870</id><published>2008-10-18T20:27:00.003+02:00</published><updated>2008-10-18T20:55:15.856+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><category scheme='http://www.blogger.com/atom/ns#' term='css'/><title type='text'>Simulando enlaces con javascript</title><content type='html'>En algunas ocasiones necesitamos poner un enlace en un elemento del DOM de una web que no acepta la propiedad href.&lt;br /&gt;&lt;br /&gt;Normalmente ocurre cuando se quiere añadir un hipervínculo que no estaba previsto al realizar la maquetación. &lt;br /&gt;&lt;br /&gt;Para esos casos se puede simular el comportamiento de un enlace mediante javascript.&lt;br /&gt;&lt;br /&gt;Supongamos que el div con id 'texto' es el que queremos que tenga un enlace a otra página, con el evento &lt;span style="font-style:italic;"&gt;onclick&lt;/span&gt; y cambiando el &lt;span style="font-style:italic;"&gt;document.location&lt;/span&gt; podemos irnos a la página que queremos al pinchar en el elemento.&lt;br /&gt;&lt;br /&gt;El problema es que al pasar por encima el ratón nada nos indica que es un enlace, con el evento &lt;span style="font-style:italic;"&gt;onmouseover&lt;/span&gt; y cambiando la propiedad css &lt;span style="font-style:italic;"&gt;cursor&lt;/span&gt; podemos hacer que parezca un enlace.&lt;br /&gt;&lt;br /&gt;Un ejemplo de como quedaría.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 1px solid black; padding: 5px; background-color: rgb(51, 102, 153); color: rgb(0, 0, 0);"&gt;&lt;pre wrap=""&gt;&amp;lt;html&gt;&amp;lt;body&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;div id="texto" onclick="document.location='http://google.com'" onmouseover="this.style.cursor='pointer'"&amp;gt;lorem ipsum&amp;lt;/div&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/body&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-6446879445239046870?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/6446879445239046870/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=6446879445239046870&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/6446879445239046870'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/6446879445239046870'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/10/simulando-enlaces-con-javascript.html' title='Simulando enlaces con javascript'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-1005047910712343396</id><published>2008-10-12T16:22:00.003+02:00</published><updated>2008-10-12T16:35:57.350+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Transacciones en rails</title><content type='html'>En &lt;a href="http://javiyu.blogspot.com/2008/09/transacciones-en-mysql.html"&gt;esta&lt;/a&gt; entrada expliqué como usar las transacciones a nivel de base de datos (MySQL), ahora lo haré a nivel de aplicación con rails.&lt;br /&gt;&lt;br /&gt;Si usamos MySQL debemos recordar que por ahora el único motor que soporta transacciones es InnoDB.&lt;br /&gt;&lt;br /&gt;Los objetos que heredan de ActiveRecord tienen un método &lt;span style="font-style:italic;"&gt;transaction&lt;/span&gt; que acepta un bloque, las operaciones que se ejecuten dentro se realizarán indivisiblemente.&lt;br /&gt;&lt;br /&gt;Imaginemos que tenemos un modelo llamado &lt;span style="font-style:italic;"&gt;Post&lt;/span&gt;, con los campos &lt;span style="font-style:italic;"&gt;title&lt;/span&gt; y &lt;span style="font-style:italic;"&gt;content&lt;/span&gt;, el campo &lt;span style="font-style:italic;"&gt;title&lt;/span&gt; no puede ser nulo.&lt;br /&gt;&lt;br /&gt;Si hacemos esto.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 1px solid black; padding: 5px; background-color: rgb(51, 102, 153); color: rgb(0, 0, 0);"&gt;&lt;pre wrap=""&gt;Post.transaction do&lt;br /&gt;    Post.create(:title =&gt; 'en la transaccion', :content =&gt; 'texto')&lt;br /&gt;    Post.create(:content =&gt; 'texto')&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Como la segunda operación no es válida (el campo &lt;span style="font-style:italic;"&gt;title&lt;/span&gt; es nulo) ninguna de las operaciones se reflejará en base de datos, por el contrario, si le asignamos un &lt;span style="font-style:italic;"&gt;title&lt;/span&gt; a la segunda operación se ejecutarán normalmente y tendremos dos entradas nuevas en la tabla de posts.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-1005047910712343396?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/1005047910712343396/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=1005047910712343396&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/1005047910712343396'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/1005047910712343396'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/10/transacciones-en-rails.html' title='Transacciones en rails'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-6135385948766832628</id><published>2008-10-11T23:25:00.002+02:00</published><updated>2008-10-11T23:38:04.793+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>Ejecutar comandos linux sobre múltiples ficheros</title><content type='html'>Para ejecutar comandos masivamente sobre una lista de ficheros en linux se pueden combinar los comandos &lt;span style="font-style:italic;"&gt;find&lt;/span&gt; y &lt;span style="font-style:italic;"&gt;xargs&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;find&lt;/span&gt; es bastante conocido, básicamente lo que hace es buscar archivos según los criterios que le indiquemos.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;xargs&lt;/span&gt; coge una lista y ejecuta el comando que le pasemos a cada elmento de esa lista.&lt;br /&gt;&lt;br /&gt;La sintaxis es la siguiente.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;find . -name "*.txt" | xargs echo&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Con eso listaríamos los ficheros con extensión txt.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;find . -name "*.php" | xargs -I fichero cat fichero &gt;&gt; acumulado.php&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;El parámetro -I hace que podamos darle un nombre a la entrada del comando que queremos ejecutar para realizar operaciones más complejas.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;find . -name "*.cpp" | xargs -t -I fichero mv fichero fichero.old&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Al realizar operaciones masivas con ficheros es posible que cometamos algún error, para comprobarlo se puede utilizar el parámetro -t que hace que se indiquen en la salida todos y cada uno de los comandos que &lt;span style="font-style:italic;"&gt;xargs&lt;/span&gt; ejecuta.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-6135385948766832628?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/6135385948766832628/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=6135385948766832628&amp;isPopup=true' title='2 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/6135385948766832628'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/6135385948766832628'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/10/ejecutar-comandos-linux-sobre-mltiples.html' title='Ejecutar comandos linux sobre múltiples ficheros'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-2917482715407096627</id><published>2008-10-06T23:25:00.002+02:00</published><updated>2008-10-06T23:53:05.916+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bases de datos'/><title type='text'>Búsquedas fulltext en mysql</title><content type='html'>Las búsqueda fulltext son un tipo de búsqueda especial para los campos de texto, en MySQL solo está disponible para el motor MyISAM. Incluso los resultados se ordenan por relevancia.&lt;br /&gt;&lt;br /&gt;Se pueden indexar en modo fulltext los campos de tipo char, varchar y text.&lt;br /&gt;&lt;br /&gt;Para crear un índice fulltext la sintaxis es la siguiente.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;alter table tabla add fulltext(campo);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Se pueden combinar varios campos para el índice.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;alter table tabla add fulltext(campo1,campo2);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;La sintaxis para las consultas fulltext.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;select * from tabla where match(campo) against('contenido');&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Hay que tener en cuenta ciertas condiciones al realizar búsquedas, las más importantes: &lt;br /&gt;&lt;br /&gt;1) Si la consulta aparece en la mitad de los registros se toma como 'común', se ignoran los resultados&lt;br /&gt;2) Se ignoran palabras demasiado cortas&lt;br /&gt;&lt;br /&gt;Si no nos viene bien la regla 1), podemos hacer las búsquedas en 'modo booleano' aunque en este caso los resultados no se ordenan por relevancia.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;select * from tabla where match(campo) against('contenido' in boolean mode);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;En 'modo booleano' se pueden aplicar también modificadores, por ejemplo, si queremos las tuplas con contenido 'texto' y sin 'basura'.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;select * from tabla where match(campo) against('+texto -basura' in boolean mode);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;También se puede utilizar el wildcard '*'.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;select * from tabla where match(campo) against('text*' in boolean mode);&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-2917482715407096627?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/2917482715407096627/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=2917482715407096627&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/2917482715407096627'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/2917482715407096627'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/10/bsquedas-fulltext-en-mysql.html' title='Búsquedas fulltext en mysql'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-7203389421070097663</id><published>2008-09-29T22:50:00.003+02:00</published><updated>2008-09-29T23:11:01.480+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bases de datos'/><title type='text'>Transacciones en MySQL</title><content type='html'>Las operaciones de escritura en MySQL (inserciones, actualizaciones y borrados) se realizan por defecto en modo &lt;span style="font-style:italic;"&gt;autocommit&lt;/span&gt;, es decir, se actualizan automáticamente en la base de datos.&lt;br /&gt;&lt;br /&gt;Este comportamiento es bueno para la mayoría de aplicaciones ya que los cambios se propagan muy rápido, sin embargo no son todo ventajas.&lt;br /&gt;&lt;br /&gt;Si queremos realizar una operación compleja en la que actualizamos varios campos o tablas y falla alguna de las operaciones, la base de datos puede quedar en un estado inconsistente o no deseado.&lt;br /&gt;&lt;br /&gt;En este caso resultaría útil poder deshacer los cambios, decirle de alguna forma que todas esas operaciones van '&lt;span style="font-style:italic;"&gt;unidas&lt;/span&gt;', o se ejecutan todas, o ninguna.&lt;br /&gt;&lt;br /&gt;Existe una forma de hacer lo anterior, crear una transacción, los cambios se guardarán en la base de datos si todo ha ido bien, si no, volveremos al estado anterior.&lt;br /&gt;&lt;br /&gt;MySQL soporta transacciones, pero no con todos los motores, MyISAM por ejemplo no lo soporta, InnoDB sí.&lt;br /&gt;&lt;br /&gt;Un ejemplo de como funcionan las transacciones.&lt;pre&gt;&lt;br /&gt;mysql&gt; create table tabla (name char(20), unique(name)) engine = InnoDB;&lt;br /&gt;Query OK, 0 rows affected (0.01 sec)&lt;br /&gt;&lt;br /&gt;mysql&gt; insert into tabla set name = 'primero';&lt;br /&gt;Query OK, 1 row affected (0.01 sec)&lt;br /&gt;&lt;br /&gt;mysql&gt; insert into tabla set name = 'segundo';&lt;br /&gt;Query OK, 1 row affected (0.01 sec)&lt;br /&gt;&lt;br /&gt;mysql&gt; start transaction;&lt;br /&gt;Query OK, 0 rows affected (0.00 sec)&lt;br /&gt;&lt;br /&gt;mysql&gt; insert into tabla set name = 'tercero';&lt;br /&gt;Query OK, 1 row affected (0.00 sec)&lt;br /&gt;&lt;br /&gt;mysql&gt; select * from tabla;&lt;br /&gt;+---------+&lt;br /&gt;| name    |&lt;br /&gt;+---------+&lt;br /&gt;| primero | &lt;br /&gt;| segundo | &lt;br /&gt;| tercero | &lt;br /&gt;+---------+&lt;br /&gt;3 rows in set (0.00 sec)&lt;br /&gt;&lt;br /&gt;mysql&gt; insert into tabla set name = 'segundo';&lt;br /&gt;ERROR 1062 (23000): Duplicate entry 'segundo' for key 1&lt;br /&gt;mysql&gt; rollback;&lt;br /&gt;Query OK, 0 rows affected (0.01 sec)&lt;br /&gt;&lt;br /&gt;mysql&gt; select * from tabla;&lt;br /&gt;+---------+&lt;br /&gt;| name    |&lt;br /&gt;+---------+&lt;br /&gt;| primero | &lt;br /&gt;| segundo | &lt;br /&gt;+---------+&lt;br /&gt;2 rows in set (0.00 sec)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Como se puede ver al hacer &lt;span style="font-style:italic;"&gt;rollback&lt;/span&gt; volvemos al estado anterior de la base de datos, si hubiésemos querido guardar los cambios tendríamos que haber ejecutado &lt;span style="font-style:italic;"&gt;commit&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Durante la transacción los resultados que se muestran están en memoria, pero no físicamente guardados en la base de datos, si abrimos otra sesión de mysql esos cambios no los veremos hasta que se realice un &lt;span style="font-style:italic;"&gt;commit&lt;/span&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-7203389421070097663?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/7203389421070097663/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=7203389421070097663&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/7203389421070097663'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/7203389421070097663'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/09/transacciones-en-mysql.html' title='Transacciones en MySQL'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-5396172152339997928</id><published>2008-09-28T23:02:00.002+02:00</published><updated>2008-09-28T23:19:26.277+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Lector RSS en ruby</title><content type='html'>Para crear un lector RSS tan solo es necesario crear una conexión http hasta el sitio que queramos suscribirnos y después parsear el archivo xml que nos devuelve el servidor.&lt;br /&gt;&lt;br /&gt;En ruby se puede hacer todo esto en unas pocas líneas.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 1px solid black; padding: 5px; background-color: rgb(51, 102, 153); color: rgb(0, 0, 0);"&gt;&lt;pre wrap=""&gt;#!/usr/bin/ruby&lt;br /&gt;require 'net/http'&lt;br /&gt;require 'rexml/document'&lt;br /&gt;&lt;br /&gt;http = Net::HTTP.new 'servidor.com'&lt;br /&gt;http.start&lt;br /&gt;&lt;br /&gt;response = http.get('/path_to_rss')&lt;br /&gt;xml = REXML::Document.new(response.body)&lt;br /&gt;xml.each_element('rss/channel/item') do |elem|&lt;br /&gt; puts elem.elements['title'].text&lt;br /&gt; puts elem.elements['link'].text &lt;br /&gt; puts "----------------"&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-5396172152339997928?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/5396172152339997928/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=5396172152339997928&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/5396172152339997928'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/5396172152339997928'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/09/lector-rss-en-ruby.html' title='Lector RSS en ruby'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-7446589250353708557</id><published>2008-09-25T23:57:00.002+02:00</published><updated>2008-09-26T00:12:23.840+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>Capturar y redirigir tráfico con netcat</title><content type='html'>Cuando estamos comprobando el estado de la red o depurando el funcionamiento de un protocolo viene muy bien el comando netcat.&lt;br /&gt;&lt;br /&gt;Una redirección de un puerto a otro con netcat se hace de la siguiente forma.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;nc -l -p 5000  | nc localhost 5001&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;De esa forma se reenvía lo que llegue al puerto 5000 hasta el 5001.&lt;br /&gt;&lt;br /&gt;Si agregamos el parámetro -o además podemos registrar el tráfico saliente.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;nc -l -p 5000 -o log.txt | nc localhost 5001&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;La respuesta saldrá por consola, si tenemos una aplicación que se conecta a un host remoto y queremos saber que envía y que recibe de ese host lo podemos hacer de la siguiente forma.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;iptables -t nat -A OUTPUT -p tcp -d host_remoto -j DNAT --to-destination 127.0.0.1:5000&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;nc -l -p 5000 -o log.txt | nc host_remoto puerto_remoto&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Con esto redirigiremos todo el tráfico saliente a &lt;span style="font-style:italic;"&gt;host_remoto&lt;/span&gt; a nuestro puerto 5000, guardaremos la petición en &lt;span style="font-style:italic;"&gt;log.txt&lt;/span&gt; y volveremos a enviarlo a &lt;span style="font-style:italic;"&gt;host_remoto&lt;/span&gt;, la respuesta a la petición nos aparecerá por consola.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-7446589250353708557?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/7446589250353708557/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=7446589250353708557&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/7446589250353708557'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/7446589250353708557'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/09/capturar-y-redirigir-trfico-con-netcat.html' title='Capturar y redirigir tráfico con netcat'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-3363947744195517628</id><published>2008-09-21T11:26:00.002+02:00</published><updated>2008-09-21T11:39:17.331+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Guardar datos comprimidos en base de datos con rails</title><content type='html'>En ciertas ocasiones es posible que queramos tratar los datos que vienen de una aplicación rails antes de guardarlos en base de datos. Para ello podemos sobrecargar los métodos &lt;span style="font-style:italic;"&gt;nombre_parametro&lt;/span&gt; y &lt;span style="font-style:italic;"&gt;nombre_parametro=&lt;/span&gt; en el modelo correspondiente.&lt;br /&gt;&lt;br /&gt;Si, por ejemplo, tenemos un campo de la base de datos que preveemos que ocupe mucho espacio y no va a leerse frecuentemente se puede comprimir de la siguiente forma.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 1px solid black; padding: 5px; background-color: rgb(51, 102, 153); color: rgb(0, 0, 0);"&gt;&lt;pre wrap=""&gt;class Post &lt; ActiveRecord::Base&lt;br /&gt;&lt;br /&gt;  def text&lt;br /&gt; Zlib::Inflate.inflate(read_attribute(:text))&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  def text=(new_text)&lt;br /&gt; old_text=read_attribute(:text)&lt;br /&gt; new_compress_text=Zlib::Deflate.deflate(new_text)&lt;br /&gt; write_attribute(:text, new_compress_text) if old_text!=new_compress_text&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Para comprimir/descomprimir los datos se usa la librería &lt;a href="http://www.ruby-doc.org/stdlib/libdoc/zlib/rdoc/"&gt;zlib&lt;/a&gt; así que es necesario hacer &lt;span style="font-style:italic;"&gt;require 'zlib'&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Además es necesario que el campo de la base de datos esté marcado como binario.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-3363947744195517628?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/3363947744195517628/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=3363947744195517628&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3363947744195517628'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3363947744195517628'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/09/guardar-datos-comprimidos-en-base-de.html' title='Guardar datos comprimidos en base de datos con rails'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-3474128227985039588</id><published>2008-09-20T21:31:00.003+02:00</published><updated>2008-09-20T22:00:39.944+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Decoradores en python</title><content type='html'>Para entender fácilmente los que son los decoradores en python podemos pensar que son una especie de filtros que se ejecutan antes de la llamada a una función.&lt;br /&gt;&lt;br /&gt;Realmente un decorador se ejecuta antes de la función decorada (realizando cualquier tipo de acción) y devuelve la función a ejecutar (posiblemente la función decorada). Es más fácil de entender con un ejemplo.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 1px solid black; padding: 5px; background-color: rgb(51, 102, 153); color: rgb(0, 0, 0);"&gt;&lt;pre wrap=""&gt;#!/usr/bin/python&lt;br /&gt;&lt;br /&gt;def filtro(f):&lt;br /&gt; def permiso_denegado(*args):&lt;br /&gt;  print '%s no tiene permisos para realizar esa accion' % args[0]&lt;br /&gt;  &lt;br /&gt; def comprobacion(*args):&lt;br /&gt;  if args[0] == 'admin':&lt;br /&gt;   return f(*args)&lt;br /&gt;  else:&lt;br /&gt;   return permiso_denegado(*args)&lt;br /&gt;  &lt;br /&gt; return comprobacion&lt;br /&gt;  &lt;br /&gt;&lt;br /&gt;@filtro&lt;br /&gt;def accion(usuario):&lt;br /&gt; print 'Accion realizada por %s' % usuario&lt;br /&gt; &lt;br /&gt;accion('guest')&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;En este caso se intenta realizar una acción pero si el usuario pasado como parámetro no es 'admin' no puede realizarla, en lugar de devolver una referencia a la función original, se devuelve la función de permiso denegado, &lt;span style="font-style:italic;"&gt;filtro&lt;/span&gt; es el decorador.&lt;br /&gt;&lt;br /&gt;También existe la posibilidad de combinar decoradores, lo importante es tener en cuenta cuando se programa un decorador que no tiene porqué ser el único (cuidado lo que se hace con los parámetros) y el orden, en el ejemplo &lt;span style="font-style:italic;"&gt;debug(filtro(debug(accion)))&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 1px solid black; padding: 5px; background-color: rgb(51, 102, 153); color: rgb(0, 0, 0);"&gt;&lt;pre wrap=""&gt;#!/usr/bin/python&lt;br /&gt;&lt;br /&gt;_MODO_DEBUG = True&lt;br /&gt;&lt;br /&gt;def debug(f):&lt;br /&gt; if _MODO_DEBUG:&lt;br /&gt;  print 'Se ejecuta la funcion: %s' % f.__name__&lt;br /&gt; return f&lt;br /&gt;&lt;br /&gt;def filtro(f):&lt;br /&gt; def permiso_denegado(*args):&lt;br /&gt;  print '%s no tiene permisos para realizar esa accion' % args[0]&lt;br /&gt;  &lt;br /&gt; def comprobacion(*args):&lt;br /&gt;  if args[0] == 'admin':&lt;br /&gt;   return f(*args)&lt;br /&gt;  else:&lt;br /&gt;   return permiso_denegado(*args)&lt;br /&gt;  &lt;br /&gt; return comprobacion&lt;br /&gt;  &lt;br /&gt;@debug&lt;br /&gt;@filtro&lt;br /&gt;@debug&lt;br /&gt;def accion(usuario):&lt;br /&gt; print 'Accion realizada por %s' % usuario&lt;br /&gt; &lt;br /&gt;accion('guest')&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-3474128227985039588?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/3474128227985039588/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=3474128227985039588&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3474128227985039588'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3474128227985039588'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/09/decoradores-en-python.html' title='Decoradores en python'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-3586887703812227354</id><published>2008-09-20T00:36:00.002+02:00</published><updated>2008-09-20T01:08:29.604+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Medir el rendimiento de una aplicación web</title><content type='html'>Es importante medir el rendimiento de todas las aplicaciones que creamos, en el caso de las aplicaciones web podemos usar una herramienta de hp llamada &lt;a href="http://www.hpl.hp.com/research/linux/httperf/download.php"&gt;httperf&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Para ejecutarlo de la forma más sencilla se puede hacer.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;httperf --server servidor_web --port puerto --num-conns numero_conexiones&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;servidor_web&lt;/span&gt; y &lt;span style="font-style:italic;"&gt;puerto&lt;/span&gt; apuntan a la aplicación web que queramos probar y &lt;span style="font-style:italic;"&gt;numero_conexiones&lt;/span&gt; es el número de intentos totales, entre 200 y 1000 suelen dar unos buenos resultados sin tests demasiado largos.&lt;br /&gt;&lt;br /&gt;Si queremos probar alguna página que no sea el index se puede hacer incluyendo el parámetro &lt;span style="font-style:italic;"&gt;--uri direccion&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Si la página que queremos probar necesita de registro también se puede solucionar con esta herramienta, primero necesitamos loguearnos con el navegador, observar la cookie que se nos ha creado y entonces añadir el parámetro &lt;span style="font-style:italic;"&gt;--add-header='Cookie: nombre=valor'&lt;/span&gt;, donde &lt;span style="font-style:italic;"&gt;nombre&lt;/span&gt; y &lt;span style="font-style:italic;"&gt;valor&lt;/span&gt; son los que hemos obtenido de la cookie del navegador.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-3586887703812227354?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/3586887703812227354/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=3586887703812227354&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3586887703812227354'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3586887703812227354'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/09/medir-el-rendimiento-de-una-aplicacin.html' title='Medir el rendimiento de una aplicación web'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-3072128767345222313</id><published>2008-09-17T22:37:00.003+02:00</published><updated>2008-09-17T22:49:45.796+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Seleccionar parte de una imagen con javascript</title><content type='html'>En las redes sociales que permite etiquetar imágenes se suele elegir una sección de la imagen que representa la parte ocupada por cada usuario.&lt;br /&gt;&lt;br /&gt;El problema es que a la mayoría (facebook, tuenti...) solo nos dejan seleccionar una sección cuadrada fija y muchas veces no se corresponde con lo que queremos.&lt;br /&gt;&lt;br /&gt;Con jQuery y Jcrop podemos realizar selecciones más precisas de la siguiente manera.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 1px solid black; padding: 5px; background-color: rgb(51, 102, 153); color: rgb(0, 0, 0);"&gt;&lt;pre wrap=""&gt;&amp;lt;html&amp;gt;&lt;br /&gt; &amp;lt;head&amp;gt;&lt;br /&gt;  &amp;lt;script src="jquery.pack.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;  &amp;lt;script src="jquery.Jcrop.pack.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;  &amp;lt;link rel="stylesheet" href="/css/jquery.Jcrop.css" type="text/css" /&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;script language="Javascript"&amp;gt;&lt;br /&gt;   jQuery(function(){ jQuery('#cropbox').Jcrop(); });&lt;br /&gt;   jQuery('#cropbox').Jcrop({&lt;br /&gt;    aspectRatio: 1,&lt;br /&gt;    onSelect: updateCoords&lt;br /&gt;   });&lt;br /&gt;   function updateCoords(c){&lt;br /&gt;    jQuery('#x').val(c.x);&lt;br /&gt;    jQuery('#y').val(c.y);&lt;br /&gt;    jQuery('#w').val(c.w);&lt;br /&gt;    jQuery('#h').val(c.h);&lt;br /&gt;   };&lt;br /&gt;  &amp;lt;/script&amp;gt;&lt;br /&gt; &amp;lt;/head&amp;gt;&lt;br /&gt;&lt;br /&gt; &amp;lt;body&amp;gt;&lt;br /&gt;  &amp;lt;img src="flowers.jpg" id="cropbox" /&amp;gt;&lt;br /&gt; &amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;En c.x y c.y tendremos las coordenadas dónde comienza la selección y en c.w y c.h el ancho y el alto.&lt;br /&gt;&lt;br /&gt;Una vez que sabemos exactamente la selección del usuario se puede recortar la imagen o etiquetar cada zona.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_3QpXB2efkAA/SNFtGSf3h6I/AAAAAAAAAHI/somIlI8Xawc/s1600-h/captura.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_3QpXB2efkAA/SNFtGSf3h6I/AAAAAAAAAHI/somIlI8Xawc/s320/captura.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5247094995675482018" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-3072128767345222313?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/3072128767345222313/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=3072128767345222313&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3072128767345222313'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3072128767345222313'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/09/seleccionar-parte-de-una-imagen-con.html' title='Seleccionar parte de una imagen con javascript'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_3QpXB2efkAA/SNFtGSf3h6I/AAAAAAAAAHI/somIlI8Xawc/s72-c/captura.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-4141077729639341231</id><published>2008-09-14T00:27:00.002+02:00</published><updated>2008-09-14T00:43:24.118+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Implementación caché para minimizar cálculos</title><content type='html'>Una de las reglas de optimización más importantes es la de no repetir cálculos innecesariamente.&lt;br /&gt;&lt;br /&gt;Guardando resultados intermedios y reutilizándolos cuando sea posible se mejora el rendimiento espectacularmente, en el ejemplo se consigue una ganancia casi lineal.&lt;br /&gt;&lt;br /&gt;La clase &lt;span style="font-style:italic;"&gt;NoCache&lt;/span&gt; sería la forma tradicional de implementar esta clase, a continuación la clase &lt;span style="font-style:italic;"&gt;Cache&lt;/span&gt; optimizada para lecturas sucesivas sin repetir el cálculo si no es necesario.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 1px solid black; padding: 5px; background-color: rgb(51, 102, 153); color: rgb(0, 0, 0);"&gt;&lt;pre wrap=""&gt;#!/usr/bin/python&lt;br /&gt;&lt;br /&gt;class NoCache:&lt;br /&gt; def __init__(self):&lt;br /&gt;  self.lista = range(1,900000)&lt;br /&gt; &lt;br /&gt; def getLista(self):&lt;br /&gt;  return self.lista&lt;br /&gt;  &lt;br /&gt; def setLista(self,value):&lt;br /&gt;  lista.append(self.value)&lt;br /&gt; &lt;br /&gt; def getMedia(self):&lt;br /&gt;  return reduce((lambda n,m:n+m),self.lista) / len(self.lista)&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;class Cache:&lt;br /&gt; def __init__(self):&lt;br /&gt;  self.lista = range(1,900000)&lt;br /&gt;  self.__actualizado = False&lt;br /&gt; &lt;br /&gt; def getLista(self):&lt;br /&gt;  return self.lista&lt;br /&gt;  &lt;br /&gt; def setLista(self,value):&lt;br /&gt;  self.__actualizado = False&lt;br /&gt;  lista.append(self.value)&lt;br /&gt; &lt;br /&gt; def getMedia(self):&lt;br /&gt;  if self.__actualizado:&lt;br /&gt;   return self.__sumaCache&lt;br /&gt;  else:&lt;br /&gt;   self.__sumaCache = reduce((lambda n,m:n+m),self.lista) / len(self.lista)&lt;br /&gt;   self.__actualizado = True&lt;br /&gt;   return self.__sumaCache&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;n = NoCache()&lt;br /&gt;for i in range(5):&lt;br /&gt; print n.getMedia()&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;c = Cache()&lt;br /&gt;for i in range(5):&lt;br /&gt; print c.getMedia()&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;El mismo ejemplo en ruby.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 1px solid black; padding: 5px; background-color: rgb(51, 102, 153); color: rgb(0, 0, 0);"&gt;&lt;pre wrap=""&gt;#!/usr/bin/ruby&lt;br /&gt;&lt;br /&gt;class NoCache&lt;br /&gt; def initialize&lt;br /&gt;  @lista = Array.new(900000){|i| i+1}&lt;br /&gt; end&lt;br /&gt;&lt;br /&gt; def getLista&lt;br /&gt;  return @lista&lt;br /&gt; end&lt;br /&gt; &lt;br /&gt; def setLista(value)&lt;br /&gt;  @lista &amp;lt;&amp;lt; value&lt;br /&gt; end&lt;br /&gt; &lt;br /&gt; def getMedia&lt;br /&gt;  @lista.inject{|sum, n| sum+n} / @lista.size&lt;br /&gt; end &lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;class Cache&lt;br /&gt; def initialize&lt;br /&gt;  @lista = Array.new(900000){|i| i+1}&lt;br /&gt;  @actualizado = false&lt;br /&gt; end&lt;br /&gt;&lt;br /&gt; def getLista&lt;br /&gt;  return @lista&lt;br /&gt; end&lt;br /&gt; &lt;br /&gt; def setLista(value)&lt;br /&gt;  @actualizado = false&lt;br /&gt;  @lista &lt;&lt; value&lt;br /&gt; end&lt;br /&gt; &lt;br /&gt; def getMedia&lt;br /&gt;  if @actualizado&lt;br /&gt;   @sumaCache&lt;br /&gt;  else&lt;br /&gt;   @sumaCache = @lista.inject{|sum, n| sum+n} / @lista.size&lt;br /&gt;   @actualizado = true&lt;br /&gt;   @sumaCache&lt;br /&gt;  end&lt;br /&gt; end &lt;br /&gt;end&lt;br /&gt; &lt;br /&gt;n = NoCache.new&lt;br /&gt;5.times{puts n.getMedia}&lt;br /&gt;&lt;br /&gt;c = Cache.new&lt;br /&gt;5.times{puts c.getMedia}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Otro resultado inesperado en este ejemplo es la gran diferencia de velocidad entre estos dos lenguajes.&lt;br /&gt;&lt;br /&gt;En python en mi máquina este ejemplo tarda en ejecutarse 7 segundos, en ruby 1 minuto y 28 segundos. Para este ejemplo python es ¡12 veces más rápido que ruby!.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-4141077729639341231?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/4141077729639341231/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=4141077729639341231&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/4141077729639341231'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/4141077729639341231'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/09/implementacin-cach-para-minimizar.html' title='Implementación caché para minimizar cálculos'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-8927392635911682195</id><published>2008-09-13T15:49:00.003+02:00</published><updated>2008-09-13T20:10:00.648+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Variables de solo lectura en python</title><content type='html'>Hay algunos tipos de variables, como pueden ser variables de estado, que no interesa que se modifiquen desde fuera de los métodos de una clase, aunque sí que se pueda leer su valor.&lt;br /&gt;&lt;br /&gt;Al intentar modificar el valor de una variable de un objeto se llama a la función &lt;span style="font-style:italic;"&gt;__setattr__&lt;/span&gt;, si sobrescribimos esta función se puede variar el comportamiendo habitual. Lo mismo podemos hacer con &lt;span style="font-style:italic;"&gt;__delattr__&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Así se podría mantener una distinción en una clase entre variables de solo lectura y lectura/escritura.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 1px solid black; padding: 5px; background-color: rgb(51, 102, 153); color: rgb(0, 0, 0);"&gt;&lt;pre wrap=""&gt;#!/usr/bin/python&lt;br /&gt;&lt;br /&gt;class Clase:&lt;br /&gt; __onlyReadVars=['x', 'y']&lt;br /&gt;&lt;br /&gt; def __init__(self):&lt;br /&gt;  self.__dict__['x'] = 8&lt;br /&gt;  self.__dict__['y'] = 1&lt;br /&gt;  self.a = 2&lt;br /&gt; &lt;br /&gt; def __setattr__(self, nombre, valor):&lt;br /&gt;  if nombre in self.__onlyReadVars:&lt;br /&gt;   raise Exception('No se puede sobrescribir %s' % nombre)&lt;br /&gt;  else:&lt;br /&gt;   self.__dict__[nombre] = valor&lt;br /&gt;&lt;br /&gt; def __delattr__(self, nombre):&lt;br /&gt;  if nombre in self.__onlyReadVars:&lt;br /&gt;   raise Exception('No se puede eliminar %s' % nombre)&lt;br /&gt;  else:&lt;br /&gt;   del self.__dict__[nombre]&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;De esta forma si intentamos eliminar o sobrescribir alguna de las variables de solo lectura se lanzará una excepción.&lt;br /&gt;&lt;br /&gt;Aun así, hay una manera de saltarse el filtro si hacemos lo siguiente.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;c = Clase()&lt;br /&gt;c.__dict__['x'] = 30&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;__dict__&lt;/span&gt; es un diccionario con todas las variables del objeto y sus valores, al modificarlo no se llama a la función &lt;span style="font-style:italic;"&gt;__setattr__&lt;/span&gt;,&lt;span style="font-style:italic;"&gt; __getattr__&lt;/span&gt; ni &lt;span style="font-style:italic;"&gt;__delattr__&lt;/span&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-8927392635911682195?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/8927392635911682195/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=8927392635911682195&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/8927392635911682195'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/8927392635911682195'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/09/varibles-de-solo-lectura-en-python.html' title='Variables de solo lectura en python'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-4831710185444760827</id><published>2008-09-11T23:07:00.003+02:00</published><updated>2008-09-11T23:15:24.587+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>Trucos para bash</title><content type='html'>Hay ciertas situaciones al trabajar en consola que se hacen un poco pesadas y se pueden evitar con algunas combinaciones de teclas disponibles en bash.&lt;br /&gt;&lt;br /&gt;Cuando necesitamos ir a un directorio y volver al que estábamos anteriormente se puede ejecutar.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;cd -&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Para ver todas las variables definidas en la shel simplemente escribiendo &lt;span style="font-style:italic;"&gt;$&lt;/span&gt; y pulsando dos veces al tabulador deberían aparecer.&lt;br /&gt;&lt;br /&gt;Cuando ejecutamos un comando muy largo repetidas veces se puede hacer una búsqueda incremental en el historial pulsando &lt;span style="font-style:italic;"&gt;Ctrl+R&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Una de las cosas más molestas de trabajar con consola es editar comandos muy largos, se puede hacer fácilmente con estos atajos de teclado.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Ctrl+A&lt;/span&gt;: pone el cursor al principio de la línea&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Ctrl+E&lt;/span&gt;: pone el cursor al final de la línea&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Ctrl+K&lt;/span&gt;: borra desde el cursor hasta el final de la línea&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Ctrl+U&lt;/span&gt;: borra desde el principio hasta el cursor&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Ctrl+Y&lt;/span&gt;: pega el texto que cortaste con &lt;span style="font-style:italic;"&gt;Ctrl+K&lt;/span&gt; o &lt;span style="font-style:italic;"&gt;Ctrl+U&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-4831710185444760827?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/4831710185444760827/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=4831710185444760827&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/4831710185444760827'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/4831710185444760827'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/09/trucos-para-bash.html' title='Trucos para bash'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-3082190974230698861</id><published>2008-09-09T23:19:00.002+02:00</published><updated>2008-09-09T23:34:53.112+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Medir el tiempo de cada funcion en python</title><content type='html'>Cuando vamos a optimizar código lo primero en lo que pensamos es en medir el tiempo que tarda cada función de nuestro programa para ver donde se puede mejorar más (&lt;a href="http://es.wikipedia.org/wiki/Amdahl"&gt;Ley de Amdahl&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;En python el módulo timeit nos facilita mucho esta tarea, se puede usar de la siguiente manera.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;import timeit&lt;br /&gt;t = timeit.Timer("funcion()", "from __main__ import funcion")&lt;br /&gt;t.timeit()&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;t.timeit()&lt;/span&gt; ejecuta múltiples veces la función y devuelve el tiempo transcurrido, si se le pasa un parámetro ejecutará la función ese número de veces.&lt;br /&gt;&lt;br /&gt;También se puede ejecutar varias veces el test anterior para asegurarnos que no influye ningún otro proceso en la medida del tiempo, para ello se puede ejecutar &lt;span style="font-style:italic;"&gt;t.repeat(numero_de_veces)&lt;/span&gt; y devolverá un array con los tiempos transcurridos.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-3082190974230698861?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/3082190974230698861/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=3082190974230698861&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3082190974230698861'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3082190974230698861'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/09/medir-el-tiempo-de-cada-funcion-en.html' title='Medir el tiempo de cada funcion en python'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-7327957870263343802</id><published>2008-09-07T23:29:00.002+02:00</published><updated>2008-09-07T23:52:22.842+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>MapReduce</title><content type='html'>&lt;a href="http://en.wikipedia.org/wiki/MapReduce"&gt;MapReduce&lt;/a&gt; es una técnica popularizada por Google (aquí el &lt;a href="http://labs.google.com/papers/mapreduce-osdi04-slides/index.html"&gt;documento original&lt;/a&gt;) para el tratamiento de grandes cantidades de información en un tiempo razonable.&lt;br /&gt;&lt;br /&gt;El nombre proviene de las funciones propias de la programación funcional &lt;span style="font-style:italic;"&gt;map&lt;/span&gt; y &lt;span style="font-style:italic;"&gt;reduce&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;En python estas dos funciones se pueden combinar de la siguiente forma para contar el número de números impares de una lista:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;reduce(lambda n,m: n+m, map(lambda n: n%2, [1,2,3,4,5,6,7,8,9]))&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Primero, &lt;span style="font-style:italic;"&gt;map&lt;/span&gt; aplica la función &lt;span style="font-style:italic;"&gt;n%2&lt;/span&gt; a toda la lista original y cambiandola de dominio (de números naturales a [0,1]), después &lt;span style="font-style:italic;"&gt;reduce&lt;/span&gt; suma la nueva lista obteniendo el número de elementos impares.&lt;br /&gt;&lt;br /&gt;¿Qué ventaja tiene esta manera de hacerlo el recuento a la tradicional? &lt;br /&gt;Lo primero que se nos hubiera ocurrido tradicionalmente sería recorrer la lista en aumentando un contador si un número es impar.&lt;br /&gt;Con MapReduce hacemos un procedimiento intermedio (cambiar la lista de dominio) pero a cambio es un diseño muy sencillo de paralelizar.&lt;br /&gt;&lt;br /&gt;Por definición &lt;span style="font-style:italic;"&gt;map&lt;/span&gt; aplica una función a cada elemento de una lista, implicitamente no hay relación entre cada cálculo realizado por &lt;span style="font-style:italic;"&gt;map&lt;/span&gt;, así que cada operación la puede realizar un nodo.&lt;br /&gt;&lt;br /&gt;Tras eso se necesita almacenar todos los resultados en un nodo central para obtener el resultado final, mayor eficiencia obtendremos en este algoritmo cuanto más porcentaje del cálculo lo hagamos mediante &lt;span style="font-style:italic;"&gt;map&lt;/span&gt; y menos mediante &lt;span style="font-style:italic;"&gt;reduce&lt;/span&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-7327957870263343802?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/7327957870263343802/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=7327957870263343802&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/7327957870263343802'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/7327957870263343802'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/09/mapreduce.html' title='MapReduce'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-5312040525787407129</id><published>2008-09-07T12:51:00.002+02:00</published><updated>2008-09-07T12:56:16.464+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>Crear un disco virtual usando la memoria RAM</title><content type='html'>En muchas ocasiones se trabaja intensivamente con un conjunto no demasiado grande de ficheros, se puede acelerar mucho el acceso a estos ficheros si se almacenan en la memoria RAM.&lt;br /&gt;&lt;br /&gt;Para ello, en linux se puede crear un nuevo punto de montaje que acceda a la RAM, tan solo es necesario hacer lo siguiente.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;mkdir /mnt/ramdisk&lt;br /&gt;mount tmpfs /mnt/ramdisk -t tmpfs&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Ya podemos trabajar en el directorio ramdisk, eso sí, la memoria RAM es volátil, si queremos guardar los cambios antes de apagar el pc es necesario copiarlo a cualquier otro directorio del disco duro.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-5312040525787407129?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/5312040525787407129/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=5312040525787407129&amp;isPopup=true' title='6 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/5312040525787407129'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/5312040525787407129'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/09/crear-un-disco-virtual-usando-la.html' title='Crear un disco virtual usando la memoria RAM'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-6398057472906643070</id><published>2008-09-06T13:41:00.003+02:00</published><updated>2008-09-06T13:50:58.319+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Leer los parámetros de la lista de comandos en python</title><content type='html'>La mayoría de programas que se usan mediante la línea de comandos aceptan parámetros y eso es lo que le da a estos programas mayor flexibilidad que a los que se usan mediante interfaz gráfica.&lt;br /&gt;&lt;br /&gt;Para leer los parámetros de un programa en python nos puede servir la librería &lt;a href="http://docs.python.org/lib/module-optparse.html"&gt;optparse&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Tiene bastantes opciones e incluso genera la ayuda de forma automática al llamar al programa con -h.&lt;br /&gt;Un ejemplo de como se utiliza.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 1px solid black; padding: 5px; background-color: rgb(51, 102, 153); color: rgb(0, 0, 0);"&gt;&lt;pre wrap=""&gt;#!/usr/bin/python&lt;br /&gt;&lt;br /&gt;from optparse import OptionParser&lt;br /&gt;&lt;br /&gt;parser=OptionParser()&lt;br /&gt;parser.add_option("-a", "--all", dest="todos", action="store_true", default=False,&lt;br /&gt; help="afecta a todos los elementos")&lt;br /&gt;parser.add_option("-f", action="store_false", dest="todos", &lt;br /&gt; help="affecta solo al primer elemento")&lt;br /&gt;parser.add_option("--without-output", action="store_false", dest="output", default=True,&lt;br /&gt; help="sin mostrar salida")&lt;br /&gt;parser.add_option("-i", "--insert", action="store", dest="newValue",&lt;br /&gt; help="inserta un elemento al final de la lista")&lt;br /&gt;&lt;br /&gt;(options, args)=parser.parse_args()&lt;br /&gt;&lt;br /&gt;lista=[1,2,3,4,5,6,7,8,9];&lt;br /&gt;nuevaLista=lista&lt;br /&gt;&lt;br /&gt;if options.todos:&lt;br /&gt; nuevaLista=map(lambda n: n*2, lista)&lt;br /&gt;else:&lt;br /&gt; nuevaLista[0]=lista[0]*2&lt;br /&gt;&lt;br /&gt;if options.newValue:&lt;br /&gt; nuevaLista.append(int(options.newValue))&lt;br /&gt;&lt;br /&gt;if options.output:&lt;br /&gt; print nuevaLista&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Se pueden combinar parámetros, agrupar, hacerlos excluyentes... casi todo lo que se ocurra, si necesitas algo más específico mira en el enlace anterior.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-6398057472906643070?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/6398057472906643070/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=6398057472906643070&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/6398057472906643070'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/6398057472906643070'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/09/leer-los-parmetros-de-la-lista-de.html' title='Leer los parámetros de la lista de comandos en python'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-7703439009074220954</id><published>2008-08-31T11:25:00.002+02:00</published><updated>2008-08-31T11:35:46.144+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>Convertir fichero .nrg a .iso</title><content type='html'>Para convertir un fichero .nrg al formato .iso en linux sin necesidad de ningún programa adicional tan solo hay que ejecutar el siguiente comando.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;dd bs=1k if=imagen.nrg of=imagen.iso skip=300&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;La explicación, con este comando lo que hacemos es copiar el fichero quitando los primeros 300kB (skip indica el número de bloques que no queremos copiar y bs es el block size).&lt;br /&gt;&lt;br /&gt;En realidad un fichero .nrg y uno .iso se diferencian simplemente en eso, nero añade esa cabecera con información propia. &lt;br /&gt;&lt;br /&gt;Hay un programa que hace esta misma conversión en linux, &lt;a href="http://gregory.kokanosky.free.fr/v4/linux/nrg2iso.en.html"&gt;nrg2iso&lt;/a&gt;.&lt;br /&gt;Este programa está hecho en c, la conversión la realiza de esta manera.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;fseek (nrgFile, 307200, SEEK_SET);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;El resto del programa es básicamente una copia de ficheros, al igual que hace el comando dd, en este caso salta 307200 bytes, que en realidad corresponde a los 300kB mencionados arriba (300*1024).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-7703439009074220954?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/7703439009074220954/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=7703439009074220954&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/7703439009074220954'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/7703439009074220954'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/08/convertir-fichero-nrg-iso.html' title='Convertir fichero .nrg a .iso'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-394142691024356559</id><published>2008-08-30T19:15:00.002+02:00</published><updated>2008-08-30T19:49:58.489+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>Ficheros abiertos por un proceso</title><content type='html'>Para localizar los procesos que están usando un fichero en linux tenemos el comando &lt;span style="font-style:italic;"&gt;fuser&lt;/span&gt;. En concreto ejecutando lo siguiente.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;fuser -va fichero&lt;/span&gt; (fichero también puede ser un directorio).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;fuser -km fichero&lt;/span&gt; (mata todos los procesos que acceden al fichero).&lt;br /&gt;&lt;br /&gt;Una funcionalidad similar se puede obtener con lsof, además lsof también permite ver los sockets abiertos.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;lsof fichero&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Ejecutando simplemente lsof se muestran todos los fichero abiertos así que podemos filtrar mejor con grep.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;lsof | grep fichero&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;lsof | grep UDP&lt;/span&gt; (sockets udp abiertos).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-394142691024356559?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/394142691024356559/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=394142691024356559&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/394142691024356559'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/394142691024356559'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/08/ficheros-abiertos-por-un-proceso.html' title='Ficheros abiertos por un proceso'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-429833950949551953</id><published>2008-08-27T23:19:00.002+02:00</published><updated>2008-08-27T23:31:15.251+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>Hacer copia de seguridad del MBR</title><content type='html'>Si instalamos y reinstalamos frecuentemente distintos sistemas operativos en el mismo disco duro es frecuente perder el MBR (Master Boot Record).&lt;br /&gt;&lt;br /&gt;Cuando ya tenemos un MBR que nos sirve y no lo queremos perder en ninguna reinstalación podemos hacer una copia de seguridad, para ello hay que ejecutar el siguiente comando.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;dd if=/dev/sda of=/mbr.bak bs=512 count=1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Donde /dev/sda es el disco duro y /mbr.bak la copia de seguridad, para reestablecer la copia de seguridad tan solo hay que hacer.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;dd if=/mbr.bak of=/dev/sda bs=512 count=1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;El problema al hacerlo así es que también estamos sobreescribiendo la tabla de particiones, para no afectar a la tabla de particiones sobreescribiendo el gestor de arranque hay que escribir solo los primeros 446 bytes.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;dd if=/dev/sda of=/mbr.bak bs=446 count=1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;dd if=/mbr.bak of=/dev/sda bs=446 count=1&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-429833950949551953?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/429833950949551953/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=429833950949551953&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/429833950949551953'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/429833950949551953'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/08/hacer-copia-de-seguridad-del-mbr.html' title='Hacer copia de seguridad del MBR'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-7210758857960528538</id><published>2008-08-26T22:03:00.002+02:00</published><updated>2008-08-26T22:18:32.858+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>Matar procesos selectivamente en linux</title><content type='html'>Para terminar (matar) procesos en linux se suele usar la orden &lt;span style="font-style:italic;"&gt;kill pid&lt;/span&gt; o &lt;span style="font-style:italic;"&gt;killall programa&lt;/span&gt; pero hay otra forma de hacerlo más potente.&lt;br /&gt;&lt;br /&gt;El comando en cuestión es &lt;span style="font-style:italic;"&gt;pkill&lt;/span&gt;, dejo una guía rápida de las opciones que permite, siempre se pueden combinar varias.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;pkill -u usuario&lt;/span&gt; mata todos los procesos de un usuario.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;pkill patron&lt;/span&gt; mata todos los procesos en los que el patrón esté incluído en el nombre.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;pkill -n patron&lt;/span&gt; mata al proceso más nuevo de los que coinciden con el patrón.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;pkill -o patron&lt;/span&gt; mata al proceso más antiguo de los que coinciden con el patrón.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;pkill -x patron&lt;/span&gt; mata los procesos en los que el nombre coincide exactamente con el patrón.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;pkill -v -u usuario&lt;/span&gt; mata todos los procesos que no son del usuario (-v invierte el efecto de la acción).&lt;br /&gt;&lt;br /&gt;Hay algunas opciones más, para verlas todas &lt;span style="font-style:italic;"&gt;man pkill&lt;/span&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-7210758857960528538?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/7210758857960528538/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=7210758857960528538&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/7210758857960528538'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/7210758857960528538'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/08/matar-procesos-selectivamente-en-linux.html' title='Matar procesos selectivamente en linux'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-3282488514189278329</id><published>2008-08-24T22:40:00.002+02:00</published><updated>2008-08-24T22:56:06.082+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><category scheme='http://www.blogger.com/atom/ns#' term='c'/><title type='text'>Número de argumentos variables en C</title><content type='html'>Para crear un método que acepte un número de argumentos variables en C hay que incluir la cabecera &lt;span style="font-style:italic;"&gt;stdarg&lt;/span&gt;, una vez incluída podremos acceder a las macros  &lt;span style="font-style:italic;"&gt;va_start&lt;/span&gt;, &lt;span style="font-style:italic;"&gt;va_arg&lt;/span&gt; y &lt;span style="font-style:italic;"&gt;va_end&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;va_start&lt;/span&gt; acepta como parámetro el último parámetro antes de la lista variable.&lt;br /&gt;&lt;span style="font-style:italic;"&gt;va_arg&lt;/span&gt; necesita el tipo del parámetro que hay que devolver.&lt;br /&gt;&lt;span style="font-style:italic;"&gt;va_end&lt;/span&gt; libera los recursos usados para la lectura de parámetros.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 1px solid black; padding: 5px; background-color: rgb(51, 102, 153); color: rgb(0, 0, 0);"&gt;&lt;pre wrap=""&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;#include &amp;lt;stdarg.h&amp;gt;&lt;br /&gt;&lt;br /&gt;int sumatorio(int howmany, ...){ &lt;br /&gt; int i;&lt;br /&gt; int total = 0;&lt;br /&gt; va_list ap;&lt;br /&gt;&lt;br /&gt; va_start(ap, howmany);&lt;br /&gt; &lt;br /&gt; for (i=0; i&amp;lt;howmany; i++)&lt;br /&gt;  total+=va_arg(ap, int);&lt;br /&gt; &lt;br /&gt; va_end(ap);&lt;br /&gt;&lt;br /&gt; return total;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main(){&lt;br /&gt; printf("%d\n", sumatorio(4, 1,2,3,4));&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-3282488514189278329?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/3282488514189278329/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=3282488514189278329&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3282488514189278329'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3282488514189278329'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/08/nmero-de-argumentos-variables-en-c.html' title='Número de argumentos variables en C'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-5034925255406335243</id><published>2008-08-24T01:04:00.002+02:00</published><updated>2008-08-24T01:16:10.694+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><category scheme='http://www.blogger.com/atom/ns#' term='c'/><title type='text'>Comprobaciones numéricas en C</title><content type='html'>Es conocido que C es un lenguaje muy potente pero a muy bajo nivel, esto tiene algunas consecuencias al trabajar con valores numéricos que con otros lenguajes ni nos plantearíamos.&lt;br /&gt;&lt;br /&gt;En primer lugar, ¿qué devuelven las funciones matemáticas en caso de que no exista un resultado a su operación?&lt;br /&gt;&lt;br /&gt;Hay algunas funciones matemáticas como la raíz cuadrada y el logaritmo que no siempre tienen solución, en estos casos se devuelve &lt;span style="font-style:italic;"&gt;nan (Not A Number)&lt;/span&gt; y se puede comprobar con la función &lt;span style="font-style:italic;"&gt;isnan&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Otra situación posible es llegar a un valor infinito, ¿qué ocurre entonces? pues se devuelve &lt;span style="font-style:italic;"&gt;inf&lt;/span&gt; y se puede comprobar con &lt;span style="font-style:italic;"&gt;isinf&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Aquí un ejemplo de como se puede llegar a estas situaciones, para compilar &lt;span style="font-style:italic;"&gt;gcc prog.c -o prog -lm&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 1px solid black; padding: 5px; background-color: rgb(51, 102, 153); color: rgb(0, 0, 0);"&gt;&lt;pre wrap=""&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;#include &amp;lt;math.h&amp;gt;&lt;br /&gt;&lt;br /&gt;int main(){&lt;br /&gt; float dividendo=999999999;&lt;br /&gt; float divisor=0.000000000000000000000000000000001;&lt;br /&gt; float num=dividendo/divisor;&lt;br /&gt;&lt;br /&gt; if(isinf(num)) printf("Infinito\n");&lt;br /&gt; printf("%f\n",num);&lt;br /&gt;&lt;br /&gt; num=sqrt(-num);&lt;br /&gt; if(isnan(num)) printf("Not a number\n");&lt;br /&gt;&lt;br /&gt; printf("%f\n",num);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-5034925255406335243?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/5034925255406335243/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=5034925255406335243&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/5034925255406335243'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/5034925255406335243'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/08/comprobaciones-numricas-en-c.html' title='Comprobaciones numéricas en C'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-3821634811669781314</id><published>2008-08-22T22:27:00.002+02:00</published><updated>2008-08-22T22:35:58.152+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Threads en ruby</title><content type='html'>El manejo de threads en ruby es muy sencillo, la creación de threads se basa en pasar un bloque a la creación de un objeto de la clase thread.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 1px solid black; padding: 5px; background-color: rgb(51, 102, 153); color: rgb(0, 0, 0);"&gt;&lt;pre wrap=""&gt;#!/usr/bin/ruby&lt;br /&gt;&lt;br /&gt;t1 = Thread.new do&lt;br /&gt; 10.times do&lt;br /&gt;  puts "hello from thread 1"&lt;br /&gt;  sleep(0.2)&lt;br /&gt; end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;t2 = Thread.new do &lt;br /&gt; 10.times do&lt;br /&gt;  puts "hello from thread 2"&lt;br /&gt;  sleep(0.2)&lt;br /&gt; end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;t1.join&lt;br /&gt;t2.join&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Para pasar parámetros se hace de la siguiente forma.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 1px solid black; padding: 5px; background-color: rgb(51, 102, 153); color: rgb(0, 0, 0);"&gt;&lt;pre wrap=""&gt;#!/usr/bin/ruby&lt;br /&gt;&lt;br /&gt;t1 = Thread.new(1) do |id|&lt;br /&gt; 10.times do&lt;br /&gt;  puts "hello from thread #{id}"&lt;br /&gt;  sleep(0.2)&lt;br /&gt; end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;t2 = Thread.new(2) do |id|&lt;br /&gt; 10.times do&lt;br /&gt;  puts "hello from thread #{id}"&lt;br /&gt;  sleep(0.2)&lt;br /&gt; end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;t1.join&lt;br /&gt;t2.join&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Para controlar las secciones criticas tan solo hay que cambiar la variable de clase critical a true.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 1px solid black; padding: 5px; background-color: rgb(51, 102, 153); color: rgb(0, 0, 0);"&gt;&lt;pre wrap=""&gt;#!/usr/bin/ruby&lt;br /&gt;&lt;br /&gt;counter = 0;&lt;br /&gt;&lt;br /&gt;t1 = Thread.new do&lt;br /&gt; 100000.times do&lt;br /&gt;  Thread.critical = true&lt;br /&gt;  counter += 1&lt;br /&gt;  Thread.critical = false &lt;br /&gt; end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;t2 = Thread.new do&lt;br /&gt; 100000.times do&lt;br /&gt;  Thread.critical = true&lt;br /&gt;  counter -= 1&lt;br /&gt;  Thread.critical = false&lt;br /&gt; end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;t1.join&lt;br /&gt;t2.join&lt;br /&gt;&lt;br /&gt;puts counter&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Se pueden consultar los demás métodos de la clase Thread en la &lt;a href="http://corelib.rubyonrails.org/classes/Thread.html"&gt;documentación oficial&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-3821634811669781314?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/3821634811669781314/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=3821634811669781314&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3821634811669781314'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3821634811669781314'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/08/threads-en-ruby.html' title='Threads en ruby'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3499379363161703464.post-3541658630500725805</id><published>2008-08-21T21:51:00.003+02:00</published><updated>2008-08-21T22:11:45.184+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='programacion'/><title type='text'>Resaltado de expresiones regulares</title><content type='html'>A veces cuando estamos trabajando con expresiones regulares nos podemos perder un poco, para hacer más fácil la tarea se puede realizar un resaltado del &lt;span style="font-style:italic;"&gt;matching&lt;/span&gt; de la siguiente forma.&lt;br /&gt;&lt;br /&gt;&lt;div style="border: 1px solid black; padding: 5px; background-color: rgb(51, 102, 153); color: rgb(0, 0, 0);"&gt;&lt;pre wrap=""&gt;#!/usr/bin/ruby&lt;br /&gt;&lt;br /&gt;pre = "\033[7m"&lt;br /&gt;post = "\033[m"&lt;br /&gt;&lt;br /&gt;print "Cadena&amp;gt; "&lt;br /&gt;STDOUT.flush&lt;br /&gt;str = gets.chop!&lt;br /&gt;&lt;br /&gt;while true&lt;br /&gt; print "Expresion regular&amp;gt; "&lt;br /&gt; STDOUT.flush&lt;br /&gt; re = Regexp.new(gets.chop!)&lt;br /&gt; puts str.gsub(re, "#{pre}\\&amp;amp;#{post}")&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Un ejemplo de uso.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_3QpXB2efkAA/SK3L3E9e8AI/AAAAAAAAAHA/_m9nr8amz4E/s1600-h/captura.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_3QpXB2efkAA/SK3L3E9e8AI/AAAAAAAAAHA/_m9nr8amz4E/s320/captura.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5237066088786620418" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3499379363161703464-3541658630500725805?l=javiyu.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://javiyu.blogspot.com/feeds/3541658630500725805/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3499379363161703464&amp;postID=3541658630500725805&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3541658630500725805'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3499379363161703464/posts/default/3541658630500725805'/><link rel='alternate' type='text/html' href='http://javiyu.blogspot.com/2008/08/resaltado-de-expresiones-regulares.html' title='Resaltado de expresiones regulares'/><author><name>javiyu</name><uri>http://www.blogger.com/profile/16257073535399021686</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_3QpXB2efkAA/SK3L3E9e8AI/AAAAAAAAAHA/_m9nr8amz4E/s72-c/captura.png' height='72' width='72'/><thr:total>0</thr:total></entry></feed>
