Me lo contaron y lo olvidé, lo leí y lo entendí, lo hice y lo aprendí.





viernes, 22 de marzo de 2013

Crear PDF con PHP [Dompdf]

Dompdf es una librería de PHP que permite tomar una página HTML y renderizarla (convertirla) a un PDF; aunque realmente no se crea un archivo PDF pero para el usuario de la página web se verá un auténtico archivo de éste tipo y podrá imprimirlo, guardarlo y tratarlo en su totalidad como uno.

Su uso es muy sencillo, pondré un sencillo ejemplo de su uso básico:

Tenemos una página HTML con éste código:


<html>
<head>
<title>Archivo pdf</title>
</head>
<body>
<center>
<h1>P&aacute;gina renderizada a PDF</h1>
</center>
</body>
</html>


La página se llama "pagina1.html". (Se ve así: http://unrinconenlaweb.webcindario.com/programas/pdf/pagina1.html)
Ahora, para renderizarla a un PDF es necesario crear una página php con el siguiente código:


<?php
require_once("dompdf/dompdf_config.inc.php"); //Aquí se incluye la librería php del Dompdf
$file = file_get_contents("pagina1.html"); //Se "extrae" la página que se convertirá a PDF

$dompdf = new DOMPDF(); //Se crea un objeto del tipo DOMPDF
    $dompdf->load_html($file); //Se le "carga" la página que convertiremos
    $dompdf->render(); //Se manda a llamar el método para renderizar
        
    header('Content-type: application/pdf'); //Ésta es simplemente la cabecera para que el navegador interprete todo como un PDF
    echo $dompdf->output(); //Y con ésto se manda a imprimir el contenido del pdf
?>


El resultado será éste: http://unrinconenlaweb.webcindario.com/programas/pdf/ejemplo1.php
Como se nota, hay que abrir la página .php en lugar de la .html

Ahora, en más de la mitad de las ocasiones se requerirá que la información a mostrar en el PDF varíe, como puede ser una fecha, el nombre del usuario o cualquier otro dato.
Para eso, hay que poner en la página .html palabras "claves" que después serán reemplazadas por los valores dinámicos a la hora de renderizar.
Es éste ejemplo voy a poner 3 valores numéricos aleatorios en el PDF.
Para empezar, aquí está la página html (Se llama "pagina2.html")

<html>
<head>
<title>Archivo pdf</title>
</head>
<body>
<center>
<h1>P&aacute;gina renderizada a PDF</h1>
</center>
<br />
<br />
<li><b>Dato 1:</b> {#dato1}</li>
<li><b>Dato 2:</b> {#dato2}</li>
<li><b>Dato 3:</b> {#dato3}</li>
</body>
</html>


Se ve así: http://unrinconenlaweb.webcindario.com/programas/pdf/pagina2.html
Como se puede notar, están escritas "{#dato1}" "{#dato2}" y "{#dato3}" que en éste caso servirán de "palabras clave" que reemplazaré por número generados aleatoriamente.
La página php contiene lo siguiente:


<?php
require_once("dompdf/dompdf_config.inc.php"); //Se incluye la librería Dompdf
$file = file_get_contents("pagina2.html"); //Se "extrae" la página a renderizar

$dato1=rand(1,100); //guardo en una variable un número random entre 1 y 100
$dato2=rand(101,200); //guardo en otra variable un número aleatorio entre 101 y 200
$dato3=rand(300,10000); // y guardo en una tercera variable un número aleatorio entre 300 y 10000
$dompdf = new DOMPDF(); //creo un objeto de la clase DOMPDF
                                                              
         /*En la siguiente función reemplazo las "palabras clave" por los valores aleatorios de las variables que creé arriba*/
$html = str_replace( //a la variable $html guardo lo que me arroja la función str_replace
        array(
"{#dato1}","{#dato2}","{#dato3}" //éstas son las palabras claves a reemplazar
        ), 
        array(
$dato1,$dato2,$dato3 //éstos son los datos que sustituirán las palabras claves
        ), 
        $file //y se reemplazará de la página cargada en ésta variable, lo que hice más arriba
    );
    $dompdf->load_html($html); //Se carga la página que convertiremos ya con los reemplazos
    $dompdf->render(); //mandamos a llamar el método para renderizar
        
    header('Content-type: application/pdf'); //ponemos la cabecera para PDF
    echo $dompdf->output(); //se imprime el documento PDF
?>


El resultado será así: http://unrinconenlaweb.webcindario.com/programas/pdf/ejemplo2.php
Cada vez que se recarga la página, se muestran 3 valores diferentes en los campos.

Para descargar los ejemplos y la librería, aquí está el enlace:
https://dl.dropbox.com/u/46960544/pdf.rar

jueves, 24 de enero de 2013

Buscador dinámico [AJAX, JQuery]

Un "diseño" interesante para un buscador podría ser uno que, al momento de teclear en el campo de búsqueda, se fueran mostrando en "tiempo real" los resultados en el espacio correspondiente.

Una buena forma de hacerlo es mediante JQuery que tiene un mejor manejo de los eventos y brinda un sencillo método para manejar AJAX.

Para nuestro ejemplo, vamos a considerar que tenemos una Base de datos "busqueda" con la tabla "post" que contiene los siguientes campos:

| id | titulo | contenido |
| 1  |         |                 |


Crearemos primero nuestro archivo .php que será el que realizará la búsqueda en la base de datos y mostrará los resultados en una tabla:

Conectamos primero a la base de datos:
<?php

$dbhost = "localhost";
$dbuser = "root";
$dbpass = "";
$mysqli = new mysqli($dbhost,$dbuser,$dbpass,"busqueda");

?>

Luego comprobaremos si recibimos el parámetro de búsqueda por POST además de evitar que éste sea un espacio en blanco:

<?php


if(isset($_POST['parametro'])) //Verificamos que venga el parámetro vía POST
{
$parametro=trim($_POST['parametro']); //Limpiamos los espacios en blanco
if($parametro!="") //Comprobamos que no quede una cadena vacía
{
....

Ahora lo sencillo, realizar la búsqueda en la base de datos buscando tanto en el campo "título" como en el campo "contenido" coincidencias con respecto al parámetro buscado y lo metemos todo a una tabla:

<?php


$result = $mysqli->query("SELECT * FROM post WHERE titulo LIKE '%$parametro%' or contenido LIKE '%$parametro%';");
$resultados = array();
while ($row_errs = $result->fetch_array()) 

$resultados[]= $row_errs; 
}
?>
<table>
<?php
foreach($resultados as $post):
?>
<tr>
<td>
<?php echo $post['titulo'].": "; ?>
</td>
<td>
<?php echo $post['contenido']; ?>
</td>
</tr>
<?php
endforeach;
?>
</table>
<?php


?>

El archivo de búsqueda quedaría así:
Visualizar archivo de busqueda.php

Ahora la página que ofrecerá la interfaz para la búsqueda (que puede ser un simple html).
Primero que nada se debe tener el archivo de JQuery e insertarlo en la página:

<script type="text/javascript" src="jquery-1.3.2.min.js"></script>

Ahora bien, lo único que necesitamos es un input tipo text en el cual introducir el texto a buscar y un div el cual mostrará los resultados arrojados por el archivo de busqueda.php :


<input type="text" id="parametro" />
<br />
<br />
<div id="resultado" style="border: solid black 1px;"></div>

Y, por último, la "magia" de JQuery, con JavaScript se hará una función que, tanto al presionar una tecla como al soltarla mientras se esté escribiendo en el campo de texto, se extraiga el contenido del input, se envíe por POST a búsqueda.php y se recarge el div con el resultado obtenido:


<script type="text/javascript">
$(document).ready(function() {
$("#parametro").keydown( //Evento de presionar una tecla en el campo cuyo id sea "parametro"
function(event)
{
var param = $("#parametro").attr("value"); //Se obtiene el valor del campo de texto
$("#resultado").load('busqueda.php',{parametro:param}); //Y se envía por vía post al archivo busqueda.php para luego recargar el div con el resultado obtenido
}
);
});
$(document).ready(function() {
$("#parametro").keyup( //Evento de soltar una tecla en el campo cuyo id sea "parametro"
function(event)
{
var param = $("#parametro").attr("value"); //Se obtiene el valor del campo de texto
$("#resultado").load('busqueda.php',{parametro:param}); //Y se envía por vía post al archivo busqueda.php para luego recargar el div con el resultado obtenido
}
);
});
</script>

Pues nada difícil realmente, gracias a la ayuda de JQuery.

Para ver cómo resultaría implementado éste "buscador" aquí un ejemplo con una base de datos que se le han introducido 5 registro:

Para descargar el ejemplo, aquí el enlace de google drive:



[Demostración] Extraer datos de una Web (SQL Injection)

Posiblemente sean pocos a los que no les haya llamado la atención éste tema.
La inyección SQL (SQL injection o SQLi) es la forma más sencilla de lograr extraer los datos de un sistema, entre otras cosas, y la más común (debido al mismo caso).

Éste método consiste en alterar una consulta original que se realiza a la base de datos introduciendo un texto extra, que debe ser correcto, con el cual le indicamos qué queremos obtener.

Por ejemplo, suponiendo que se busca un usuario cuyo nombre se encuentre en una variable que es rellenada por el usuario:

"Select * FROM usuario WHERE nombre='$nombre';"

Si el valor de la variable $nombre fuera normal, como por ejemplo darknet, la consulta sería:

"Select * FROM usuario WHERE nombre='darknet';"

Por ahora todo funcionaría correctamente, pero ¿Qué pasaría si no se filtran bien los valores introducidos en la variable $nombre?
La respuesta es que se puede deformar la consulta para obtener un resultado indeseado para el sistema pero correcto para el atacante.
En el mismo ejemplo, vamos a darle a la variable $nombre el valor de darknet' or nombre LIKE '%%; la consulta alterada sería:

"SELECT * FROM usuario WHERE nombre='darknet' or nombre LIKE '%%';"

De ésta forma la consulta traería los datos de TODOS los usuarios en lugar de sólo 1.
Ahora bien, ya que se entiende el funcionamiento de una inyección, el método que se utiliza (en este caso) para obtener los datos de una página Web es manejando los parámetros GET de la página.
Los parámetros GET son aquellos que se observan en la URL del sitio y que, por lo general, van después del signo de '?'.
Por ejemplo, se tiene la siguiente URL:
http://www.paginaweb.com/index.php?search=123&status=2

Los parámetros GET de la URL son: search=123&status=2; como cada parámetro está separado por el signo &, así pues tenemos 2 parámetros: search y status, cuyos valores son '123' y '2' respectivamente. Éstos parámetros llegan a ser usados por los programadores para hacer consultas a la base de datos, como por ejemplo en las páginas de noticias o blogs en donde utilizan un parámetro para buscar el Id de la nota que se va a mostrar.
Claro que, aunque se usen los parámetros GET ésto no quiere decir que la página sea vulnerable ya que se pueden filtrar los valores obtenidos en los parámetros y ver si son legítimos o no.

Pero bien, al tener entendido cómo funciona ésta mecánica les presento un vídeo en donde se hace una demostración a la hora de indagar y extraer datos de una Base de datos en una página vulnerable:



Por si la resolución del vídeo a la hora de subirlo a YouTuBe no es muy apreciable, aquí les dejo el enlace de descarga directa: https://dl.dropbox.com/u/46960544/inyeccion%20SQL.mp4

Siendo ésto todo, me despido...

viernes, 4 de enero de 2013

[Demostración] Figuras sencillas en Blender


El modelado en 3D, sea el programa que sea, fácilmente se complica para la mayoría de los usuarios debido a que es un entorno precisamente en 3 dimensiones. Pero la mayoría de las complicaciones no se dan por el programa que se esté utilizando sino en la forma de pensar del usuario que casi siempre espera encontrar formas pre-determinadas o tutoriales para realizar las figuras que requiere, o simplemente el entorno de desarrollo le agobia sin permitirle usar la creatividad para realizar las figuras más sencillas a partir de las formas y herramientas más básicas.

El vídeo que presento es precisamente una demostración (y no un tutorial de ¿Cómo crear un(a)...?) de lo sencillo que es crear figuras simples a partir de las formas básicas.

Las figuras que demuestro en el vídeo son 1 pino, arbol y una cabeza humana (de una mujer).
Uso la versión de BLender 2.64 y no utilizo ninguna herramienta adicional del programa únicamente las transformaciones (escalado, duplicado y rotación).



Espero que el video sea una buena demostración que para hacer trabajos no profesionales no se requiere de una gran cantidad de herramientas ni de tiempo, es sólo cuestión de creatividad y de usar las figuras como un rompecabezas. Espero en breve hacer una demostración de figuras un poco más complejas utilizando herramientas más interesantes (distorción de nodos y operaciones booleanas).

Me despido.

miércoles, 19 de diciembre de 2012

Botón para mostrar ayuda [HTML, CSS, JavaScript]

La idea es muy simple, se quiere dar al usuario la opción de ver, en una página web, la ayuda o información que tal vez quiera saber.
Aunque es seguido que se quiere "llenar" espacio en una página, hay ocasiones en las que no se cuenta con mucho espacio o no se quiere amontonar elementos en la interfaz.
Para ello está este sencillo método: un "botón" que al pasar el cursor por encima de éste se muestra un div con la información que se desea mostrar; al quitarse el cursor la información también se oculta.

Primero, tenemos el DIV en el cual se muestra la ayuda:


<div id="ayuda">
    <b>
        Instrucciones de uso:
        <br />
        .....
    </b>
</div>

Lo importante es el "id" del div.
Ahora, lo esencial es que inicialmente esté oculto y que, cuando se muestre, esté encima de todos los demás elementos de la página. En sí, sólo hace falta los siguientes 2 atributos CSS:


visibility: hidden;
z-index: 5000;

Más, para mi gusto, se vería bien que estuviera sombrado y con esquinas redondeadas. Ésto es opcional claramente, pero el CSS del div sería:


#ayuda{
        border: solid gray 1px;
        width: 250px;
        background-color: white;
        box-shadow: 6px 6px 5px #999;
        -webkit-box-shadow: 6px 6px 5px #999;
        -moz-box-shadow: 6px 6px 5px #999;
        visibility: hidden;
        z-index: 5000;
    }

Después el botón, que realmente no será un botón sino un enlace; pero antes, mencionaré las funciones en JavaScript para ocultar y mostrar el DIV de ayuda:


function mostrarAyuda()
{
document.getElementById('ayuda').style.visibility = "visible";
}
function ocultarAyuda()
{
document.getElementById('ayuda').style.visibility = "hidden";
}

La función "mostrarAyuda" le asigna el valor "visible" al atributo "visibility" al div de ayuda. Lo cual hace que se muestre.
La función "ocultarAyuda" le asigna el valor "hidden" (oculto) al atributo "visibility" al div de ayuda. Lo cual hace que se oculte.
Y bueno, el enlace (que servirá de botón) para mostrar y ocultar la ayuda al pasar el cursor por encima:

<a id="boton" href="#" onmouseover="javascript:mostrarAyuda()" onmouseout ="javascript:ocultarAyuda()">Ayuda</a>

Ahí, el evento onmouseover (cuando se le pasa el cursor por encima) manda a llamar la función "mostrarAyuda". Caso contrario con el evento "onmouseout" llama la función "ocultarAyuda".

Y finalmente, el estilo del enlace que hará de botón. Como es muy complejo el estilo CSS para darle un buen toque elegante, además de que cambie según el cursor se encuentre encima o no, sólo les pongo el código CSS:


#boton {
        -moz-box-shadow:inset 0px 1px 0px 0px #ffffff;
        -webkit-box-shadow:inset 0px 1px 0px 0px #ffffff;
        box-shadow:inset 0px 1px 0px 0px #ffffff;
        background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #ffffff), color-stop(1, #d1d1d1) );
        background:-moz-linear-gradient( center top, #ffffff 5%, #d1d1d1 100% );
        filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#d1d1d1');
        background-color:#ffffff;
        -moz-border-radius:6px;
        -webkit-border-radius:6px;
        border-radius:6px;
        border:1px solid #dcdcdc;
        display:inline-block;
        color:#777777;
        font-family:arial;
        font-size:15px;
        font-weight:bold;
        padding:6px 24px;
        text-decoration:none;
        text-shadow:1px 1px 0px #ffffff;
    }
#boton:hover {
        background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #d1d1d1), color-stop(1, #ffffff) );
        background:-moz-linear-gradient( center top, #d1d1d1 5%, #ffffff 100% );
        filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#d1d1d1', endColorstr='#ffffff');
        background-color:#d1d1d1;
    }
#boton:active {
        position:relative;
        top:1px;
    }


El resultado se vería así:
http://unrinconenlaweb.webcindario.com/programas/boton_ayuda/pagina.html

Y pueden descargar los archivos, separado el CSS, JS y HTML para un manejo más sencillo :D

https://docs.google.com/open?id=0B6J7PWBjtBf7TUxzZEFkYVlvWjA



martes, 23 de octubre de 2012

Temporada de recitales ISMEV




TEMPORADA DE MÚSICA DE CÁMARA 2012
ANIVERSARIO X ISMEV (Instituto Superior de Música del Estado de Veracruz)


OCTUBRE

24.- Recital de cello y piano 18:00 hrs.
        Invitados especiales: Makcim Fernández y Mónica Florescu.

31.- Recital de piano 18:00 hrs.
        Invitados especiales: Teresita Jiménez y Aldo Tercero.


NOVIEMBRE

7.- Alumnos del maestro Abel Péres Pitón 18:00 hrs.

14.- Ensamble de maestros ISMEV 18:00 hrs.
        Dir. Alfredo Hernández.

21.- Ensamble de percusiones ISMEV 18:00 hrs.
       Maestros Jesús Reyes Y Eduardo Tellez.

28.- Dúo Karla y Rafael Jiménez 18:00 hrs.

DICIEMBRE
5.- Grupo de cámara, Maestros ISMEV, orquesta de cámara OSJEV  18:00 hrs.
      Dir. Antonio Tornero.

10.- Recital de Trompeta  18:00 hrs.
       Alumnos del maestro Tim Mckeown 18:00 hrs.

12.- Propedéutico en canto y artes escénicas 18:00 hrs.
       Maestra Ana Luisa.

Imagen de cartelera


Arco Sur #1, Reserva Territorial, Xalapa de Enriquez, Veracruz, C.P. 91070. 
TEL/FAX 2288193648 y 49

martes, 18 de septiembre de 2012

Insertar juego "Torres de Hanoi" en una WEB

Hola desde hace un rato.

Vagando en la web buscando accesorios para una página, encontré el clásico juego de Hanoi en JavaScript y liberado precisamente para ser implementado en cualquier página y/o blog.
La cosa es muy sencilla, aquí van los pasos:

1.-

Descargamos unas imágenes que nos servirán para los discos y las torres del juego:

Descargar recursos

2.-
Descomprimimos la carpeta y subimos las imágenes a un servidor de alojamiento web; debe ser necesariamente de alojamiento web ya que TODAS las imágenes deben estar dentro del mismo directorio. Por ejemplo, yo usé Webcindario.com y los subí al directorio "http://midominio.webcindario.com/img/hanoi/"

3.-

Lo siguiente es, en el cuerpo (body) de la página/blog se copia el siguiente código en donde editarán el valor de la variable imgdir por el de la dirección en la cual subiste las imágenes (Dejo los créditos y Copyright):



<SCRIPT LANGUAGE="JavaScript">
<!-- Original:  Adam Stock (adam@digital-biz.com) -->

<!-- (c) Copyright 1998-99 Adam L. Stock. All Rights Reserved -->
<!-- You have permission to republish this code provided -->
<!-- that you do not remove this copyright notice -->

// Cambia la dirección por la cual tú subiste las imágenes
imgdir = " http://midominio.webcindario.com/img/hanoi/ ";


function preload() {
this.length = preload.arguments.length;
for (var i = 0; i < this.length; i++) {
this[i] = new Image();
this[i].src = imgdir + preload.arguments[i];
   }
}

var pics = new preload("disk1.gif","disk2.gif",
"disk3.gif","disk4.gif","disk5.gif","disk6.gif",
"disk7.gif","pole.gif", "disk1h.gif","disk2h.gif",
"disk3h.gif","disk4h.gif","disk5h.gif","disk6h.gif",
"disk7h.gif");

var selectedr = null;
var selectedc = null;
var maxposts = 3;
var maxdisks = 7;
var all_posts = 3;
var startpost = 1;
var endpost = (startpost-1 < 0 ? maxposts-1 : startpost-1);
var disks = 7;
var imgwidth = 160;
var imgheight = 14;
var game_is_over = false;
var show_messages = false;
var board = new Array(maxposts);
board[0] = new Array(maxdisks + 1);
board[1] = new Array(maxdisks + 1);
board[2] = new Array(maxdisks + 1);

function initboard(startpost, disks) {
var len = board[0].length;
selectedc = null;
selectedr = null;
game_is_over = false;
endpost = (startpost-1 < 0 ? maxposts-1 : startpost-1);

for (i = 0; i < len; i++) {
board[0][i] = 0;
board[1][i] = 0;
board[2][i] = 0;
}
for (i = len-disks, j = 0; i < len; i++, j++) {
board[startpost][i] = len - j - 1;
   }
}

function drawall() {
for (j=0; j<board.length; j++) {
for (i=0; i<board[j].length; i++) {
draw(j,i, getName( board[j][i]));
   }
}
message("You may begin! Select a piece to move.");
}

function restart(start) {
startpost = start;
disks = document.forms[0].disc.options[document.forms[0].disc.selectedIndex].text;
initboard(startpost,disks);
drawall();
theAnim = new Animation();
}
initboard(startpost, disks);

function getName( num ) {
if (num == 0) return "post.gif";
return "disk" + num + ".gif";
}

function message(str, force) {
if (force || !game_is_over && !show_messages)
document.disp.message.value = str;
}

function messageadd(str) {
if (!game_is_over)
document.disp.message.value = document.disp.message.value + "\n" + str;
}

function isempty(num) {
for (i = 0; i < board[num].length; i++) {
if ( board[num][i] != 0) return false;
}
return true;
}

function topmost(num) {
for (i = 0; i < board[num].length; i++) {
if (board[num][i] != 0) return  i;
}
return -1;
}

function ispost(i,j) {
return (board[j][i] == 0);
}

function istopdisk(i,j) {
return (board[j][i-1] == 0);
}

function drawboard() {
document.writeln("<h2>The Towers of Hanoi</h2><p>");
document.writeln("<table cellspacing=0 cellpadding=0 border=0>");
document.write("<tr>");
for (j = 0; j < board.length; j++) {
document.write("<td>");
document.write("<a href='javascript:clicked("+0+","+j+")'><img src='" + imgdir + "posttop.gif' border=0></a><br>");
for (i=0; i< board[0].length; i++) {
document.write("<a href='javascript:clicked("+i+","+j+")'>");
document.write("<img src='" + imgdir + getName(board[j][i]) + "' name='pos"+ j + i + "' border=0><br>");
document.write("</a>");
}
document.writeln("</td>");
}
document.write("</tr></table>");
document.write("<form name='disp'><textarea name='message' wrap=virtual rows=2 cols=40></textarea><br>" +
"Disks: <select name=\"disc\" size=1><option>3<option>4<option>5<option>6<option selected>7</select><input "
+"type=button value=\"Start the Game Over\" onClick=\"restart(startpost);\"><input "
+"type=button value=\"Solve It!\" onClick=\"restart(startpost);setTimeout('hanoi(disks,startpost,endpost)',300)\"></form>");
}

function draw(x,y,name) {
document.images["pos"+x+""+y].src = imgdir + name;
}

function animate(x,y,name) {
theAnim.addFrame( "pos"+x+""+y, imgdir + name);
}

function clicked(i,j) {
document.forms[0].message.focus(); // get rid of annoying outline in MSIE
document.forms[0].message.blur();

if (game_is_over)  restart(startpost = endpost);
if (!isselection() && ispost(i,j)) { message("Select a piece to move."); return; }
if (!ispost(i,j)) { toggle(j); return; };
if (ispost(i,j) && selectedc == j) { message("Move the piece to a different post."); return; }
if (!legalmove(j)) { message("That is not a legal move. Try again."); return; }
move(j); return;
}

function legalmove(j) {
if (isempty(j)) return true;
return (board[j][topmost(j)] < board[selectedc][selectedr]);
}

function isselection() {
return selectedc != null;
}

function toggle( num ) {
var toppos = topmost(num);

if (selectedc == num && selectedr == toppos) {
selectedc = null; selectedr = null;
animate(num,toppos,"disk" + board[num][toppos] + ".gif");
message("Select a piece to move.");
return;
}
if (isselection()) {
animate(selectedc,selectedr,"disk" + board[selectedc][selectedr] + ".gif");
}
selectedc = num; selectedr = toppos;
animate(num,toppos,"disk" + board[num][toppos] + "h.gif");
message("Click on the post to which you want to move the disk.");
}

function move( num ) {
var toppos = (!isempty(num) ? topmost(num) : board[num].length);
board[num][toppos-1] = board[selectedc][selectedr];
board[selectedc][selectedr] = 0;
animate(selectedc,selectedr,"post.gif");
animate(num,toppos-1,"disk" + board[num][toppos-1] + ".gif");
selectedc = null; selectedr = null;
message("Select a piece to move.");
game_over();
}

function hanoi(no_of_disks, start_post, goal_post) {
if (no_of_disks > 0) {
var free_post = all_posts - start_post - goal_post;
hanoi (no_of_disks - 1, start_post, free_post);
show_messages = true;
toggle(start_post);
move(goal_post);
show_messages = false;
hanoi (no_of_disks - 1 , free_post, goal_post);
game_over(true);
   }
}

function game_over(forceMsg) {
var filledpost = null;
var val = 0;
for (k = 0; k < board.length; k++)  {
val += ( isempty(k) ? 1 : 0 );
if (!isempty(k)) filledpost = k;
}

if (val == 2 && isempty(startpost)) {
message("You won!", forceMsg);
game_is_over = true;
endpost = filledpost;
}
return game_is_over;
}


function Animation() {
this.imageNum = new Array();
this.imageSrc = new Array();
this.frameIndex = 0;      
this.alreadyPlaying = false;

this.getFrameCount = getframecount;
this.moreFrames = moreframes;      
this.addFrame = addframe;      
this.drawNextFrame = drawnextframe;
this.startAnimation = startanimation;
}

function getframecount() {  return this.imageNum.length; }
function moreframes() {  return this.frameIndex < this.getFrameCount(); }
function startanimation() {
if (!this.alreadyPlaying) {
theAnim.alreadyPlaying = true;
setTimeout('theAnim.drawNextFrame()',5);
   }
}

function addframe(num, src) {
var theIndex = theAnim.imageNum.length;
theAnim.imageSrc[theIndex] = src;
theAnim.imageNum[theIndex] = num;
theAnim.startAnimation();
}

function drawnextframe() {
if (theAnim.moreFrames()) {
document.images[ theAnim.imageNum[theAnim.frameIndex] ].src = theAnim.imageSrc[theAnim.frameIndex];
theAnim.frameIndex++;
setTimeout('theAnim.drawNextFrame()', 30);
} else {
theAnim.alreadyPlaying = false;
   }
}

drawboard();
var theAnim = new Animation();
message("You may begin! Select a piece to move.");
document.disp.message.value = "";
</script>

4.- (opcional)

Y una última línea para agradecer a quienes aportan éstos códigos y los difunden libremente:

<p><center>
<font face="arial, helvetica" size="-2">Free JavaScripts provided<br/>
by <a href="http://javascriptsource.com">The JavaScript Source</a></font>
</center><p>

El resultado (con unas simples adaptaciones personales) se encuentra aquí: http://unrinconenlaweb.blogspot.mx/p/torres-de-hanoi.html

Espero y les guste el juego.
Seguiremos picando código.