Noticias sobre mis proyectos

jueves, 30 de diciembre de 2010

Barça es todo CORAZÓN

Xavi inauguró el marcador

Si todavía Ud. tenía dudas de que los catalanes sabían bailar, pregúntele al  Real Madrid. Ni Cristiano Ronaldo, ni ninguna otra de sus estrellas pudo detener la sinfonía. Todos se seguían muy bien el ritmo: era el mismo compás que escuchaban las últimas 5 veces que enfrentaron a este equipo; era la sinfonía de Guardiola. Los corazones de todos los jugadores, del público, ... todo estaba bien coordinado para lograr la resonancia que sentimos en el Camp Nou. Mourinho estaba muy fatigado (por decirlo de alguna forma ...) y no sabía cómo bailar este vals (¿o era una polka?): nada de paseitos, nada de reclamos a los árbitros, ni picardías ... todo era en vano. Y es que el  Barça quiere el balón y el afecto es recíproco. Después de un favorable 6-2 en el encuentro previo ahora el equipo merengue se llevo una manito.

Mourinho cariacontecido

Pero esto no bastaba y volvimos a la carga. Próxima víctima el  Rubin Kazan. Esta vez se rompió el hechizo. Lo que no lograron los titulares años atrás, lo supieron hacer los suplentes esta vez. Porque el  Barça es todo talento; sin dudas el relevo está asegurado. Esta vez la máquina no quiere parar. Para no dejar lugar a dudas, ya lejos del Camp Nou, la visita a la  Real Sociedad también rindió sus frutos. De allí nos llevamos otra manito. Sí, necesitábamos DOS manos porque así una lava la otra, así como Messi también hizo DOS goles.

Celebración de Xavi Hernández Messi, Xavi e Iniesta aspirantes al Balón de Oro

Lo que muchos todavía no entienden es que  Barça es puro orgullo. Es por eso que son la base del equipo de España, actual campeón del mundo; es por eso que la CANTERA otra vez VENCIÓ a la CARTERA; es por eso que provienen de allí los tres  candidatos al Balón de Oro (aunque confieso que prefiero a Schneider o Forlán en vez de Iniesta); es por eso que todo el mundo está de fiesta ... simplemente ES QUE EL BARÇA ES TODO CORAZÓN.

jueves, 23 de diciembre de 2010

Usar bindings de XAML para mostrar valores de tipos enumerados en controles WPF

Microsoft.NET

Este artículo es breve y consiste en una respuesta a  un pequeño tutorial que publicó mi amigo Feston en  su blog. Su solución consiste en utilizar el método GetValues para obtener un arreglo con todos los valores definidos para el tipo de datos en cuestión. Sin embargo, ¿realmente es necesario escribir líneas de código para lograr esto? Continúe leyendo y conocerá una alternativa que logra el mismo efecto, pero sólo utiliza el fichero XAML (que es dónde debería especificarse este tipo de cosas).

El procedimiento es simple (qué otra cosa podría decir :). Comencemos por crear una aplicación WPF sencilla (menú File > New > Project ... y selccionar WPF Application). El Visual Studio mostrará el editor WPF con una ventana vacía. Para hacer más simple el ejemplo, editaré el fichero Window1.xaml.cs para que luzca de la forma siguiente. Esto no implica que haya pérdida de generalidad en la discusión, puesto a que los pasos son similares si el tipo enumerado se define en otro fichero o assembly.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace EnumNamespace {
    public enum MyEnum {Value1, Value2, Value3, Value4}
}

namespace WpfEnumBinding {
    public partial class Window1 : Window {
        public Window1() {
            InitializeComponent();
        }
    }
}

Una vez hecho esto, se añade en el fichero XAML una referencia al namespace dónde se encuentra el tipo enumerado y otra al namespace System (seguro que el IntelliSense ayudará mucísimo ;o). Luego se define un recurso del tipo ObjectDataProvider que permita hacerle binding al valor que devuelve el método GetValues. Posteriormente se utiliza la extension StaticResource para hacer referencia al valor en cuestión. Si utilizamos un combobox, el fichero XAML queda de la siguiente manera:

<Window x:Class="WpfEnumBinding.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:EnumNamespace="clr-namespace:EnumNamespace"
    xmlns:System="clr-namespace:System;assembly=mscorlib"
    Title="Window1" Height="300" Width="300">
    <Window.Resources>
        <ObjectDataProvider x:Key="MyEnumResource" 
                            MethodName="GetValues" 
                            ObjectType="{x:Type System:Enum}">
            <ObjectDataProvider.MethodParameters>
                <x:Type TypeName="EnumNamespace:MyEnum" />
            </ObjectDataProvider.MethodParameters>
        </ObjectDataProvider>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="25" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <ComboBox ItemsSource="{Binding Source={StaticResource MyEnumResource}}"/>
    </Grid>
</Window>

... y la aplicación luce así

Espero que les sea útil esta sugerencia, al menos para aplicar en otras circunstancias parecidas los conocimientos adquiridos. Si le gustó este artículo le digo que los demás serán igual de interesantes, por lo que le invito a  suscribirse a este blog para que este al tanto de otros trucos similares. No lo olvide simelo pide siempre habrá una respuesta a esa inquietud o duda que Usted tenga del mundo de la informática y la programación.

Moropo: Bind de un tipo Enum a un combobox en C#

martes, 20 de julio de 2010

Dibujando figuras geométricas con Eukleides y LATEX

Problema 4 IMO 2007 Hanoi

Regreso después de unas vacacaciones durante las cuales la nostalgia me hizo regresar a la solución de ejercicios de las Olimpiadas Internacionales de Matemáticas. Esta vez les narraré cómo obtuve con ayuda de Eukleides la figura de uno de los problemas de geometría que resolví. La necesitaba para publicar la demostración en un nuevo blog de Soluciones de Olimpiadas, donde trataré de documentar mis experiencias en la lucha constante que ha representado la resolución de estos ejercicios tan complejos. ¡Ojalá hubiéramos tenido una herramienta como esa en mis tiempos! Espero que les sea útil a ustedes también. Me siento satisfecho puesto a que hace más de siete años que no intentaba resolverlos, así que todavía estoy en forma :o). Usted puede suscribirse a este blog si desea estar al tanto de otros temas igual de interesantes. Si lo desea también puede recibir automáticamente las respuestas a los ejercicios que se irán publicando en el nuevo blog de Soluciones de Olimpiadas. Si Usted desea también puede solicitar permisos para publicar sus propias soluciones, o artículos relacionados con estos eventos.

¿Qué es Eukleides?

Existen varias alternativas para lograr que una computadora dibuje figuras geométricas en el plano. LaTeX es una de ellas. Sin embargo, en gran parte de los casos hay que emplear herramientas diseñadas desde el punto de vista del funcionamiento interno de la computadora. En otros casos hay que especificar hasta el más mínimo detalle para obtener una figura medianamente comprensible. Todo esto dificulta el aprendizaje y la rápida familiarización de los usuarios con la herramienta, puesto a que se impone una nueva forma de pensar y a veces se necesita hasta realizar cálculos no siempre evidentes.

Eukleides es una herramienta genial que interpreta un lenguaje descriptivo para obtener representaciones de figuras de la geometría euclideana. Sus características permiten que se pueda obtener una figura conociendo solamente los conceptos matemáticos y las relaciones entre los puntos y las curvas que se mencionan en el ejercicio en cuestión. Resulta asombroso que el enunciado del problema se pueda traducir casi directamente para obtener la descripción de la figura. Utilicemos el mismo problema de geometría que resolví para ilustrar lo que estoy diciendo. Su enunciado es el siguiente :

Problema 4 - IMO 2007 (Vietnam). En un triángulo ABC la bisectriz del ángulo BCA y la circunferencia circunscrita al triángulo se cortan en R (R != C). Dicha recta corta a la mediatriz de BC en P y a la mediatriz de AC en Q . El punto medio de BC es K y el punto medio de AC es L . Demostrar que los triángulos RPK y RQL tienen áreas iguales.

A continuación representaré las condiciones del problema (resaltadas en negritas ;o) en el órden que van apareciendo en el enunciado de problema. Solo tengan en cuenta que utilizo la sintaxis de la versión 1.0.3 de eukleides (después explico más al respecto ;o)

A B C triangle

l = bisector(B, C, A)
c = circle(A, B, C)
C R intersection(l, c)
P = intersection(l, perpendicular(segment(B, C), midpoint(segment(B, C)) ))
Q = intersection(l, perpendicular(segment(A, C), midpoint(segment(A, C)) ))
K = midpoint(segment(B, C))
L = midpoint(segment(A, C))

draw(A, B, C)
draw(l)
draw(c)
draw(segment(K, P), dashed)
draw(segment(L, Q), dashed)

draw("$A$", A, -130:)
draw("$B$", B, -50:)
draw("$C$", C, 130:)
draw("$P$", P, 0.1, -160:)
draw("$Q$", Q, 0.1, 50:)
draw("$R$", R, -130:)
draw("$K$", K, 50:)
draw("$L$", L, 130:)

color(gray)
mark(A, C, R)
mark(B, C, R)

Esto es todo lo que se necesita. Como se puede apreciar el lenguaje es declarativo y resulta increíble la similitud con el enunciado del problema. También hay que resaltar que hay comandos específicos para dibujar y para denotar los puntos y rectas que aparecen en la figura. Con ellos se pueden obtener distintos estilos y formas.

Para obtener la figura incluimos en texto anterior en el fichero imo2k7pb4.euk y luego instalamos eukleides y sus dependencias (Eukleides utiliza las extensiones PSTricks de LaTeX). En Debian o Ubuntu solo está empaquetada la la versión 1.0.3 de eukleides, pero la la versión 1.5.4 de eukleides cubre las mismas necesidades con un lenguaje más expresivo. Sin embargo es posible encontrar la versión 1.5.4 empaquetada en sid, por lo que quizás pronto la tendremos en los repositorios. La instalación se haría de la siguiente manera :

$ sudo apt-get install eukleides ; XXX dependencias

Después se utiliza el comando euk2edit y se especifica el formato de salida que se desea obtener (en este caso un fichero PostScript)

$ euk2edit imo2k7pb4.euk ps

El fichero imo2k7pb4.ps contiene ahora la figura en el formato deseado. Para conocer todos los formatos que se pueden obtener, basta con leer la salida del comando

$ pstoedit -help

Conclusiones

La herramienta también permite la traducción de los comandos a varios idiomas. El fichero anterior podría ser escrito también en español (si hubiera una traducción ;o) de esta forma

A B C triangulo

l = bisectriz(B, C, A)
c = circulo(A, B, C)
C R interseccion(l, c)
P = interseccion(l, perpendicular(segmento(B, C), puntomedio(segmento(B, C)) ))
Q = interseccion(l, perpendicular(segmento(A, C), puntomedio(segmento(A, C)) ))
K = puntomedio(segmento(B, C))
L = puntomedio(segmento(A, C))

dibuja(A, B, C)
dibuja(l)
dibuja(c)
dibuja(segmento(K, P), discontinuo)
dibuja(segmento(L, Q), discontinuo)

dibuja("$A$", A, -130:)
dibuja("$B$", B, -50:)
dibuja("$C$", C, 130:)
dibuja("$P$", P, 0.1, -160:)
dibuja("$Q$", Q, 0.1, 50:)
dibuja("$R$", R, -130:)
dibuja("$K$", K, 50:)
dibuja("$L$", L, 130:)

color(gris)
resalta(A, C, R)
resalta(B, C, R)

Si consideramos que existe una herramienta visual llamada xeukleides, entonces ¡hasta un niño podría hacer esto y obtener sus figuras! . Espero que les haya gustado este artículo. Suscríbase a este blog si desea continuar este viaje para descubrir las bondades de los diferentes software libres. No olvide que si Usted desea también puede solicitar permisos para publicar sus propias demostraciones en el blog de Soluciones de Olimpiadas, o artículos relacionados con estos eventos. La invitación está hecha para recibir automáticamente las respuestas a los ejercicios que se irán publicando allí.

viernes, 28 de mayo de 2010

Pentagramas para la web

Notación musical en el Canvas

¿Que tal si se pudiera escribir música en una notación como la que se muestra a continuación y que fuera representada visualmente cómo muestra la figura? Mohit Muthanna ha implementado la noción de pentagrama utilizando el elemento canvas de HTML5 (algo que Internet Explorer no implementará). La versión actual es reciente aún, y todavía necesita un DSL para escribirla. Jono de Mozilla trabajó en un simple DSL basado en texto que resultó muy interesante porque permite hacerlo con solo modificar el texto en un elemento textarea. Si desea conocer los detalles continúe leyendo hasta el final. Le invito a suscribirse mediante RSS si desea estar al tanto de otras noticias del mundo de la informática, y las tecnologías web.

score {
  title: Hip Tune
  artist: Hip Person
  bar { v8 C4 D4 E4 F4 (C4 E4 G4) } 
  bar { v8 C4 D4 E4 F4 (C4 E4 G4) } repeat 3
}
 

La API luce actualmente de la siguiente forma:

function VexNotationDemo1(b) {
    b = new Vex.Music.Artist(b, {
        scale:0.9, width:900
    });
    var c = b.CreateScore(),
        d = b.CreateScore();
    b.DrawScore(c);
    var e = GetBar1(b,c);
    b.DrawBar(e);
    e = GetBar2(b,c);
    b.DrawBar(e);
    e = GetBar3(b,c);
    b.DrawBar(e);
    e = GetBar4(b,c);
    b.DrawBar(e);
    c = GetBar5(b,c);
    b.DrawBar(c);
    b.DrawScore(d);
    c = b.CreateContinuingBarFrom(c,d);
    b.DrawBar(c);
    d = GetBar7(b,d);
    b.DrawBar(d)
}
    
function GetBar4_2(b,c) { 
    c = b.CreateBar(c);
    var d = c.AddLine();
    d.AddNote(b.CreateNote({keys:["f##/4"],duration:"h"}));
    var e = [];
    e.push(b.CreateNote({keys:["a##/4"],duration:"16"}));
    e.push(b.CreateNote({keys:["f##/5"],duration:"16"}));
    e.push(b.CreateNote({keys:["f##/5"],duration:"16"}));
    e.push(b.CreateNote({keys:["f##/5"],duration:"16"}));
    e.push(b.CreateNote({keys:["f#/4","a/4","f/5"],duration:"16"}));
    e.push(b.CreateNote({keys:["f#/4","a/4","f/5"],duration:"16"}));
    d.AddNotes(e);
    e = b.CreateBeam(e);
    d.AddBeam(e);
    e = b.CreateNote({keys:["db/4"],duration:"32"});
    var f = b.CreateNote({keys:["f#/4"],duration:"32"}),
        g = b.CreateNote({keys:["db/4"],duration:"32"}),
        h = b.CreateNote({keys:["f#/4"],duration:"32"});
    d.AddNote(e);
    d.AddNote(f);
    d.AddNote(g);
    d.AddNote(h);
    b = b.CreateBeam([e,f,g,h]);
    d.AddBeam(b);
    return c;
}
 

SVG podría ser también una buena opción para hacer esto. En cualquier caso sería genial tener un control que generara el audio a partir de la partitura, no creen?

miércoles, 26 de mayo de 2010

Control de usuarios personalizado con Apache y mod_authnz_external

Apache Software Foundation

A medida que pasa el tiempo me convenzo más de que es correcto separar la lógica de autentificación de los usuarios y el código de las aplicaciones web. En este artículo explicaré una alternativa para delegar estas tareas al servidor Apache, pero sin tener que escribir un nuevo módulo. Por fortuna existen muchas extensiones de propósito específico para hacer esto. Un ejemplo notable es mod-auth-pam, el cual expande las posibilidades pues se aprovecha toda la flexibilidad que ofrece la arquitectura Pluggable Authentication Modules. Pero por ejemplo, ¿qué hacer si ya tenemos una aplicación que brinda acceso a los usuarios de una forma muy particular y queremos reutilizar en nuevas aplicaciones ese método y los mismos datos? Continúe leyendo este artículo y encontrará la vía de solución. Notará que la configuración es relativamente fácil de hacer en sistemas GNU/Linux como Ubuntu . No olvide suscribirse a este blog si desea conocer más trucos del mundo de la informática.

¿Qué es mod_authnz_external?

Existen muchas extensiones de propósito específico para validar la identidad de los usuarios. La lista incluye a authn_alias, authn_anon, authn_dbd, authn_dbm, authn_default, authn_file, authnz_ldap, authz_dbm, authz_default, authz_groupfile, authz_host, authz_owner, authz_user, mod-auth-kerb, mod-auth-mysql, mod-auth-pgsql, mod-auth-plain, authcassimple-perl, authenntlm-perl, mod-auth-cas, mod-auth-openid, mod-auth-radius, mod-auth-sys-group, mod-authn-sasl, mod-authnz-external, mod-authz-unixgroup, webauth. El módulo mod_authnz_external es un módulo de Apache que permite autenticar los usuarios contra servicios externos. Sus ventajas consisten en que se puede utilizar para construir rápidamente infraestructuras de este tipo que sean seguros y fiables. Sin embargo hay que ser muy cuidadosos pues, si se utiliza mal, puede ser una fuente de vulnerabilidades. Esto se debe a que se delega todo el trabajo a un proceso externo que ejecuta un script configurado para este próposito. Además, debido a su diseño, no siempre es posible utilizarlo junto con autentificación del tipo Digest. Por tal razón frecuentemente se necesitaría transmitir las claves como texto plano. Una solución a este problema sería utilizar SSL. Pero, bueno, vayamos al grano ...

Seguridad web basada en los usuarios del sistema

Una de las aplicaciones más notables de este módulo es poder reutilizar la base de datos de usuarios locales del sistema para proteger una aplicación web, sin tener que exponer el fichero shadow. Para eso utilizaremos pwauth. Solo con unas pocas líneas ya es posible saber lo que hace

$ sudo apt-get install pwauth
$ sudo pwauth
myuser
mypassword
$ echo $?
0
$ sudo pwauth
myuser
wrong_password
$ echo $?
1

Como se puede observar el programa lee el usuario y la contraseña desde la entrada estándar y facilita el resultado a través del código de retorno del proceso (el valor 0 indica que los datos son correctos). Para ilustrar el resto del proceso, supongamos que tenemos una instancia de Trac corriendo con FastCGI. Para utilizaríamos unas líneas como las que aparecen a continuación:

ScriptAlias /trac /var/lib/trac/share/cgi-bin/trac.fcgi
<Location "/trac">
  Order allow,deny
  Allow from all
</Location>
ApacheConf

Para lograr nuestro objetivo solo debemos instalar el módulo y habilitarlo.

$ sudo apt-get install libapache2-mod-authnz-external
$ sudo ln -s /etc/apache2/mods-available/authnz_external.load /etc/apache2/mods-enabled/authnz_external.load

Luego procedemos a modificar el archivo de la siguiente forma.

# Registrar el método 'unix' para ejecutar `pwauth` e 
# interactuar a través de la entrada y salida estándar
DefineExternalAuth unix pipe /usr/sbin/pwauth   

ScriptAlias /trac /var/lib/trac/share/cgi-bin/trac.fcgi
<Location "/trac">
  Order allow,deny
  Allow from all

  # Autentificación básica
  AuthType Basic

  # Utilice un valor de su preferencia
  AuthName "swl"

  # El módulo `authnz_external` se hará cargo
  # de verificar la identidad de los usuarios
  AuthBasicProvider "external"

  # Para esta aplicación se utilizará el script identificado como 
  # 'unix' (ver la directiva `DefineExternalAuth` más arriba ;o)
  AuthExternal "unix"

  # Proteger el sitio (denegar acceso anónimo)
  require valid-user
</Location>
ApacheConf

¡Es así de simple! Espero que les sea útil en su quehacer cotidiano. Le sugiero suscribirse a este blog pues en próximos artículos podrán conocer cómo escribir su propio utilitario para validar los nombres de usuarios y las contraseñas.

jueves, 29 de abril de 2010

¡ Bienvenido Ubuntu Lucid Lynx !

Hoy se espera el lanzamiento oficial de Ubuntu 10.04 (Lucid Lynx) . Vendrá con 3 años de soporte para estaciones de trabajo y cinco para servidores. A continuación les muestro el calendario de las distribuciones y la armonización con Debian squeeze que se ha considerado.

Calendario de las distribuciones

Armonización con Debian squeeze

Ubuntu Debian RHEL SLES
Kernel 2.6.32 + drm-33 2.6.32 + drm-33 2.6.32 2.6.32
GCC 4.4 4.4
Python 2.6 2.6
OpenOffice.org 3.2 3.2
Perl 5.10.1 5.10.1
Boost 1.40 1.40
X Server 1.7 1.7
Mesa 7.7 7.7
Mono (thanks Jo Shields) 2.4-snapshot 2.4-snapshot

miércoles, 21 de abril de 2010

Kohsuke Kawagushi se despide de Sun (Oracle). ¿También Hudson?

Kohsuke Kawagushi a la izquierda

En entradas anteriores ya les había comentado acerca de la fusión entre Oracle y Sun, y comentaba acerca de las implicaciones de la alianza. Brevemente quería hacerles saber que a principio de este mes de abril Kohsuke Kawagushi 1 ha decidido pasar página a sus años como empleado de Sun. Según el anuncio oficial en el blog de Hudson, en lo sucesivo sus esfuerzos estarán dirigidos a organizar una compañía que promueva el desarrollo del producto que le ha hecho mundialmente reconocido: el servidor de integración continua Hudson.

La calidad de este software está avalada por su vasta comunidad de usuarios y los galardones que le han sido otorgados. Entre ellos podemos mencionar el 2008 Duke's Choice Award. Hudson tiene un lado comercial conocido como Sun Continuous Integration Server. Realmente no se menciona nada sobre la posibilidad de ser asumido por Oracle. Solo se conoce que

We are revisiting the support offering as we transition into Oracle. Please check back later for updates.

Sin embargo espero que, en el global, todo esto beneficie al producto y mantenga viva su comunidad de usuarios. Para más detalles le invito a seguir el blog de Hudson. Próximamente (cuando aprenda dos o tres cosas ;o) espero poder comentarles un poco más acerca de este excelente producto. Simelo pide, no faltará un consejo útil para que Usted comience a experimentar los beneficios de la integración continua. No pierda las oportunidad de estar actualizado.

jueves, 15 de abril de 2010

Soporte para AMF (RPC) en Trac

Parche de la API multi-protocols para Trac

Otro día histórico. Después que Odd Simon Simonsen me invitara a participar en el desarrollo del muy útil y exitoso plugin TracXmlRpc y añadir soporte para Hessian, le ha tocado el turno a Action Message Format. Este es un protocolo binario diseñado por Macromedia, actualmente absorbido por Adobe Systems. Su objetivo es proporcionar un medio ligero y eficiente para codificar, decodificar y transportar datos entre Flash Player y el Flash Remoting gateway. En otras palabras se puede utilizar Flash Remoting MX con ActionScript para hacer aplicaciones interactivas, en este caso utilizando datos de proyectos administrados por Trac. El nuevo componente que ha sido construido permite tener más elementos de juicio para evaluar la API que se desarrolla actualmente, y que permitirá ejecutar los métodos disponibles a través de múltiples protocolos. Hace solo unos minutos efectué la primera llamada exitosa utilizando AMF desde Python . Los detalles ...

... no quiero adelantar mucho todavía porque la implementación no está estable y muy probablemente se le hagan cambios incompatibles al prototipo de la API que existe hoy. Pero bueno, todo comenzó con un parche ofrecido por thijs para incorporarlo en el plugin plugin TracXmlRpc. En ese momento solo existían implementaciones para dos protocolos muy populares: XML-RPC, JSON-RPC. Hay soporte para el primero en la librería estándar (i.e. xmlrpclib.ServerProxy), mientras que el segundo es accesible si se utilizan otras librerías (e.g. wsgi-jsonrpc). En el caso específico de AMF, el autor del parche ofreció un ejemplo basado en PyAMF que luego modifiqué un poco hasta obtener lo siguiente :

#!/usr/bin/env python

"""
AMF client for the Trac RPC plugin.
"""

import base64
from optparse import OptionParser
from socket import error
import sys

from pyamf.remoting import RemotingError
from pyamf.remoting.client import RemotingService

p = OptionParser()

p.add_option("-U", dest="username",
                  help="Trac USER", metavar="USER")
p.add_option("-P", dest="password", metavar="PASSWORD",
                  help="use PASSWORD to authenticate USER")
p.add_option("-e", dest="env", metavar="URL",
                  help="base URL of target environment")

(opts, args) = p.parse_args()

username = opts.username
password = opts.password
try :
  url = opts.env + '/rpc'
except :
  sys.exit("Missing Trac environment. Use -e option.")

service_name = 'system'

gw = RemotingService(url)
if (username, password) != (None, None):
  auth = base64.encodestring('%s:%s' % (username, password))[:-1]
  gw.addHTTPHeader("Authorization", "Basic %s" % auth)

service = gw.getService(service_name)

try:
    print service.getAPIVersion()
except RemotingError, e:
    print e
except error, e:
    print e[1]

Como se puede ver, si la base del servidor se encuentra, por ejemplo, en http://localhost/trac entonces el protocolo está disponible en http://localhost/trac/rpc. Realmente esta URL debe servir para todos los protocolos disponibles que ya mencioné anteriormente y los que vendrán. El tipo de protocolo se determina considerando el encabezado Content-Type de la petición HTTP, que en este caso es application/x-amf. Esta es la idea fundamental que utilizó Odd para diseñar la API.

El script anterior muestra el número de la versión del protocolo. Para probar, ejecutamos el módulo de la siguiente forma

$ python ./amf-client.py -U username -P mypassword -e http://localhost/trac
[1, 1, 0]

¡Y ya está! . A continuación les muestro otro ejemplo más simplificado utilizando solamente el intérprete de Python.

>>> import base64
>>> from pyamf.remoting import RemotingError
>>> from pyamf.remoting.client import RemotingService
>>> username, password = 'olemis', 'mypassword'
>>> url = 'http://localhost/trac/rpc'
>>> gw = RemotingService(url)
>>> auth = base64.encodestring('%s:%s' % (username, password))[:-1]
>>> gw.addHTTPHeader("Authorization", "Basic %s" % auth)
>>> service = gw.getService('system')
>>> print service.getAPIVersion()
[1, 1, 0]

¡Eso es todo! Todas estas implementaciones serán ofrecidas próximamente por el plugin TracRpcProtocols. Si quiere estar al tanto del desarrollo de esta nueva funcionalidad le invito a seguir los próximos artículos. El soporte de AMF para Trac es solo el segundo capítulo de la primera temporada (gracias osimons y thijs ;o) .

martes, 6 de abril de 2010

Demanda sobre patente impide distribuir Microsoft Word

Microsoft Office

El gigante Microsoft acaba de ver rechazada su petición a la corte de apelaciones de los Estados Unidos. Por segunda vez, la firma sigue siendo acusada de haber violado las patentes relacionadas con el procesamiento de ficheros XML en el producto Microsoft Office Word . El 22 de diciembre pasado el tribunal había dictaminado la indemnización por un monto de $ 290 millones USD que engrosarían las arcas de la sociedad canadiense i4i. Además se ordenó la prohibición de la venta de su producto Microsoft Word en territorio estadounidense. Recientemente la sociedad canadiense i4i explica en un comunicado que la instancia judicial ha rechazado la demanda del gigante de Redmond con el objetivo de que un panel de 11 jueces reconsidere el caso. 

Loudon Owen, presidente de i4i declaró que "El proceso fue largo y desgastante, pero esta decisión refuerza fuertemente el mensaje de que las pequeñas empresas y los titulares de las invenciones amparados por la propiedad intelectual pueden ser protegidos, y lo serán" . Como resultado Microsoft está obligado a retirar inmediatamente la función XML de Microsoft Word 2003 y 2007 . Sin embargo los recursos no están agotados. Todavía es posible continuar el proceso de apelación o solicitar al veredicto de la Corte Suprema para seguir revisando el caso.

lunes, 29 de marzo de 2010

Comparación de sistemas de control de versiones (a.k.a.VCS o SCM)

En esta breve entrada quería invitarles a que visiten el sitio http://versioncontrolblog.com , sobre todo si están tratando de decidir cuál sistema de control de versiones utilizarán. Allí es posible ver una tabla que compara las funcionalidades de los sistemas que se seleccionen teniendo en cuenta varios criterios como.

  • Commits atómicos
  • Soporte para seguir copias de ficheros y carpetas
  • Duplicación remota del repositorio
  • Control de acceso
  • Posibilidad de trabajar en un único sub-directorio
  • Interfaz web
  • Disponibilidad de interfaces de usuario gráficas
  • ... mucho más ...

Espero les sea útil el consejo ;o)

Tutorial: Cómo crear enlaces directos en Windows con Python

Enlaces directos en Windows

En esta ocasión trataré de resumir varios artículos escritos por Mike Driscoll y Tim Golden. Todos estos tutoriales tratan de explicar diferentes vías para crear desde Python enlaces directos (a.k.a shortcuts) para acceder a aplicaciones de Windows. Mi intención es, primeramente, acordarme. En segundo lugar quisiera facilitar documentar en un solo lugar los enfoques disponibles, y tratar de ilustrar las diferencias más ventajas o desventajas. Finalmente el texto estará en español ;o). Antes que todo, si todavía no se ha dado cuenta le digo que solo hablaré de Microsoft Windows. El artículo puede servir también como un pequeño mini-tutorial acerca del uso de los módulos winshell, win32com, pythoncom y habrá hasta un poquito de corrutinas ;o). Si desea estar al tanto de próximos artículos igualmente útiles, le invito a suscribirse por medio de RSS.

Preparación

Python Programming on Win32

Lo primero que hay que hacer es instalar las extensiones de Python para Win32 que se encuentran en el paquete de Mark Hammond llamado PyWin32. Igualmente útil puede resultar tener listo el módulo winshell de Tim Golden. Este último permite ubicar fácilmente las carpetas especiales (semi-mágicas) del sistema.

Creando un enlace a una URL en el Escritorio

Quizás la tarea más sencilla es crear un enlace (a.k.a link) en el Escritorio para acceder fácilmente a un sitio conocido. En caso que sea suficiente utilizar el navegador de Internet predeterminado, solo tendríamos que hacer esto:

import os.path, winshell

desktop = winshell.desktop()
path = os.path.join(desktop, "myNeatWebsite.url")
target = "http://www.google.com/"
 
shortcut = file(path, 'w')
shortcut.write('[InternetShortcut]\n')
shortcut.write('URL=%s' % target)
shortcut.close()

Brevemente podemos apreciar cómo se utiliza el módulo winshell para obtener el camino al Escritorio del usuario y se crea un fichero con extensión .url dentro de esta carpeta. El contenido de este fichero es el requerido por el sistema operativo y, finalmente debe lucir más o menos así

[InternetShortcut]
URL=http://www.google.com/

¡Eso es todo! :o)

La solución a más bajo nível con pythoncom

Quizás la versión más complicada, y por tanto más explícita, es la que se obtiene al utilizar la API Win32 desde Python. Para ello se emplea el módulo pythoncom, que permite cargar cualquier objeto COM e interactuar casi directamente con las interfaces y otros elementos. Veamos el ejemplo.

import os, sys
import pythoncom
from win32com.shell import shell, shellcon
 
shortcut = pythoncom.CoCreateInstance (
  shell.CLSID_ShellLink,
  None,
  pythoncom.CLSCTX_INPROC_SERVER,
  shell.IID_IShellLink
)
program_location = r'C:\Program Files\SomeCoolProgram\prog.exe'
shortcut.SetPath (program_location)
shortcut.SetDescription ("My Program Does Something Really Cool!")
shortcut.SetIconLocation (program_location, 0)
 
desktop_path = shell.SHGetFolderPath (0, shellcon.CSIDL_DESKTOP, 0, 0)
persist_file = shortcut.QueryInterface (pythoncom.IID_IPersistFile)
persist_file.Save (os.path.join (desktop_path, "My Shortcut.lnk"), 0)

Como se puede apreciar esto no es muy pitónico que digamos, sobre todo debido a que la API Win32 está diseñada para ser utilizada desde lenguajes como C. Más adelante se verán otras formas más sencillas de hacerlo. Sin embargo, creo que es un ejemplo muy interesante porque revela que los conocedores de la API Win32 siempre podrán utilizarla desde Python de una forma muy similar a la que ya están acostumbrados. Veamos qué está pasando.

Después de importar los módulos necesarios, se carga una instancia de la clase ShellLink y se indica que se utilizarán los métodos de la interfaz IShellLink que ella implementa. Por suerte los GUID de ambos ya están definidos (i.e. win32com.shell.shell.CLSID_ShellLink, win32com.shell.shell.IID_IShellLink). La función pythoncom.CoCreateInstance no es más que un simple wrapper alrededor de la archi-conocida función con un nombre similar presente en la API Win32. A continuación se especifican los datos necesarios para crear el enlace (i.e. programa a ejecutar, descripción y el ícono). En este momento ya todo está casi listo.

Lo único que falta por hacer es crear el fichero con la información que hemos especificado anteriormente. El último bloque de instrucciones se encarga de esto. La función win32com.shell.shell.SHGetFolderPath es similar a la presente en la API Win32. En este caso se utiliza la constante win32com.shell.shellcon.CSIDL_DESKTOP para obtener el camino a la carpeta del escritorio del usuario. Allí se creará el fichero My Shortcut.lnk, que es el que deseamos. Para hacerlo, hay que utilizar el objeto COM anterior pero necesitamos el método Save definido en la interfaz IPersistFile (su GUID es pythoncom.IID_IPersistFile). El método QueryInterface hace todo el trabajo de preparación.

A continuación les presento un código que utiliza la misma filosofía para actualizar el enlace creado en la sección anterior y hacer que apunte a otra URL.

import os, sys
import pythoncom
from win32com.shell import shell, shellcon

shortcut = pythoncom.CoCreateInstance (
  shell.CLSID_InternetShortcut,
  None,
  pythoncom.CLSCTX_INPROC_SERVER,
  shell.IID_IUniformResourceLocator
)

desktop_path = shell.SHGetFolderPath (0, shellcon.CSIDL_DESKTOP, 0, 0)
shortcut_path = os.path.join (desktop_path, "myNeatWebsite.url")
persist_file = shortcut.QueryInterface (pythoncom.IID_IPersistFile)
persist_file.Load (shortcut_path)

shortcut.SetURL ("http://python.org")
persist_file.Save (os.path.join (shortcut_path, "myNeatWebsite.url"), 0)

Creando un enlace al Media Player Classic con win32com

Python

Este ejemplo será un tin más complejo. Utilizaremos el módulo win32com para crear un enlace. Este módulo brinda acceso desde Python a ciertos componentes implementados sobre la tecnología COM, así que se trata de una operación digamos que a bajo nivel. Sin embargo, La ventaja en este caso consiste en que se facilitan varios pasos que sí son necesarios si se utiliza la API Win32 directamente con otros lenguajes (e.g. C, Object Pascal), o cómo se mostró en el ejemplo anterior. Veamos el código.

import os, winshell
from win32com.client import Dispatch
 
desktop = winshell.desktop()
path = os.path.join(desktop, "Media Player Classic.lnk")
target = r"P:\Media\Media Player Classic\mplayerc.exe"
wDir = r"P:\Media\Media Player Classic"
icon = r"P:\Media\Media Player Classic\mplayerc.exe"
 
shell = Dispatch('WScript.Shell')
shortcut = shell.CreateShortCut(path)
shortcut.Targetpath = target
shortcut.WorkingDirectory = wDir
shortcut.IconLocation = icon
shortcut.save()

Como se puede apreciar, en este caso se utiliza el shell de Windows mediante la interfaz IDispatch (más bien su equivalente en Python win32com.client.Dispatch ;o). Se utiliza el identificador WScript.Shell para cargar el objeto COM que deseamos y luego se utilizan sus métodos para asociarle el camino donde se guardará el enlace, el del ejecutable, el directorio de trabajo inicial, y el ícono que se mostrará. Este último puede ser el camino a un fichero .ico o a un ejecutable o dll'. La última llamada al método Save es muy importante, pues es la que hace que el enlace se haga persistente (i.e. se escriba en el disco)

A continuación les muestro una función que puede ser útil para manejar ambos casos.

from win32com.client import Dispatch
import os.path
 
def createShortcut(path, target='', wDir=None, icon=''):
    if wDir is None :
        wDir = os.path.dirname(os.path.abspath(target))
    ext = path[-3:]
    if ext == 'url':
        shortcut = file(path, 'w')
        shortcut.write('[InternetShortcut]\n')
        shortcut.write('URL=%s' % target)
        shortcut.close()
    else:
        shell = Dispatch('WScript.Shell')
        shortcut = shell.CreateShortCut(path)
        shortcut.Targetpath = target
        shortcut.WorkingDirectory = wDir
        if icon <> '':
            shortcut.IconLocation = icon
        shortcut.save()

Creando el enlace en Archivos de programas utilizando winshell

Ya hemos visto varias variantes pero sin dudas esta resultará la más económica en cuanto a líneas de código.

import os, winshell
 
program_files = winshell.programs()
winshell.CreateShortcut (
               Path=os.path.join (program_files, 'My Shortcut.lnk'),
               Target=r'C:\Program Files\SomeCoolProgram\prog.exe')

En este caso se guardará el enlace My Shortcut.lnk en la carpeta Archivos de programas del menú de inicio del usuario actual. El camino lo devuelve winshell.programs(). La función winshell.CreateShortcut hace exactamente lo que necesitamos. Además de los argumentos mostrados en el ejemplo, también es posible utilizar los siguientes:

  • Path : el camino dónde se creará el enlace
  • Target : el fichero que se ejecutará al activar el enlace
  • Arguments : Los argumentos (i.e. línea de comandos) que recibirá la aplicación
  • StartIn? : directorio de trabajo inicial
  • Icon : ícono que se mostrará en el Explorador de Windows
  • Description : Descripción del enlace

Resolviendo los enlaces

En este caso trataremos de implementar para Windows una funcionalidad que se obtiene casi sin esfuerzo al utilizar los enlaces simbólicos de sistemas Unix. A diferencia de este último, en Windows los enlaces directos son ficheros comunes y corrientes para el sistema de archivos, pero como ya vimos para el shell representan objetos de tipo IShellLink. Esta diferencia nos obliga a poner el parche porque ya salió el hueco ;o). A continuación leeremos una lista de ficheros y, si encontramos un enlace directo, lo seguiremos para retornar el fichero de destino.

import os, sys
import glob
import pythoncom
from win32com.shell import shell, shellcon

def shortcut_target (filename):
  link = pythoncom.CoCreateInstance (
    shell.CLSID_ShellLink,    
    None,
    pythoncom.CLSCTX_INPROC_SERVER,    
    shell.IID_IShellLink
  )
  link.QueryInterface (pythoncom.IID_IPersistFile).Load (filename)
  #
  # GetPath devuelve el camino y una estructura de tipo `WIN32_FIND_DATA`
  # que se ignorará. El parámetro indica si se desea obtener el 
  # nombre corto, el UNC o el camino (a.k.a. "raw path").
  # Por alguna extraña razón la documentación indica que las 
  # constantes correspondientes se pueden combinar :-$ .
  #
  name, _ = link.GetPath (shell.SLGP_UNCPRIORITY)
  return name

def shell_glob (pattern):
  for filename in glob.glob (pattern):
    if filename.endswith (".lnk"):
      yield (filename, shortcut_target (filename))
    else:
      yield (filename, filename)

desktop = shell.SHGetSpecialFolderPath (None, shellcon.CSIDL_DESKTOP)
for filename in shell_glob (os.path.join (desktop, "*")):
  print filename

¿Se podría mejorar este ejemplo utilizando winshell?

Conclusiones

Hay múltiples variantes para utilizar Python con el fin de crear enlaces directos en Windows. La más sencilla parece ser la que utiliza la función winshell.CreateShortcut. Sin embargo, hay tela por donde cortar y níveles de complejidad para todos los gustos.

Espero que le haya sido útil este corto tutorial. Si es así, le invito a estar al tanto de los próximos artículos. Trataré de abordar temas tan útiles y recurrentes como este. Me sentiría satisfecho si logro sacarle de un apuro o darle una idea para mejorar sus scripts de Python.

miércoles, 10 de marzo de 2010

Funcionalidades de Gmail Labs que voy a extrañar

GMail Labs

Recientemente Google ha decidido graduar y descontinuar funcionalidades de GMail Labs. Finalmente han permanecido 6 y se han retirado 5 Según se plantea, la decisión de quién se queda y quién se va se ha tomado considerando la cantidad de usuarios que los utilizaban. Ahora mi pregunta es relativamente simple: ¿acaso la popularidad es el mejor medidor en este caso ?

Graduados y expulsados

Para ser más explícitos, las mejoras que quedaran en el servicio resultan ser

  • Search Autocomplete
  • Go To Label
  • Forgotten Attachment Detector
  • YouTube Previews
  • Custom Label Colors
  • Vacation Dates

Retiradas las firmas aleatorias

Por otra parte se ha decidido prescindir de los siguientes Labs

  • Muzzle
  • Email Addict
  • Location in Signature
  • Random Signature
  • Fixed Width Font

Entre estos sentiré especial nostalgia por los dos últimos . Las firmas aleatorias me resultaban muy útiles al ser un canal muy propicio para aprovechar las listas de correos y promocionar con un mínimo esfuerzo varias páginas o sucesos. Su utilidad fue más evidente después de que le agregaron el título y el enlace que ofrecía el RSS de origen.

Letras con ancho fijo

Letras con ancho variable

Por otra parte el uso de letras con ancho fijo era muy útil para personas (como yo ;o) que incluyen código fuente muy frecuentemente al enviar mensajes a listas de correo. En este caso no soy el único que siente la ya confirmada desaparición de estas herramientas. Ahora yo me pregunto, ¿es que acaso es más útil tener un jueguito de serpientes en la Bandeja de entrada? No sé pero mi impresión es que la popularidad en este caso deja mucho que desear. Como dice Leonid Mamchenkov : it sucks to be a minority .

Retiradas las firmas aleatorias

viernes, 5 de marzo de 2010

La cara oculta de Fibonacci (en Python)

Leonardo de Pisa

Este artículo puede ser muy útil para que todos aquellos que se aferran a los resultados y conclusiones teóricas pues sean más cuidadosos al analizar sus resultados. Los números de Fibonacci nos revelerán las grandes distancias que pueden existir entre la teoría y la práctica. Esta famosa sucesión, que en sus orígenes fue útil para cuantificar la reproducción de los conejos, todavía sigue sorprendiendo a los teóricos de las matemáticas y otras ramas como las ciencias de la computación. En este caso revelaremos el secreto que se esconde tras un algoritmo aparentemente simple. No hay trucos, ni engaños de ningún tipo. Continúe leyendo hasta el final y seguro que se sorprenderá. Este es el primer espacio que dedico a analizar algoritmos útiles y sus diversas implementaciones. Si le interesa este tema o cualquier otro que se trate en este blog, Usted puede suscribire para recibir los próximos artículos. Le comento que pronto mencionaré sucesos realmente polémicos y candentes. Le invito también a que siga este blog, para así recorrer juntos el camino que nos lleve a todos a la comprensión de las tecnologías actuales y sus fundamentos.

Algoritmo simple para generar la serie

Seguramente todos conocen un algoritmo sencillo y eficiente (e.g. O(n)) para calcular los números de Fibonacci. A continuación les muestro su implementación en Python :

def Fibonacci(n):
  fn = f1 = f2 = 1
  for x in xrange(2, n):
    fn = f1 + f2
    f2, f1 = f1, fn
  return fn

if __name__ == '__main__' :
  from time import time
  
  def measure(n) :
    st = time()
    Fibonacci(n)
    return time() - st
  
  for data in ((x, sum(measure(x) for _ in xrange(10)) / 10) for x in xrange(25000)):
    print "%s,%s" % data

Sencillo, ¿verdad? Es muy fácil darse cuenta de que el número de sumas que se necesitan es proporcional al valor del argumento n. Por tanto a nadie dudaría al afirmar que esta implementación es muy eficiente y del órden O(n). Pero sería bueno preguntarse : ¿es esto lo que sucede realmente cuándo se ejecuta?

El ser tiene memoria ontológica en la praxis

Verifiquemos si el tiempo de ejecución de este algoritmo es realmente lineal. En este caso deberíamos obtener valores con pequeñas desviaciones alrededor de una recta. Las variaciones pueden estar dadas por la intervención del planificador de procesos del sistema operativo, la atención a interrupciones y otros muchos factores que realmente están fuera de nuestro control y pueden variar de un momento a otro, o de una computadora a otra. Grafiquemos los tiempos de ejecución para números menores que 46. Cada valor mostrado es el promedio los tiempos reportados por el comando que aparece a continuación al realizar 10 ensayos con el mismo valor de n :

$ python work/temp/fib/fib.py > work/temp/fib/fib.csv

Tiempos de ejecución -46 valores-

¿Cuáles son los resultados? Bueno realmente no hay nada más parecido a una recta. En este momento Usted se preguntará ¿cuál es el misterio? , ¿me están tomando el pelo?, ¿esto es una broma?, ¿me están hacendo perder mi tiempo?. No se deje llevar por las apariencias. Veamos otro gráfico obtenido al repetir los ensayos con los números enteros menores que 25,000 (tomados a intervalos de 50 para que los datos no sean tan voluminosos ;o).

Tiempos de ejecución -25

¡No es posible! El incremento en este caso no es para nada lineal, sino que la curva parece una parábola. Incluso si se trata de realizar un ajuste con una función cuadrática la coincidencia se hace muy evidente. ¿Cómo es posible que se comporte con este crecimiento cuadrático (i.e. O(n2))?

Revelando el secreto

La causa fundamental por la que en este caso los resultados teóricos difieren tan significativamente de los prácticos es que en el primer caso se asumió que durante la ejecución todas las sumas se ejecutaban en un tiempo constante, pero esto no es así cuando se lleva a cabo el proceso en un ordenador real. El hecho de que para números pequeños la linealidad se mantiene, nos da una pista muy importante para buscar la raíz del problema. ¿Todavía no se les ocurre nada? Todos aquellos que mencionaron la aritmética de los números enteros grandes definitivamente acertaron.

Tiempos de ejecución -250

A medida que se van computando nuevos números de la sucesión, los valores se van haciendo tan grandes, que exceden los 32 bits (y eventualmente también los 64 bits) de la arquitectura de base. Por tal razón hay que apelar al tipo long. Claro que el lenguaje es consistente y todo esto resulta transparente para el programador. Pero, al mismo tiempo el costo para calcular cada suma se va haciendo proporcional a la longitud del número de Fibonacci previo. La adición de dos números grandes de longitud O(n) es un algoritmo lineal (i.e. O(n)).

La demostración matemática

A continuación les presento un análisis que explica la baja eficiencia del algoritmo mencionado, cuando se ejecuta en una PC real. Se considera el procesamiento adicional y solapado realizado por la librería bigint.

En cada iteración i se realiza un número de operaciones del órden O(número de dígitos de fib_N) = O(digits(fib_N)). Por tanto es necesario sumar todos estos valores para cada número (i.e. valor de i) entre 1 y n:

http://3.bp.blogspot.com/_DpPqqMKo7KA/S5Fa1euOSSI/AAAAAAAAAHY/-x4tijjOTg0/s400/f1.png

Pero, ¿cuál es el número de dígitos del enésimo número de Fibonacci? Como punto de partida tomaremos la fórmula de Binet. La misma enuncia que el enésimo número de Fibonacci puede ser expresado por calculado utilizando la fórmula siguiente :

http://4.bp.blogspot.com/_DpPqqMKo7KA/S5Fa1hbqTkI/AAAAAAAAAHg/vlyabGb-4-k/s400/f2.png

El número de dígitos de un número se puede calcular hallando la parte entera del valor log 10 (number) + 1. Por tanto la cifra que buscamos es nada más y nada menos :

http://3.bp.blogspot.com/_DpPqqMKo7KA/S5Fa1w7ofOI/AAAAAAAAAHo/JJn3URon2po/s400/f3.png

Al sumar todos los costos en los que se incurre para el valor final, se obtiene la siguiente expression:

http://3.bp.blogspot.com/_DpPqqMKo7KA/S5FbGxccmUI/AAAAAAAAAHw/BJ6PN6g89IA/s400/f4.png

Se puede observar cómo el tiempo de ejecución de este algoritmo "lineal" realmente resulta ser cuadrático, considerando que cada suma se ejecuta en un tiempo proporcional a la cantidad de dígitos de los números de Fibonacci involucrados.

Conclusiones

Los métodos y resultados teóricos son de un valor tremendo para las matemáticas y las ciencias de la computación en general. La belleza y al mismo tiempo complejidad de las demostraciones es una fuente de sorpresa. Su comprensión desarrolla nuestra capacidad de razocinio y otras habilidades que nos permitirían comprender más a fondo el mundo que nos rodea. Sin embargo, la realidad suele ser mucho más rica. Por tanto es de vital importancia comprender y validar las hipótesis antes de emitir un juicio definitivo, y aplicar los teoremas y corolarios con mucho cuidado.

Si desea participar en este recorrido que realizaré para ilustrar aspectos interesantes de varios algoritmos famosos, le invito a estar al tanto de los próximos artículos. Pero estos no son los únicos temas que se tratan aquí en el blog de Simelo. Le invito también a que siga este blog. ¡ Seguro que no se arrepentirá !