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.
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.
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
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#
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>
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í:





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í:





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:





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):





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; } } |
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.
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?
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 () |
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:
Sin mas por el momento les dejo los problemas iniciales: