Archive for the ‘Programacion’ category

SVG+Firefox me han fallado

January 8th, 2009

Recientemente me vi con la necesidad de crear una pagina web que visualizara gráficos dinámicos de acuerdo a ciertos datos recabados en tiempo real.

Debido a que ocupaba mostrar el gráfico tanto en una pantalla gigante como en dispositivos móviles pensé que la solución obvia era usar gráficos vectoriales. ¿Que tan difícil podía ser?.

Que ingenuo fui.

Innegablemente la clara solución era SVG (Scalable Vectors Graphics), sabia que me toparía con un par de problemas, principalmente con compatibilidad entre navegadores. Ninguna batalla que algún desarrollador web no haya luchado alguna vez. Un trabajo sucio pero alguien tiene que hacerlo.

IE no soporta SVG, a su vez usa un formato propietario VML (Vector Markup Language) el cual no tengo interés de aprender (ningún otro navegador lo soporta), pero afortunadamente Adobe ofrece un plugin que le da a IE la posibilidad de visualizar SVG, una pequeña molestia pero nada infranqueable.

Entre otras cosas lo que requería hacer era insertar varias instancias de una misma imagen SVG sobre otra imagen SVG base y manipularla a través de scripting para asignar su posicionamiento, mascara, etc. Pero al intentar insertar la imagen no aparecía nada.

WTF?!
Después de batallar, leer, moverle, etc. Se me ocurre insertar una imagen PNG a la vez de SVG y todo funciona correctamente. WHAT?. Resulta que Firefox solo soporta insertar imágenes rasterizadas (jpg, png) dentro de SVG, y no puedo insertar otras imágenes vectoriales dentro de imágenes vectoriales.

DAMN!
En ese instante quede aturdido, que sentido tiene usar SVG por ser escalable si no puedo insertar imágenes escalables (Ojo, es un bug de Firefox, la recomendación de SVG especifica que esto debe de ser permitido). No tenia sentido que siguiera con mi esfuerzo de implementarlo a golpe de SVG con javascript.

Por mucho que me doliera tuve que abandonar la solución que utilizaba estandares para usar formatos propietarios.

Una ves mas, Flash ha ganado la batalla.

Navidad y Compiladores

December 23rd, 2008

Compiladores

Desde hace varios años cuando aun estaba estudiando en la universidad me llamaba mucho la atención el diseño e implementación de compiladores. Lamentablemente en la universidad nunca tuve la oportunidad de implementar uno a través de mis clases de compiladores (donde curiosamente nunca llegamos a ver compiladores, solo autómatas y cosas por el estilo).

Claro que eso no es pretexto, pero jamas tuve el animo de tomar el famoso libro del dragón de los compiladores y leerlo a fondo, tan solo una ojeada bastaba para intimidar al mas duros y valientes con la notación de gramática.

expr -> expr + term | expr – term | term
term -> term * factor | term / factor | factor
factor -> digit | (expr)

Decidí dejar de procrastinar al respecto y me conseguí el libro, y lo que antes parecía brujería de la mala con un vistazo resulto ser entendible y manejable con una lectura mas profunda. Eso o eh madurado un poco. Lo mas probable es que sea un poco de ambas cosas.

Compilers: Principles, Techniques, and Tools 2nd Edition (Purple Dragon Book)

Compilers: Principles, Techniques, and Tools 2nd Edition (Purple Dragon Book)

Espero poder terminarlo y poder completar un compilador o interprete (Aun no me decido) como proyecto personal.

Navidad

Mi hermosa esposa me ha dado unos increíbles regalos de navidad, ¡gracias mi amor!

Detalles de los regalos:

  • Brisingr: La tercera parte de la trilogía (ahora parece que es saga) de Christopher Paollini, en estos momentos estoy leyendo los dos primeros libros (Eragon y Eldest) para tener fresca la tercera parte cuando inicie su lectura.

    Brisingr, tercera parte de El Legado

    Brisingr, tercera parte de El Legado

  • Guitar Hero III Legends of Rock: ¿Necesito decir mas?

    Guitar Hero III Legends of Rock

    Guitar Hero III Legends of Rock

  • Guitar Hero World Tour: Así es, versión solo guitarra, no puedo darme el lujo de una batería con niños tan curiosos =P

    Guitar Hero World Tour

    Guitar Hero World Tour

  • Trauma Center New Blood: Quede sorprendido cuando jugué Trauma Center Under the Knife en el DS de Kid hace ya mas de un año, un juego sumamente adictivo, ¡espero que la versión para Wii sea al menos tan bueno!

    Trauma Center New Blood

    Trauma Center New Blood

Gracias de nuevo amor, y ¡Feliz Navidad a Todos!

¿Como funciona el swaping con XOR?

March 6th, 2008

Los que estudiaron programación indudablemente se encontraron con el problema de swapear dos variables, es decir, intercambiar su valor, y los profesores indudablemente mostraban la resolución:

1
2
3
4
5
6
	void Swap (ref int a, ref int b) 
	{
		int swapTemporal = a;
		a = b;
		b = swapTemporal;
	}

Donde se usaba una variable temporal para no perder el valor de a cuando se le asigna el valor de b, para posteriormente asignárselo a b. Algunos tal ves se hayan encontrado la resolución alternativa, usando XOR sin variable temporal:

1
2
3
4
5
6
	void Swap (ref int a, ref int b) 
	{
		a = a ^ b;
		b = a ^ b;
		a = a ^ b;
	}

Y quedaron sorprendidos por que ciertamente funciona.

¿Pero, por que?

Empezamos definiendo rápidamente, XOR es un OR exclusivo, lo que significa que es un operador binario que nos da como resultado un 1 solamente si uno de los dos (pero no ambos) operandos es igualmente 1, es decir, la siguiente tabla de verdad:

	_________________
	| a | b | a ^ b |
	-----------------
	| 0 | 0 |   0   |
	| 0 | 1 |   1   |
	| 1 | 0 |   1   |
	| 1 | 1 |   0   |
	-----------------

Dado esto podemos definir un par de axiomas:

	a ^ a = 0
	a ^ 0 = a

es decir:

  • Si ambos operandos son iguales en un XOR el resultado es invariablemente cero
  • Si un operando es igual a cero en un XOR el resultado es invariablemente el valor del otro operando

Y estos dos axiomas son lo único que necesitamos para comprobar que el primer y segundo código son equivalentes:

a’ = a ^ b //Es a prima para evitar confundir la variable con el valor original de a

b’ = a’ ^ b
Si sutituimos el valor de a’ tenemos:
b’ = (a ^ b) ^ b
b ^ b = 0 por nuestro primer axioma, por lo que nos queda:
b’ = a ^ 0
a ^ 0 = a por nuestro segundo axioma, por lo que tenemos
b’ = a

a’ = a’ ^ b’ //Si sustituimos los valores de a’ y b’ tenemos:
a’ = (a ^ b) ^ a
a ^ a = 0 por nuestro primer axioma, por lo que nos queda:
a’ = b ^ 0
b ^ 0 = b por nuestro segundo axioma, por lo que tenemos
a’ = b

Asi, al finl de las tres operaciones a’ tiene el valor original de b, y b’ el valor original de a.

Q.E.D. \o/

Como ven la demostración es trivial y seguramente un overkill, pero te puede matar 5 minutos de aburrimiento :p. Nos vemos en la siguiente entrega cuando demuestre que el negro es blanco, claro, al menos que muera antes en un crucero de zebras.

Aprendiendo Regex – El imperio contrataca.

February 21st, 2008

Gnoblis posteo hacerca de un pequeño programa que hizo para convertir bbcode a html en su web: http://gnoblis.gamersla.net/?p=67. El codigo esta aca http://gamersla.net/gnoblis/descargas/CCast.cs

Su solucion si bien funciona, no es de lo mas elegante. El problema es facilmente resuelto con expresiones regulares, y se lo hizo saber en un comentario en su post.

Claro, los que me conocen sabran que no es suficiente haberle dicho como se podria resolver mejor, ¡hace falta hacerlo uno mismo!

Asi que como demostracion del poder de las expresiones regulares y que no soy un hablador les muestro el codigo:

Nota, el programa no lo probe a excepcion de las expreciones regulares, por lo que pueden encontrarse con sorpresas ;)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
 
class Program
{
 
    public static void Main(string[] args)
    {
 
        StreamReader inputReader;
        StreamWriter outputWriter;
        string actualLine;
        StringBuilder inputFileContent = new StringBuilder ();
 
        foreach (string actualFile in args) //Agrego la capacidad de convertir varios archivos a la ves
        {
            if (!File.Exists(actualFile))
            {
                Console.WriteLine("File not found, skipped: {0}", actualFile);
                continue;                   //Ignoramos el archivo, pero seguimos con los demas \o/
            }
 
            inputReader = new StreamReader(File.OpenRead(actualFile));
 
 
            inputFileContent.Remove(0, inputFileContent.Length);
            while ((actualLine = inputReader.ReadLine()) != null)
                inputFileContent.AppendLine(string.Format("{0}{1}", actualLine, "<br />"));
 
            inputReader.Close ();
 
            if (inputFileContent.Length == 0)
            {
                Console.WriteLine("Empty file, skipped: {0}", actualFile);
                continue;
            }
 
            string bbcodeData = inputFileContent.ToString();
 
            //Quitamos todos los espacios antes y despues de un igual, no solo uno
            bbcodeData = Regex.Replace(bbcodeData, @"\ {0,}=\ {0,}", "=", RegexOptions.IgnoreCase | 
                                                                          RegexOptions.Multiline);
 
            //Convertimos [b], [i], [u], [s] y sus respectivos cierres
            bbcodeData = Regex.Replace(bbcodeData, @"\[(?<tag>\/{0,1}[b|i|u|s])\]", @"<${tag}>", 
                RegexOptions.IgnoreCase | RegexOptions.Multiline);
 
            //imagenes
            bbcodeData = Regex.Replace(bbcodeData, @"\[img\](?<url>.*?)\[\/img\]",
                "<img src=\"${url}\" />", RegexOptions.IgnoreCase | RegexOptions.Multiline);
 
            //Links
            bbcodeData = Regex.Replace(bbcodeData, @"\[url=(?<url>.*?)\](?<data>.*?)\[/url\]",
                "<a href=\"${url}\">${data}</a>", RegexOptions.IgnoreCase | RegexOptions.Multiline);
 
            //Colores
            bbcodeData = Regex.Replace(bbcodeData, @"\[color=(?<color>.*?)\](?<data>.*?)\[/color\]", 
                "<font color=\"${color}\">${data}</font>", RegexOptions.IgnoreCase | 
                                                           RegexOptions.Multiline);
 
            outputWriter = new StreamWriter (File.Create(actualFile + ".html"));
 
            outputWriter.Write(bbcodeData);
 
            outputWriter.Close();
        }
    }
}

¿No sabes XPath? ¡Aprende!

December 11th, 2007

Otra de las herramientas de un desarrollador que se vuelven completamente imprescindibles una ves que las conoces es XPath.

XPath es un estándar del W3C para realizar querys a documentos Xml, haciendo fácil filtrar los nodos de un documento de acuerdo a la estructura y atributos de los nodos.

Si no usamos XPath, tendríamos que iterar a través de todos los nodos de un documento Xml para obtener la información que buscamos.

Para no hacérsela mas larga voy a dejar que el código hable por si mismo.

Imaginen que tienen el siguiente Xml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="utf-8" ?> 
<Sucursales>
	<Sucursal name="Matriz">
		<Articulo name="Monitor" precio="1500"/>
		<Articulo name="Impresora" precio="400"/>
	</Sucursal>
	<Sucursal name="Mayoreo">
		<Articulo name="Monitor" precio="1600"/>
		<Articulo name="Impresora" precio="500"/>
	</Sucursal>
	<Sucursal name="Menudeo">
		<Articulo name="Monitor" precio="1800"/>
		<Articulo name="Impresora" precio="700"/>
	</Sucursal>
</Sucursales>

Y ustedes quieren saber tres cosas:

  1. ¿Que artículos con que precios se encuentran en la sucursal Matriz?
  2. ¿Que sucursales tienen monitores?
  3. ¿Que precio tiene una impresora en la sucursal menudeo?

Sin XPath estas tres simples preguntas se convierte en esta monstruosidad:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
using System;
using System.Xml;
using System.Collections.Generic;
 
class Program
{
    public static void Main()
    {
        XmlDocument document = new XmlDocument();
        document.Load("Test.xml");
        XmlNode sucursales = document.ChildNodes[1];
 
        //Obtener los articulos de la sucursal matriz
        XmlNodeList articulosMatriz;
        foreach (XmlNode sucursal in sucursales.ChildNodes)
            if (sucursal.Name == "Sucursal")
                if (sucursal.Attributes["name"].Value == "Menudeo")
                    articulosMatriz = sucursal.ChildNodes;
 
        //Obtener todas las sucursales que tienen monitores
        List<XmlNode> sucursalesConMonitor = new List<XmlNode>();
        foreach (XmlNode sucursal in sucursales.ChildNodes)
        {
            if (sucursal.Name == "Sucursal")
            {
                foreach (XmlNode articulo in sucursal.ChildNodes)
                {
                    if (articulo.Name == "Articulo")
                    {
                        if (articulo.Attributes["name"].Value == "Monitor")
                        {
                            sucursalesConMonitor.Add(sucursal);
                            break; //Siguiente sucursal
                        }
                    }
                }
            }
        }
 
        //Obtener el precio de una impresora en la sucursal menudeo
        XmlNode impresoraSucursalMenudeo = null;
        foreach (XmlNode sucursal in sucursales.ChildNodes)
        {
            if (sucursal.Name == "Sucursal")
            {
                if (sucursal.Attributes["name"].Value == "Menudeo")
                {
                    foreach (XmlNode articulo in sucursal.ChildNodes)
                    {
                        if (articulo.Name == "Articulo")
                        {
                            if (articulo.Attributes["name"].Value == "Impresora")
                            {
                                impresoraSucursalMenudeo = articulo;
                                break; 
                            }
                        }
                    }
 
                    if (impresoraSucursalMenudeo != null)
                        break; //Se encontro el articulo, terminamos!
                }
            }
        }
    }
}

¡HORRIBLE!

Claro que si hicieron la tarea y saben XPath, ¡las cosas cambian dramáticamente!:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System;
using System.Xml;
 
class Program
{
    public static void Main()
    {
        string xPathQuery;
        XmlDocument document = new XmlDocument();
        document.Load("Test.xml");
 
        //Obtener los articulos de la sucursal matriz
        xPathQuery = @"/Sucursales/Sucursal[@name='Matriz']/Articulo";
        XmlNodeList nodes = document.SelectNodes(xPathQuery);
 
        //Obtener todas las sucursales que tienen monitores
        xPathQuery = @"/Sucursales/Sucursal[./Articulo[@name='Monitor']]";
        nodes = document.SelectNodes(xPathQuery);
 
        //Obtener el precio de una impresora en la sucursal menudeo
        xPathQuery = @"/Sucursales/Sucursal[@name='Menudeo']/Articulo[@name='Impresora']";
        XmlNode node = document.SelectSingleNode(xPathQuery);
    }
}

SIMPLE, SENCILLO Y HERMOSO

Si no saben nada al respecto lean por lo menos este tutorial de w3schools, no se arrepentirán.

P.S XPath es un estándar, por lo que no depende de .NET, puedes usarlo en Java, Python o lo que te de tu gana

¿No sabes Regex? ¡Aprende!

December 7th, 2007

Algo de lo que me e dado cuenta cuando e dado platicas/talleres/cursos es que la gran mayoría de los desarrolladores, al menos de la región, no tienen ni puta idea acerca de que demonios son las expresiones regulares (Regex para los amigos).

Muchos recuerdan haber escuchado algo al respecto en su clase de autómatas en la universidad, pero como a todos, les paso de noche :P .

Es difícil de entender como la gente puede pasarse sentado en su vida profesional sin saber Regex, escribiendo cientos de lineas de código resolviendo problemas que con unos cuantos caracteres de Regex queda solucionado.

Si aun no sabes Regex, ¡deja de leer esto inmediatamente y ponte a buscar información al respecto!

Para los escépticos, un pequeño ejemplo:

Imagina que quieres validar que un teléfono siga el formato (900) 9-00-00-00, la forma común de hacerlo seria algo cómo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    bool isValidPhoneNumber(string input)
    {
        //Validate (900) 9-00-00-00
        if (input.Length != 16)
            return false;
        if (!input.StartsWith("("))
            return false;
        if (input[4] != ')')
            return false;
        int number;
        if (!int.TryParse(input.Substring(1, 3), out number))
            return false;
        if (input[1] == '0' || !char.IsNumber(input[1]))
            return false;
        if (input[5] != ' ')
            return false;
        string[] numbers = input.Substring(6, 10).Split ('-');
        if (numbers.Length != 4)
            return false;
        foreach (string subpart in numbers)
            if (!int.TryParse(subpart, out number))
                return false;
        if (numbers[0][0] == '0')
            return false;
        return true;
    }

Es tedioso de hacer, resulta fácil dejar errores en el, sin mencionar que es completamente horrible y resulta difícil de entender, y precisamente este es uno de los momentos en que Regex es útil:

1
2
3
4
5
6
7
8
   bool isValidPhoneNumber(string input)
    {
        //Validate (900) 9-00-00-00
        string expression = @"^\([1-9]\d{2}\)\ [1-9](\-\d{2}){3}$";
        System.Text.RegularExpressions.Regex regex = 
            new System.Text.RegularExpressions.Regex(expression);
        return regex.IsMatch(input);
    }

Si bien la sintaxis puede resultar confusa al inicio, basta un poco de practica para acostumbrarse a ella y puede llegar a ahorrarte toneladas de trabajo, especialmente si la usas para buscar patrones de texto en ves de solamente validación.

Confíen en mi, si no las conocen, ¡Aprendan!.

P.S: No me hago responsable de cualquier mal uso que puedan hacer de ellas ;)