Posts Tagged ‘Programacion’

Taller jQuery SISEI 2011

November 30th, 2011

Hace un par de semanas realice un taller en el SISEI 2011 (No me pregunten que significa, algo de simposio internacional de tortugas marinas o algo así), les dejo el enlace hacia el material con el que se trabajo.

Saludos.

http://albertein.com.mx/talks/jqueryworkshop/index.html

Desconferencia Barcamp V2

November 14th, 2011

A los asistentes a mi desconferencia en el Barcamp V2 sobre funciones en javascript y otras hierbas les dejo el ejemplo final, implementando (badly) una clase que se comporta de manera similar a Linq (Tan solo implemento 3 métodos, select, where y groupBy). Una diferencia primordial es que en esta versión de javascript los métodos corren inmediatamente y no trabajan sobre Enumerables o similares como en .NET.

Para poder probar el código se debe de correr sobre Firefox, debido a que por pereza en el ejemplo del uso de groupBy llamo a toSource para mostrar el resultado y este método esta disponible en chrome.

Saludos.

function Linq(collection) {
 
    var items = collection;
 
    var iterate = function(operation) {
    	for (var i = 0; i < items.length; i++) {
    		operation(items[i], i);
    	}
    };
 
    this.reduce = function(init, reductor) {
    	var results = init;
    	iterate(function(item, index){
    		results = reductor(results, item);
    	});
    	return results;
    }
 
    this.select = function(selector) {
    	var results = new Array();
    	iterate(function(item, index) {
    		results[index] = selector(item);
    	});
    	return new Linq(results);
    };
 
    this.where = function(filter) {
    	var results = new Array();
    	var j = 0;
    	iterate(function(item, index) {
    		if (filter(item))
    			results[j++] = item;
    	});
 
    	return new Linq(results);
    }
 
    this.groupBy = function(fieldSelector) {
    	var dict = { };
    	iterate(function(item, index) {
    		field = fieldSelector(item);
    		if (dict[field] === undefined) 
    			dict[field] = {
    				count: 0,
    				items: new Array()
    			};
		dict[field].items[dict[field].count] = item;
		dict[field].count++;
 
    	});
 
    	var i = 0;
    	var results = new Array();
    	for (var item in dict)
    		results[i++] = {
    			key: item,
    			items: dict[item].items
    		};
    	return new Linq(results);
    };
 
    this.toArray = function() { return collection };
    this.toString = function() {
    	return this.reduce("", function(base, item) {
    		return base + item + ",";
    	});
    };
}
 
function Dude(name, age) {
	this.name = name;
	this.age = age;
}
 
alert(new Linq([5, 6, 7])
	.select(function(i) { return i * 3})
	.where(function(i) { return i % 2 == 0 }).toString()); //Shows 18
 
 
var dudes = [
	new Dude("A", 5),
	new Dude("B", 5),
	new Dude("C", 6),
	new Dude("D", 7),
	new Dude("E", 8),
	new Dude("F", 6)
];	
var t = new Linq(dudes).groupBy(function (p) { return p.age }).toArray();
for (var i = 0; i < t.length; i++)
	alert(t[i].key + " - " + t[i].items.toSource());

Desarrollando Webs Dinamicas

April 26th, 2010

Aquí les dejo la liga al material de lo que se vio en el demotaller “Desarrollando Webs Dinámicas (con HTML y jQuery)”. Y aprovecho parea dejarles liga a las fotos del FLISol.

Saludos!.

Desarrollando Webs Dinámicas (con HTML y jQuery)
Fotos del FLISol Sinaloa 2010

Hágalo usted mismo: Integrando Twitter @Anywhere en WordPress, ¡a la mala!

April 17th, 2010

Hace algunos días Twitter presento su nueva API @Anywhere, y justo ayer @Robsainz me pidió que lo implementara en su Web.

Fruto de eso les tengo esta mini guía para implementar @Anywhere en su blog de WordPress, aun que fácilmente puede ser adaptado para demás sitios. Cabe señalar que esta es una manera “rudimentaria” de lograrlo con mucho espíritu “hágalo usted mismo”, modificando tu Template actual. La mejor forma de hacerlo sería con un plugin, pero debido a lo reciente de la API de momento no se encuentra ninguno estable y configurable disponible.

Primero se debe de registrar su aplicación (o en este caso web) en http://dev.twitter.com/apps/new para optener su API key. Despues de hacerlo no olviden seguir los pasos que están en : http://groups.google.com/group/twitter-development-talk/browse_thread/thread/5c96366e2362fe85#

  1. Go to: http://twitter.com/oauth
  2. Click on your application
  3. On the “Application Details” page click the “Edit Application
    Settings” button
  4. On the settings page for your application, scroll down to the item
    labeled “Default Access type”
  5. Change the “Default Access type” to “Read & Write”

Después necesitan editar el archivo header.php del tema que estén usando, justo sobre el tag </head> deben de poner el siguiente código (reemplazando AQUIVATUAPIKEY por tu api key Y AQUIVATUTWITTERUSER por tu usuario de twitter):

<script src="http://platform.twitter.com/anywhere.js?id=AQUIVATUAPIKEY&v=1">
</script>
<script type="text/javascript">
    jQuery(document).ready (function () {
        twttr.anywhere(function (twitter) {
            twitter.hovercards();
            twitter("#twitt-box").tweetBox ( {
                counter: true,
                height: 100,
                width: 250,
                label: "Twittea desde aqui",
                defaultContent: "Estoy probando @Anywhere en mi blog"
            });
            twitter("#follow-me").followButton ("AQUIVATUTWITTERUSER");
        });
    })
</script>

Y después solo falta que crees un Widget que contenga lo siguiente:

<div id="follow-me"></div>
<div id="twitt-box"></div>

Hagalo usted mismo: Efecto marquesina con Javascript

May 30th, 2009

Recientemente m313n45 me pidio ayuda para hacer un efecto de marquesina con unas imágenes y al dar click sobre alguna de ellas se viera la versión completa, todo esto sin usar flash.

Lo realice obviamente con Javascript + JQuery y a continuacion veremos paso a paso como lograrlo.

Tambien pueden ver el ejemplo completo aquí

Las imágenes para las marquesina son 6, iniciamos con el markup de las imágenes.

1
2
3
4
5
6
7
8
9
10
<div id="container">
	<img src="01.png" alt="1"/>
	<img src="02.png" alt="2"/>
	<img src="03.png" alt="3"/>
	<img src="04.png" alt="4"/>
	<img src="05.png" alt="5"/>
	<img src="06.png" alt="6"/>
</div>
<div id="viewport">
</div>

Además ocupamos darle estilo:

1
2
3
4
5
6
7
8
9
10
11
12
13
#container
{
	overflow: hidden;
	width: 400px;
	height: 64px;
	border-style: solid;
}
#container img
{
	position: relative;
	width: 60px;
	height: 64px;	
}

overflow: hidden; hace que las imágenes que no quepan en el contenedor esten ocultas en ves de causar scrolling o un efecto similar, además hacemos las imágenes mas pequeñas y asignamos su posicion como relativa, lo cual sera útil a realizar la animación.

Hasta el momento esto se ve así:

123456

Notece que una de las imágenes se encuentra oculta de momento, debido a que no se alcanza a mostrar en el contenedor.

Después iniciamos con la animacion, requerimos a JQuery para facilitarnos las cosas, tendrán que agregar la referencia a la libreria en su header además de agregar el código de animación:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var deltaX = 5;
var deltaT = 42;	
 
$(document).ready (function ()
{
	setTimeout("animate()", deltaT); //start animation
});
 
function animate ()
{
	var left = parseInt ($("#container img").css("left"));
	left -= deltaX;
 
	$("#container img").css("left", left + "px");
 
	setTimeout ("animate()", deltaT); //continue animation
}

Donde deltaT define cada cuantos milisegundos ocurrira la animacion y deltaX indica el desplazamiento cada intervalo de deltaT milisegundos. La animación la realizamos modificando la propiedad left del css. Ahora esto se ve así:

123456

Pero para el momento en que ustedes lleguen a leerlo todas las imágenes habrán desaparecido hacia la izquierda, así que recarguen la pagina por favor y bajen rápidamente hasta este punto para ver la animación.

Eso ocurre por que ocupamos hacer que la marquesina sea giratoria, para lograr el efecto debemos de quitar la primer imagen cuando esta ya no sea visible y ponerla después de la ultima imagen. La primer imagen no es visible cuando su atributo css left tenga un valor de -LongitudImagen, en este caso, -60px.

Como quitaremos la imagen, ocupamos volver a ajustar el desplazamiento a la izquierda aumentando el atributo css left con la longitud de la imagen que quitamos, es decir 60px. El script queda entonces:

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
var deltaX = 5;
var deltaT = 42;	
var imageWidth = 60;
 
$(document).ready (function ()
{
	setTimeout("animate()", deltaT); //start animation
});
 
function animate ()
{
	var left = parseInt ($("#container img").css("left"));
	left -= deltaX;
 
	if (left <= -imageWidth) //if first image is no longer visible
	{
		left += imageWidth;
		$("#container img:first")
                	.remove ()
                	.insertAfter("#container img:last");
	}
 
	$("#container img").css("left", left + "px");
 
	setTimeout ("animate()", deltaT); //continue animation
}

Y ya podemos ver la animación circular:

123456

Por ultimo requerimos que al dar click en una imagen la mostremos en su tamaño original, para dar el efecto de vinculo debemos de cambiar el css de las imágenes para que aparezca la “manita” cuando pongamos el puntero sobre la imagen, el css queda entonces:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#container
{
	overflow: hidden;
	width: 400px;
	height: 64px;
	border-style: solid;
}
#container img
{
	position: relative;
	width: 60px;
	height: 64px;	
	cursor: pointer;
}

Solo nos falta el script, pero debemos de tener cuidado, por que cuando quitamos la imagen para ponerla al final de la lista perdemos la asociación del evento y tenemos que volverla agregar,por lo que el script final queda:

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
var deltaX = 5;
var deltaT = 42;	
var imageWidth = 60;
 
$(document).ready (function ()
{
	$("#container img").click (changeViewportImage);
	setTimeout("animate()", deltaT); //start animation
});
 
function changeViewportImage ()
{
	$("#viewport img").remove ();
	$("#viewport").append ($(this).clone ());
}
 
function animate ()
{
	var left = parseInt ($("#container img").css("left"));
	left -= deltaX;
 
	if (left <= -imageWidth) //if first image is no longer visible
	{
		left += imageWidth;
		$("#container img:first")
		    .remove ()
		    .insertAfter("#container img:last")
		    .click (changeViewportImage);
	}
 
	$("#container img").css("left", left + "px");
 
	setTimeout ("animate()", deltaT); //continue animation
}

Y queda finalmente así (recuerden dar click sobre alguna imagen):

123456

Tambien pueden ver el ejemplo completo aquí

Evaluando expresiones aritméticas con C# (Shunting-yard)

May 26th, 2009

Fire_Tony tenia que escribir un programa que parseara una expresión aritmética infija (3*1/(2-6)), la convirtiera en un arbol binario, para después mostrar la expresión en notación polaca inversa (sufija) y evaluara el resultado.

El pobre no pudo terminar el problema a tiempo, y como me llamo la atención y no tenia mucho que hacer me ofrecí a resolver el problema para que revisara el código y no se viera en ese dilema la próxima ocacion.

El programa por sencillez solo evalúa numeros de 0 al 9 y reconoce los operadores *,+,- y / pero puede ser expandido fácilmente para mas casos.

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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
class SixPackJoy
{
    public static void Main(string[] args)
    {
        Console.WriteLine ("Expression: ");
        var expression = Console.ReadLine().Replace(" ", "");
        var output = new Stack<BinaryNode> ();
        var stack = new Stack<Operator> ();
        var index = -1;
 
        foreach (var token in expression)
        {
            index++;
            if ("0123456789".Contains(token)) //numeric token
            {
                output.Push(new BinaryNode (token));
            }
            else if ("*/+-".Contains(token)) //operator token
            {
                var op = new Operator (token);
 
                var lastOperator = stack.Count > 0 ? stack.Peek() : null;
                if (lastOperator != null && 
                    !lastOperator.IsParenthesis && 
                    op.ComparePrecedence(stack.Peek()) <= 0)
                {
                    var node = new BinaryNode(stack.Pop().Value);
                    if (output.Count < 2)
                    {
                        Console.WriteLine("Insuficcient operator argumets, process halted");
                        return;
                    }
                    node.RightChild = output.Pop();
                    node.LeftChild = output.Pop();
                    output.Push(node);
                }
                stack.Push(op);
            }
            else if (token == '(')
            {
                stack.Push(new Operator(token));
            }
            else if (token == ')')
            {
                while (true)
                {
                    if (stack.Count == 0)
                    {
                        Console.WriteLine("Parenthesis missmatch at {0}, process halted", index);
                        return;
                    }
                    var op = stack.Pop();
                    if (op.IsParenthesis)
                        break;
 
                    if (output.Count < 2)
                    {
                        Console.WriteLine ("Insuficcient operator argumets, process halted");
                        return;
                    }
                    var node = new BinaryNode (op.Value);
                    node.RightChild = output.Pop ();
                    node.LeftChild = output.Pop ();
                    output.Push (node);
                }
            }
            else
            {
                Console.WriteLine("Invalid token '{0}' at {1}, process halted", token, index);
                return;
            }
        }
 
        while (stack.Count != 0)
        {
            var op = stack.Pop();
            if (op.IsParenthesis)
            {
                Console.WriteLine ("Parenthesis missmatch, process halted");
                return;
            }
            if (output.Count < 2)
            {
                Console.WriteLine("Insuficcient operator argumets, process halted");
                return;
            }
            var node = new BinaryNode(op.Value);
            node.RightChild = output.Pop();
            node.LeftChild = output.Pop();
            output.Push(node);
        }
 
 
        if (output.Count != 1)
        {
            Console.WriteLine("Invalid expression, process halted");
            return;
        }
 
        var ast = output.Pop();
        Console.WriteLine("{0} = {1}", ast.GetSufixNotation (), ast.Evaluate());
 
    }
}
 
class BinaryNode
{
    public BinaryNode LeftChild;
    public BinaryNode RightChild;
 
    public BinaryNode(char value)
    {
        Value = value;
    }
 
    public char Value;
 
    public double Evaluate()
    {
        if (LeftChild == null)
            return double.Parse(Value.ToString ());
 
        var operations = new Dictionary<char, Func<double, double, double>> ()
          {
             {'*', (x, y) => x * y},
             {'/', (x, y) => x / y},
             {'+', (x, y) => x + y},
             {'-', (x, y) => x - y},
          };
 
        return operations[Value](LeftChild.Evaluate(), RightChild.Evaluate());
    }
 
    public string GetSufixNotation()
    {
        if (LeftChild == null)
            return Value.ToString ();
 
        return string.Format("{0} {1} {2}",
            LeftChild.GetSufixNotation(),
            RightChild.GetSufixNotation(),
            Value);
    }
}
 
 
class Operator
{
 
    public char Value;
 
    public Operator(char value)
    {
        Value = value;
    }
 
    public bool IsParenthesis
    {
        get
        {
            return Value == '(';
        }
    }
 
    public int ComparePrecedence(Operator o)
    {
        if ("+-".Contains(Value))
        {
            if ("+-".Contains(o.Value))
                return 0;
            else
                return -1;
        }
        else if ("+-".Contains(o.Value))
            return 1;
        else
            return 0;
    }
}

Regex replace

April 6th, 2009

Ya e hablado aquí y aquí sobre las expresiones regulares, pero nunca se tenie demasiadas de ellas.

Trabajando con un pequeño proyecto personal requería buscar dentro de un texto ocurrencias como @Nombre y #Nombre y convertirlas en un link, la solución es obvia y sencilla con expresiones regulares:

Regex.Replace("this is an example @AlbertEin", 
                    "(?<type>[@#])(?<nick>\\w{1,}[^ ])", 
                    "<a href=\"http://twitter.com/${nick}\">${type}${nick}</a>");

Esto remplaza “this is an example @AlbertEin” por “this is an example @AlbertEin“.

La expresión regular:

(?<type>[@#])(?<nick>\\w{1,}[^ ])

significa: captura bajo el nombre “type” la ocurrencia de texto que inicie con @ ó #, despues captura bajo el nombre “nick” el texto que siga que contenga al menos un carácter de texto hasta que te encuentres con un espacio en blanco.

Espero que después de tres advertencias ahora si vayan y aprendan de esta útil herramienta para la manipulación de texto.

Parsing de HTML con HtmlAgilityPack

February 5th, 2009

La web esta llena de información, todo tipo de información, desde el vídeo divertido mas irrelevante hasta noticias o documentos de verdadera importancia. Hay un mundo de información a la cual tu computadora esta unida por el cordón umbilical de tu cable de red, dispuesta a ser accesada y mostrada en tu pantalla a la mas mínima orden tuya.

Pero tiene un problema.

Toda esta valiosa información se encuentra ofuscada en HTML, un lenguaje el cual a sido seriamente abusado durante el transcurso de los años, debido a que su especificación indica que los navegadores deben hacer lo mejor posible para corregir errores en el formateo de un documento, por lo que los usuarios terminaron en volverse descuidados, olvidando una etiqueta de cierre aquí y halla, al fin y al cabos el resultado es el mismo, ¿no?, los navegadores hacen todo lo posible por mostrar incluso los documentos mas mal formados.

Eso hace que hacer un programa para extraer información de un documento HTML pueda llegar a ser un poco complicado en ocasiones.

HtmlAgilityPack to the rescue!

HtmlAgilityPack es una librería para .NET que nos brinda un parser de HTML que nos permite leer, escribir y manipular documentos HTML y soporta Xpath, el cual discutí hace tiempo. Y lo que lo hace realmente especial es que es increíblemente permisivo, soportando los documentos mas perversamente malformados que te puedes encontrar en tu navegación día a día.

HtmlAgilityPack combinado con Firebug nos permite extraer hasta la ultima gota de información requerida, y para no hacérselas larga pondré un par de ejemplos en el resto del post.

Quiero obtener la lista de títulos del blog del AlbertEin

1
2
3
4
5
6
7
8
9
10
11
static void Main(string[] args)
{
    var client = new System.Net.WebClient();
    client.Encoding = System.Text.Encoding.UTF8;
    var document = new HtmlAgilityPack.HtmlDocument();
    document.LoadHtml(client.DownloadString("http://albertein.gamersla.net"));
 
    foreach (HtmlAgilityPack.HtmlNode node in 
        document.DocumentNode.SelectNodes("//a[@class='title']"))
            Console.WriteLine(node.InnerHtml);
}

Quiero obtener la lista de palabras listada en una web de un diccionario

1
2
3
4
5
6
7
8
9
10
11
12
static void Main(string[] args)
{
    var url = "http://diccionario.babylon.com/Humanidades/Mitolog%C3%ADa/A/1/";
    var client = new System.Net.WebClient();
    client.Encoding = System.Text.Encoding.UTF8;
    var document = new HtmlAgilityPack.HtmlDocument();
    document.LoadHtml(client.DownloadString(url));
 
    foreach (HtmlAgilityPack.HtmlNode node in
        document.DocumentNode.SelectNodes("//a[@class='words']"))
            Console.WriteLine(node.InnerHtml);
}

Quiero bajar todos los malditos comics de Penny Arcade

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
static void Main(string[] args)
{
    var url = "http://www.penny-arcade.com/comic/1998/11/18/";
    var baseUrl = "http://www.penny-arcade.com";
    bool lastStrip = false;
    var client = new System.Net.WebClient();
    client.Encoding = System.Text.Encoding.UTF8;
 
    while (!lastStrip)
    {
        var document = new HtmlAgilityPack.HtmlDocument();
        document.LoadHtml(client.DownloadString(url));
 
        var imageQuery = "/html/body/div[2]/div[3]/div/div[2]/img";
        var nextButtonQuery = "/html/body/div[2]/div[3]/div/div[3]/a[4]";
 
        var imageUrl = document.DocumentNode.
            SelectSingleNode(imageQuery).Attributes["src"].Value;
 
        //Aquí iria el codigo para descargar la imagen que se encuentra en
        //baseUrl + imageUrl
 
        //Obtenemos la dirección del próximo comic
 
        url = baseUrl + document.DocumentNode.
            SelectSingleNode (nextButtonQuery).Attributes ["href"].Value; 
 
        lastStrip = url == baseUrl; // Llegamos al ultimo comic?
    }
}

Podría seguir así todo el día, pero supongo que con eso es suficiente para que capten la idea.

¿Y tu, como lo has usado?

Mi primera vez (python)

January 31st, 2009

Hace tiempo que habia visto a python, me llamo la atención por sus características poco usuales, como que los espacios tenga un valor semántico a diferencia de uno puramente visual, donde la identación en el código crea los bloques de codigos que en otros lenguajes se crean con “begin y end”, “{ y }”, etc.

Desgraciadamente no habia tenido oportunidad de usarlo para un requerimiento real de mi trabajo, pero eso cambio el día de hoy.

Hoy fue mi primera vez.

El siguiente script fue mi primero con python, toma dos parámetros de la linea de comando, el primero es un archivo con una lista de nombres de usuarios, como el que se obtiene con el siguiente comando:

1
awk -F : '{print $1}' /etc/passwd > userDatabase.txt

El segundo parámetro es un archivo que contiene una lista de usuario{Tabulador}password como por ejemplo:

1
2
3
panchito	pancho123
albertein	paparazi
dariamox	password

Lo que hace es imprimir el usuario y contraseña (separado por “:”) del segundo archivo cuando el usuario se encuentre listado en el primer archivo. Un formato idóneo para usarlo junto con chpasswd (utilería que cambia las contraseñas del sistema en modo batch).

1
python passwordFormatter.py systemUsers passwordDatabase | chpasswd

El dichoso script, es este:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import sys
 
file = open (sys.argv [1], 'r')
userList = file.read ().split ('\n')
file.close ()
 
file = open (sys.argv [2], 'r')
 
for line in file:
       userData = line.split ('\t')
       username = userData [0]
       password = userData [1]
       if username in userList:
               print username + ':' + password,
 
file.close ()

Problemas de Programación I

January 12th, 2009

Aunque pocas personas leen este blog, y mas pocas aun saben de programación voy a experimentar poner pequeños problemas de programación para que los resuelvan en los comentarios y así ganen la infame gloria en el dulce cáliz de la victoria.

Las respuestas pueden ser en cualquier lenguaje o pseudocodigo a excepción de los casos donde se indiquen, tratare de empezar con problemas sencillos y tal ves aumentar la dificultad en el futuro. Algunos problemas incluso podrían ser resueltos por personas que no sepan programar si describen los procesos paso a paso en español.

Los problemas tendrán dos características:

  1. Las respuestas requerirán de ingenio o pensar en otra forma de resolver problemas comunes
  2. En algunas ocasiones se requerirá que se preste especial atención en la formulación del problema, una palabra puede cambiar muchas cosas.

Sin mas por el momento les dejo los problemas iniciales:

  1. Define una función para multiplicación de dos números enteros mayores a cero sin utilizar el operador * (multiplicación)
  2. Define la función anterior sin utilizar ciclos dentro de la función (No for, while, do until, goto, etc.)
  3. Define una función similar a la anterior pero que realice divisiones (resultados enteros)