miércoles, 2 de diciembre de 2009

Coloreado de codigo fuente para blog en linux

Luego de escribir mi ultimo post buscando una herramienta que permita el coloreado de código fuente para nuestros blogs, y teniendo en cuenta que recomendé usar Windows Live Writer con el Plugin CodeSnnipet (Todo esto en entorno windows), quede en la tentativa de ofrecerles una solución del mismo tipo pero usando herramientas de linux, además de que en lo personal acostumbro a utilizar linux en el 70 por ciento de las tareas que realizo.

Ok, para nuestra buena suerte existe vim en el cual podemos editar nuestros archivos fuente sin ningun problema y que además de todo ofrece una herramienta que traduce todo el código fuente que estemos editando en código html directamente con la opción ":TOhtml" la cual nos arroja un resultado mas que suficiente para poder trabajar.

Para nuestro ejemplo utilizaremos un código bastante sencillo en php como el que muestro a continuacion:
<?php
function saludar{
echo "Hola a todos!!!";
}
?>

Este código lo estamos editando en vim con el nombre de prueba1.php, cuando ya lo tengamos escrito escribiremos ":TOhtml" en la linea de comandos de vim y nos mostrara el siguiente codigo
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>~/temporal/prueba1.php.html</title>
<meta name="Generator" content="Vim/7.2">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body bgcolor="#ffffff" text="#000000"><font face="monospace">
<font color="#ff40ff">&lt;?php</font><br>
<font color="#ff40ff">function</font>&nbsp;saludar<font color="#ff40ff">(){</font><br>
&nbsp;&nbsp;<font color="#ff40ff">echo</font>&nbsp;&quot;<font color="#ff6060">Hola a todos!!!</font>&quot;;<br>
<font color="#ff40ff">}</font><br>
<font color="#ff40ff">?&gt;</font><br>
</font></body>
</html>

Ahora tienen que retirar algunas lineas osea las 8 o 9 primeras dependiendo es decir retiran las lineas hasta la etiqueta que diga al final:
<span style="font-family:monospace;">
tambien deben retirar esa etiqueta, después van al final del archivo y retiran lo siguiente:
</font></body></html>
Luego de ello deben remover todas las etiquetas "<br>" del código, una forma rápida para ello es si es que todavía están en vim (para hacer esto podrían usar cualquier otro editor gedit por ejemplo), usen la siguiente opción en la linea de comandos de vim ":%s/nt><br>/nt>/g" esta sentencia retirara esas etiquetas por ustedes y listo lo que les queda es en si el código ya formateado y coloreado

Ahora lo siguiente es poner este código en una capa para que pueda contenerlo, la capa la pueden crear ustedes con las etiquetas <div> y asignándole un estilo a la misma pero yo ya les hice el trabajo, tome prestado la capa que genera el CodeSnippet y le hice algunas modificaciones para que puedan usarlo, el código de las capas es el siguiente, casi al final de ese código dejo una marca para que sepan donde pegar el código generado con el vim:
<div style="border-bottom:silver 1px solid;text-align:left;border-left:silver 1px solid;line-height:12pt;background-color:#ffffff;width:97.5%;font-family:'Courier New', courier, monospace;direction:ltr;max-height:200px;font-size:8pt;overflow:auto;border-top:silver 1px solid;cursor:text;border-right:silver 1px solid;margin:20px 0 10px;padding:4px;" id="Wrapper"><div style="text-align:left;line-height:12pt;background-color:#ffffff;width:100%;font-family:'Courier New', courier, monospace;direction:ltr;color:black;font-size:8pt;overflow:visible;border-style:none;padding:0;" id="Snippet"><pre style="text-align:left;line-height:12pt;background-color:white;width:100%;font-family:'Courier New', courier, monospace;direction:ltr;color:black;font-size:12pt;overflow:visible;border-style:none;margin:0;padding:0;">AQUI INSERTEN EL CODIGOOOOO!!!!</pre></div></div>
y listo el código resultante lo pegan directamente en su editor de posts.

El código final que obtenemos lo probé tanto en Blogger como en Wordpress y funcionan bastante bien además de que el vim tiene coloreado de código para la mayoría de los lenguajes conocidos.

Como prueba final les dejo este código de un programa simple opengl con c++.
/* 
* File: main.cpp
* Author: yosel
*
* Created on 24 de noviembre de 2009, 10:49 PM
*/

#ifdef WIN32
#include <windows.h>
#endif
#ifdef __APPLE__
#include <OpenGL/gl.h>
#include <GLUT/glut.h>
#else
#include <GL/gl.h>
#include <GL/glut.h>
#endif

#include <unistd.h>
#include "sphere.h"

float * pos;
TSphere * sphere = NULL;

void initgl(){
glEnable(GL_DEPTH_TEST);
glClearColor(0.0,0.0,0.0,0.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0,1.0,1.0,100.0);
// Proyección perspectiva. El ángulo de visualización es de 60 grados, la razón ancho/alto es 1 (son inguales), la distanciamínima es z=1.0, y la distancia máxima es z=100.0
sphere = new TSphere(5,0.1);
glMatrixMode(GL_MODELVIEW);
gluLookAt(3,3,14,0,0,0,0,1,0);
}

void display(void){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(1.0,1.0,1.0);
glutWireCube(10);
glPushMatrix();
glColor3f(0.0,0.0,1.0);
pos = sphere->getPosv();
glTranslatef(pos[0],pos[1],pos[2]);
glutSolidSphere(1,10,10);
glPopMatrix();
glFlush();
}

void idle(void){
sphere->test();
usleep(33);
glutPostRedisplay();
}

int main(int argc, char ** argv){
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowPosition(20,20);
glutInitWindowSize(500,500);
glutCreateWindow(argv[0]);
initgl();
glutDisplayFunc(display);
glutIdleFunc(idle);
glutMainLoop();
return 0;
}

PD: Olvide comentarles que todo este post lo escribi siguiendo el metodo que estamos comentando

Saludos y hasta la proxima

miércoles, 11 de noviembre de 2009

Coloreando código fuente en Blogger

Para empezar les contare que deje de escribir artículos en este blog ya que me resultaba tremendamente frustrante tratar de escribir código fuente que se muestre de forma aceptable y no lograr mi cometido, dado que el fin de este blog es hablar de acerca de programación en general, lo que implica escribir toneladas de código fuente y la manera en como lo estaba haciendo me tomaba mucho tiempo, trabajo extra, se veía muy mal, y al final me quitaban las ganas de hacerlo.

Cabe agregar también que la alternativa directa de solución era montarme un servidor web en casa con wordpress y un plugin que me permita realizar esta tarea (existen varios para wordpress), pero descarté la idea ya que los servidores que tengo en casa son de desarrollo y siempre los estoy reinstalandolos con lo necesario para realizar mis proyectos, y la idea de tener un blog en casa me impediría tocar el servidor.

Luego de pensarlo por muuuuuuuuuuuuuuuuuucho tiempo (después de mi ultimo post), decidí ponerle fin a este dilema para poder en adelante postear mas seguido (dado que tengo mucho en el tintero), entonces luego de 5 horas de encerrarme probando alternativas pude resolverlo medianamente y ahí va la solución para los que están sufriendo como yo.

Lo ideal para escribir en un blog como el nuestro es tener una herramienta que nos permita escribir código fuente con las siguientes características:

  • Permitir numeración de líneas
  • Permitir espacios y tabulaciones
  • Permitir scrollbars en los cuadros de texto donde se mostraran los códigos fuente
  • y lo mas importante, permitir coloreado de código de acuerdo al lenguaje especifico que se este utilizando

En el camino probamos varias herramientas online como por ejemplo SimpleCode que lo único que hace es tratar de reemplazar los saltos de línea y los espacios con sus códigos html estándar, lo malo que no obtenemos coloreado de código, ni numeración ni cuadros de texto con scroll. Las demás herramientas online creo que no vale la pena ni enumerarlas ya que no me convencieron en lo absoluto

Busque plugins que hagan esta tarea para blogger pero creo que no existen (si me equivoco corríjanme), al final la solución necesaria era instalarse una herramienta de escritorio que nos permita editar nuestros post, estas herramientas son llamadas Clientes Blog de los cuales existen decenas y de las cuales solo llegue a probar 10 y ¿que creen?, ninguno tiene herramientas que nos permitan lograr nuestro cometido.

Durante las pruebas con Windows Live Writer me encontré con un plugin para este cliente llamado Code Snippet el cual me dejo complacido solo tiene un pequeño problemita con el scroll horizontal (no funciona bien) y hace que las líneas de código muy extensas bajen a una segunda línea por lo demás acepta coloreado de múltiples lenguajes (c#, javascript, html, java, visual basic, y mas), también acepta numeración de líneas de código y genera cuadros de edición que poseen scrollbars el resultado es el siguiente:

   1: for(i=1;i<30;i++){
   2:     imprimir i;
   3: }

A menudo el Live Writer en conjunto con el Code Snippet suelen agregar líneas en blanco entre las líneas del código fuente esto se debe a las especificaciones de los estilos que ambos generan, la solución mas rápida si eso les sucede es utilizar otro cliente blog solo para corregir estas pequeñas deficiencias, el cliente que usaremos será Post2Blog que al parecer es el que mejor código genera solo tenemos que abrir nuestro post en el Post2Blog y volver a publicarlo nada mas no es necesario editar nada, lo que el Post2Blog hará es regenerar el código del post reparando deficiencias en el mismo

Bueno ahora que ya puedo postear código fuente es hora de sacar algunos artículos del tintero.

Saludos

jueves, 1 de octubre de 2009

Creando una aplicación CORBA completa con Java e IDL

Hace poco una amiga me pregunto si sabia programar en java a lo que respondí: "Obviamente, me estas ofendiendo ;)", y me comento que necesitaba un programa que sume dos números, yo dije dentro de mi "no hay algo un poco mas difícil??", pero con lo que no contaba es con la línea final que me escribió en la conversación "pero lo quiero usando CORBA en java", mmm hace mucho que no veía corba y me pareció interesante la idea de escribir al respecto y de paso que como buen samaritano ayudaba a mi querida amiga "la chata", esta va por ella .....

En principio vayamos a la definición de CORBA, santa wikipedia dice lo siguiente "En computación, CORBA (Common Object Request Broker Architecture - arquitectura común de intermediarios en peticiones a objetos), es un estándar que establece una plataforma de desarrollo de sistemas distribuidos facilitando la invocación de métodos remotos bajo un paradigma orientado a objetos.", esto en buen cristiano quiere decir que los métodos públicos de la instancia de una clase que ustedes escriban (siguiendo las especificaciones de corba) en el servidor pueden ser llamados remotamente desde una aplicación en una pc cliente, estas clases pueden escribirse en distintos lenguajes es decir que uno podría escribir las clases en c++ en el servidor y las instancias de estas clases podrían ser llamadas por un cliente el cual dispone de las clases escritas en java.

IDL es un lenguaje de definición de interfaces que utiliza CORBA, el cual le permitirá definir las interfaces para los servicios que ofrecerá, de estas interfaces parten las implementaciones de la parte servidor y cliente en cualquiera de los diversos lenguajes que implementan CORBA (Ada, C, C++, Smalltalk, Java, Python, Perl).

Y bueno Java es Java no tengo mas que decir...

Ahora si a lo que importa la implementación:

PASO 1: Preparar la aplicación
Crear una carpeta donde prefieran para trabajar las clases dentro de ella en mi caso estoy sobre una maquina con windows asi es que trabajare en la carpeta "d:’aplicaciones’corba’java’sumadosnumeros"

PASO 2: Definir la interfaz IDL
ya dentro de la carpeta crearemos un archivo llamado Suma.idl con el famosísimo Notepad (de cariño Visual Notepad), el cual tiene el siguiente contenido:

   1: module sumaApp{
   2:     interface suma{   
   3:         long sumar(in long primernumero, in long segundonumero);
   4:         oneway void shutdown();
   5:     }   
   6: }

Traduciendo el código diría algo así: creamos dentro de la carpeta sumaApp las clases necesarias para implementar en corba la interface suma que tiene dos métodos sumar que devuelve un entero (long), con dos parámetros de entrada (in) primernumero que es entero y segundo numero que también es entero, método que nos permitirá sumar dos números enteros, y el método shutdown que nos permitirá cerrar la transacción cuando lo necesitemos.

PASO 3: Generar las clases CORBA
Para generar las clases corba utilizaremos el compilador de interfaces que viene con el sdk de java se llama idlj, al ejecutar esta aplicación en conjunto con la definición suma.idl creara para nosotros todas las clases necesarias para poder utilizarla. El procedimiento es como sigue:

dentro de la carpeta de la aplicación ejecutar: idlj -fall suma.idl

esta generara la carpeta sumaApp y dentro de ella las clases _SumaStub.java, Suma.java, SumaHelper.java, SumaHolder.java, SumaOperations.java, SumaPOA.java

* tengan en cuenta que el directorio bin de java debe estar en las variables de entorno si no lo esta tendría que ejecutar algo así dentro de la carpeta de su aplicación: c:’ProgramFiles’java’jdk1.6.0_14’bin’idlj -fall suma.idl, esto seria para todos los comandos que usaremos en adelante

ahora solo tenemos que escribir la clase cliente y la clase servidor dentro de carpeta de la aplicación

PASO 4: La clase servidor: SumaServer.java

   1: import sumaApp.*;
   2: import org.omg.CosNaming.*;
   3: import org.omg.CORBA.*;
   4: import org.omg.PortableServer.*;
   5: import org.omg.PortableServer.POA;
   6:  
   7: class SumaImpl extends SumaPOA{
   8:     private ORB orb;
   9:  
  10:     public void setORB(ORB orb_val){
  11:         orb=orb_val;
  12:     }
  13:  
  14:     public int sumar(int primernumero, int segundonumero){
  15:         return primernumero+segundonumero;
  16:     }
  17:  
  18:     public void shutdown(){
  19:         orb.shutdown(false);
  20:     }
  21: }
  22:  
  23: public class SumaServer {
  24:  
  25:     public static void main(String args[]){
  26:         try{
  27:             ORB orb= ORB.init(args,null);
  28:             POA rootpoa=POAHelper.narrow(orb.resolve_initial_references("RootPOA"));
  29:             rootpoa.the_POAManager().activate();
  30:  
  31:             SumaImpl sumaImpl=new SumaImpl();
  32:             sumaImpl.setORB(orb);
  33:  
  34:             org.omg.CORBA.Object ref=rootpoa.servant_to_reference(sumaImpl);
  35:             Suma href=SumaHelper.narrow(ref);
  36:             org.omg.CORBA.Object objRef=orb.resolve_initial_references("NameService");
  37:             NamingContextExt ncRef=NamingContextExtHelper.narrow(objRef);
  38:  
  39:             String name="Suma";
  40:             NameComponent path[]=ncRef.to_name(name);
  41:             ncRef.rebind(path, href);
  42:             System.out.println("Servidor de suma listo y en espera");
  43:             orb.run();
  44:         }catch(Exception e){
  45:             System.err.println("Error: "+e);
  46:             e.printStackTrace(System.out);
  47:         }
  48:  
  49:         System.out.println("Adios cerrando servidor");
  50:     }
  51: }

si vemos detenidamente el código en este archivo notaremos que se implementan dos clases SumaImpl y SumaServer, SumaImpl es la que se encarga de implementar los métodos declarados en la interface en el archivo idl que definimos al principio. La clase SumaServer se encarga de generar las llamadas a los métodos corba haciendo referencia siempre a la clase SumaImpl que es la que llevara toda la lógica de la aplicación. Es decir que la clase SumaServer en si es repetitiva a diferencia de la clase SumaImpl que es donde implementaremos la logica de los métodos que utilizaremos

* No explicare el código ya que por ser pequeño asumiré que es entendible

PASO 5: la clase Cliente: SumaClient.java

   1: import sumaApp.*;
   2: import org.omg.CosNaming.*;
   3: import org.omg.CORBA.*;
   4:  
   5: public class SumaClient {
   6:  
   7:     static Suma sumaImpl;
   8:  
   9:     public static void main(String args[]){
  10:         try{
  11:             ORB orb= ORB.init(args,null);
  12:             org.omg.CORBA.Object objRef=orb.resolve_initial_references("NameService");
  13:             NamingContextExt ncRef= NamingContextExtHelper.narrow(objRef);
  14:     
  15:             String name="Suma";
  16:             sumaImpl=SumaHelper.narrow(ncRef.resolve_str(name));
  17:             //System.out.println("Obteniendo las cabeceras del objeto servidor: "+sumaImpl);
  18:             System.out.println("suma es:"+Integer.toString(sumaImpl.sumar(20, 30)));
  19:             sumaImpl.shutdown();
  20:         }catch(Exception e){
  21:             System.out.println("Error: "+e);
  22:             e.printStackTrace(System.out);
  23:         }
  24:     }
  25: }

La clase SumaClient también es sencilla dentro de la etiqueta try se realiza la construcción de los objetos CORBA y si vemos bien el llamado a la función de suma se hace casi en la ultima línea que es la única que en realidad cuenta como lógica de programa ya que la parte de construcción de objetos corba es repetitiva para la mayoría de los casos

ULTIMO PASO: Probar

Primero tenemos que compilar nuestras clases para ello usaremos la siguiente línea estando dentro de la carpeta donde esta nuestra aplicación:
javac *.java sumaApp/*.java

si no hay alertas entonces vamos por buen camino (al menos a mi no me salió ninguna)

ahora ya compilado iniciaremos el servicio orbd (asegúrense de ser administradores sino no podrán iniciar el servicio), la linea es la siguiente:
orbd -ORBInitialPort 1080
si eso no funciona pueden usar:
start orbd.exe -ORBInitialPort 1080

* ordb.exe viene en la carpeta bin del sdk de java

si todo va bien el servicio orbd se iniciara escuchando en el puerto 1080 (ustedes pueden elegir que puerto usar de los 65000 disponibles)

Ahora tenemos que iniciar nuestro servidor de sumas dentro del servicio orbd, la línea es la siguiente:
java SumaServer -ORBInitialPort 1080 -ORBInitialHost localhost

si les sale el mensaje: "servidor de suma listo y en espera" todo va bien

y como final solo tenemos que ejecutar el cliente para verificar que todo funcione, la línea es como sigue:
java SumaClient -ORBInitialPort 1080 -ORBInitialHost localhost

y debería de mostrarnos en pantalla el texto "la suma es : 50", ya que como parámetros le pasamos 30 y 20 en el código del cliente, si obtienen eso entonces ya tienen el trabajo echo

Por cuestiones pedagógicas ejecutamos el cliente y el servidor en la misma maquina lo cual no es lo ideal, para que puedan ustedes ver lo que realmente significa corba deben de llevar a otra maquina la carpeta de aplicación y desde la otra maquina ejecutar el cliente

También dejo en claro que esta aplicación es de las mas sencillas de entender y la escribí pensando en cuestiones pedagógicas, y seguramente los gurús del corba deben de tener mejores códigos comparados con este que es a mi parecer humilde pero efectivo.

Con esto terminamos pensé hacerlo en una hora pero me tomo 3 y ya son las 3 am asi es que me voy a dormir, nos vemos y hasta que por ahí se me ocurra escribir de nuevo

Saludos

jueves, 18 de junio de 2009

Ajax y DropDownLists anidados

Cuando me inicie en el mundo del desarrollo web me tope con lo que todo desarrollador que inicia se topara en algún momento de su vida, me refiero al tedioso procedimiento de utilizar combos anidados, es decir combos que depende de los valores elegidos en otros, en buen castellano quiere decir que los valores que tengo listado en el combo numero 2 dependen del valor que elegí en el combo numero 1 y que los valores que tengo listados en el combo numero 3 dependen del valor que elegí en el combo numero 2 y así sucesivamente, pudiendo llegar al en\’e9simo nivel de anidamiento sin ningún problema (claro que no conocí casos de pasaran de 4 combos anidados en proyectos reales).

Las soluciones que rondaban eran diversas, la mas sencilla de ellas requería que cada ves que eligiera un valor del combo numero 1 este recargara toda la pagina para poder capturar el valor elegido y con ello poder llenar el combo numero 2, el que a su ves cuando era elegido un valor nuevamente recargaba la pagina para capturar el valor y poder llenar el combo numero 3, etc.

Llego ajax y se facilitaron mas las cosas ya que cuando se eligiera un valor del combo numero 1 este enviaba una petición por detrás de la aplicación la misma que devolvía la lista de valores del combo numero 2 sin necesidad de recargar la pagina.

Bueno luego de tanta melancolía por aquellos años (hablo como si tuviese 60 no?), definiremos el dilema de hoy: me llegan los bocetos y las maquetas de la nueva aplicación que esta en desarrollo y le echo un ojo, lo mas fácil de desarrollar generalmente en proyectos comunes (el pan de cada día), son los famosísimos formularios de contacto entonces procedo a revisarlos de forma rápida pero sorpresa ..... el bendito formulario trae como dato obligatorio el UBIGEO (Ubicación Geográfica), que encima de todo se propone de la siguiente manera Departamento - Provincia - Distrito (osea 3 niveles), con mucha tristeza y lagrimas en los ojos por que me tomara mas tiempo de lo que pensé en hacerlo, me bajo el ultimo ubigeo disponible en las bases de datos de INEI (Instituto nacional de estadística e informática - Perú), y me dispongo a desarrollar.

En principio debemos saber que ajax como corre en el lado del cliente no deberíamos tener problemas con el lenguaje que estemos usando, esto cumplía para todos los lenguajes que yo utilizaba menos para uno .... si señores ASP.NET (c#), como sabemos existen controles listos para usarse y una variedad de alternativas en toda la web, busque pero ninguno se prestaba para lo que yo necesitaba exactamente así es que decidí usar ajax nativamente e idear la forma de llenar los dropdownlists vía javascript, esto lo dejo claro ya que no estoy usando ninguna implementación de ajax para .NET sino simplemente funciones javascript.

En principio necesitamos 3 DropdowLists que se llaman en mi caso:

cmbDpto - para los departamentos
cmbProv- para las provincias
cmbDist - para los distritos

Demás esta decirles que cmbDist depende de cmProv y cmbProv depende directamente de cmbDPto, y los defino de la siguiente forma:

   1: <td>
   2: <asp:dropdownlist id="cmbDpto" runat="server" cssclass="form_combos" onchange="return cmbDptoOnChange()"></asp:dropdownlist>
   3: </td>
   4: <td align="left">
   5: <asp:dropdownlist id="cmbProv" runat="server" cssclass="form_combos" onchange="return cmbProvOnChange()"></asp:dropdownlist>
   6: </td>
   7: <td align="left">
   8: <asp:dropdownlist id="cmbDist" runat="server" cssclass="form_combos">
   9: </td>

cmbDpto dispara la función javascript cmbDptoOnChange() y cmbProv dispara cmbProvOnChange(), también se darán cuenta que solo tienen que llenar los datos del control cmbDpto (código del departamento y nombre del departamento - la forma de llenarlo depende de ustedes), los otros dos dropDownLists no contienen elementos. Ahora necesitamos definir las funciones mencionadas arriba...

   1: function cmbDptoOnChange(){
   2:      var cmbDpto = document.getElementById("cmbDpto");
   3:      var selectedDpto = cmbDpto.options[cmbDpto.selectedIndex].value;
   4:      var requestUrl = "AjaxServer.aspx?ff=dp&tipo=" + encodeURIComponent(selectedDpto);
   5:      CreateXmlHttp();
   6:  
   7:      if(XmlHttp){
   8:          XmlHttp.onreadystatechange = HandleResponseDP;
   9:          XmlHttp.open("GET", requestUrl, true);
  10:          XmlHttp.send(null);
  11:      }
  12: }
   1: function cmbProvOnChange(){
   2:      var cmbDpto = document.getElementById("cmbDpto");
   3:      var cmbProv = document.getElementById("cmbProv");
   4:      var selectedDpto = cmbDpto.options[cmbDpto.selectedIndex].value;
   5:      var selectedProv = cmbProv.options[cmbProv.selectedIndex].value;
   6:      var requestUrl = "AjaxServer.aspx?ff=dd&tipo=" + encodeURIComponent(selectedDpto+selectedProv);
   7:  
   8:      CreateXmlHttp();
   9:  
  10:      if(XmlHttp){
  11:          XmlHttp.onreadystatechange = HandleResponseDD;
  12:          XmlHttp.open("GET", requestUrl, true);
  13:          XmlHttp.send(null);
  14:      }
  15: }

OK creo que los javascript se explican por si mismos solo que tienen dependencias es decir dependen de otras funciones, en general tenemos la función básica ajax para crear el objeto XmlHttp e inicializar una petición osea:

   1: var XmlHttp;
   2:  
   3:  function CreateXmlHttp(){
   4:      try{
   5:          XmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
   6:      }catch(e){
   7:          try{
   8:              XmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
   9:          } catch(oc){
  10:              XmlHttp = null;
  11:          }
  12:      }
  13:   
  14:      if(!XmlHttp && typeof XMLHttpRequest != "undefined"){
  15:          XmlHttp = new XMLHttpRequest();
  16:      }
  17: }

Si todo va bien con la petición de la función cmbDptoOnChange() entonces se traslada el manejo a otra función javascript HandleResponseDP() que es la que se encargara de procesar la respuesta que genera el objeto XMLHTTP esta función es como sigue:

   1: function HandleResponseDP(){
   2:      if(XmlHttp.readyState == 4){
   3:          if(XmlHttp.status == 200){
   4:              LlenarProvincias(XmlHttp.responseXML.documentElement);
   5:          }else{
   6:              alert("Problemas con el servidor Ajax." );
   7:          }
   8:      }
   9: }

si todo va bien deriva la respuesta hacia la función LlenarProvincias() que es la que se encargara de pintar nuestro control con los datos de las provincias. Ahora si es que son observadores se dieron cuenta que la función cmbDptoOnChange() y la funcion cmbProvOnChange() llaman a un archivo que lleva por nombre ajaxserver.aspx que no es mas ni menos que un webform sin código html dentro del cual se implementan funciones que devolverán los datos que se le soliciten en formato XML es decir si yo solicitara provincias devolvería algo así como :

   1: <provincias> 
   2:      <provincia>
   3:          <valor>02</valor> 
   4:          <titulo>Lima</titulo>
   5:      </provincia>
   6:      <provincia>
   7:          <valor>03</valor>
   8:          <titulo>Canta</titulo>
   9:      </provincia>
  10: </provincias>

esta respuesta es la que tenemos que parsear en la funcion LlenarProvincias() para poder pintar los elementos del control cmbProv la función es como sigue:

   1: function LlenarProvincias(NodoProvincias){
   2:      var listaProvincias = document.getElementById("cmbProv");
   3:  
   4:      for (var count = listaProvincias.options.length-1; count >-1; count--){
   5:          listaProvincias.options[count] = null;
   6:      }
   7:  
   8:      var NodoProvincia = NodoProvincias.getElementsByTagName(’provincia’);
   9:      var textValue;
  10:      var textTitulo;
  11:      var optionItem;
  12:   
  13:      for (var count = 0; count < NodoProvincia.length; count++){
  14:          var NodoValor=NodoProvincia[count].getElementsByTagName(’valor’);
  15:          textValue = GetInnerText(NodoValor[0]);
  16:          var NodoTitulo=NodoProvincia[count].getElementsByTagName(’titulo’);
  17:          textTitulo = GetInnerText(NodoTitulo[0]);
  18:          optionItem = new Option( textTitulo, textValue, false, false);
  19:          listaProvincias.options[listaProvincias.length] = optionItem;
  20:      }
  21:   
  22:      cmbProvOnChange();
  23: }

Al final de esta función se hace un llamado a la función cmbProvOnChange() directamente ya que si yo acabo de llenar mi lista de provincia lo ideal seria tomar el primer elemento de la misma y con su valor llenar mi lista de distritos no es cierto? (si lo dudas es que tienes que volver a leer desde el principio jejeje). cmbProvOnChange() procede de la misma forma que cmbDptoOnChange() es decir cmbProvOnChange llamara a la función HandleResponseDD que se encargara de recepcionar la respuesta de nuestro ajaxServer.aspx y llenara el cmbDist de distritos con la función LlenarDistritos(), las funciones se las muestro a continuación.

   1: function HandleResponseDD(){ 
   2:      if(XmlHttp.readyState == 4){ 
   3:          if(XmlHttp.status == 200){
   4:              LlenarDistritos(XmlHttp.responseXML.documentElement);
   5:          }else{
   6:              alert("Problemas con el servidor Ajax." );
   7:          }
   8:      }
   9: }
   1: function LlenarDistritos(NodoDistritos){
   2:      var listaDistritos = document.getElementById("cmbDist");
   3:      for (var count = listaDistritos.options.length-1; count >-1; count--){
   4:          listaDistritos.options[count] = null;
   5:      }
   6:   
   7:      var NodoDistrito = NodoDistritos.getElementsByTagName(’distrito’);
   8:      var textValue;
   9:      var textTitulo;
  10:      var optionItem;
  11:   
  12:      for (var count = 0; count < NodoDistrito.length; count++){
  13:          var NodoValor=NodoDistrito[count].getElementsByTagName(’valor’);
  14:          textValue = GetInnerText(NodoValor[0]);
  15:          var NodoTitulo=NodoDistrito[count].getElementsByTagName(’titulo’);
  16:          textTitulo = GetInnerText(NodoTitulo[0]);
  17:          optionItem = new Option( textTitulo, textValue, false, false);
  18:          listaDistritos.options[listaDistritos.length] = optionItem;
  19:      }
  20: }

Con esto ya tenemos todo lo de nuestro webform de contáctenos, ahora les explico lo del ajaxserver.aspx, este webform no tiene código en el archivo aspx pero si tienen funciones en el archivo ajaxserver.aspx.cs, si se dan cuenta las llamadas en las funciones cmbDptoOnChange() y cmbProvOnChange() son de tipo GET y las rutas son:

"AjaxServer.aspx?ff=dp&tipo=" + encodeURIComponent(selectedDpto); y’par
"AjaxServer.aspx?ff=dd&tipo=" + encodeURIComponent(selectedDpto+selectedProv);’par ’par

respectivamente, esto quiere decir que el webform ajaxserver.aspx recibe dos parámetros el primero ff que puede ser dp (provincias) o dd (distritos) es decir lo que se le esta solicitando, el segundo parámetro viene a ser tipo que en realidad lo que contiene es el código del departamento en el primer caso y en el segundo el código del departamento mas el código de la provincia, estos parámetros serán procesados en el webform de la siguiente manera (ajaxserver.aspx.cs):

   1: protected void Page_Load(object sender, EventArgs e){
   2:      if (!IsPostBack){
   3:          string tipo = Request.QueryString["tipo"];
   4:          string funcion=Request.QueryString["ff"];
   5:          string respuestaXML="";
   6:   
   7:          if (tipo.Length > 0 && funcion.Length>0){
   8:              Response.Clear();
   9:   
  10:              if (funcion == "dp"){
  11:                  ubigeo miubigeo = new ubigeo();
  12:                  respuestaXML = miubigeo.dameProvXML(tipo);
  13:              }
  14:              if (funcion == "dd"){
  15:                  ubigeo miubigeo = new ubigeo();
  16:                  respuestaXML = miubigeo.dameDistXML(tipo.Substring(0, 2), tipo.Substring(2, 2));
  17:              }
  18:   
  19:              Response.Clear();
  20:              Response.ContentType = "text/xml";
  21:              Response.Write(respuestaXML);
  22:              Response.End();
  23:          }else{
  24:              Response.Clear();
  25:              Response.End();
  26:          }
  27:      }else{
  28:          Response.Clear();
  29:          Response.End();
  30:      }
  31: }

Bueno y solo falta definir como serán las funciones que devuelvan XML para hacerlo simple solamente junte cadenas de texto y forme las etiquetas concatenando cadenas y nada mas. El procedimiento que muestro es solo una idea ustedes pueden generar sus cadenas XML como mas les convenga además que ustedes tienen sus propias formas de conectarse a bases de datos que obviamente difieran de la mía, aquí el código:

   1: public string dameListaXML(string idioma){
   2:      string milista = "";
   3:      milista = milista + "<provincias>";
   4:      beanitemlista miitemlista;
   5:      DbDataReader resp;
   6:      fabricaSgbd mifabrica = new fabricaSgbd();
   7:      Isgbd msgbd = mifabrica.dameSgbd();
   8:   
   9:      resp = msgbd.consultar("select * from provincias where estado=’H’ order by nombre asc");
  10:      while (resp.Read()){ 
  11:          milista = milista + "<provincia>";
  12:          milista = milista + "<codigo>" + Convert.ToString(resp["provincia_id"]) + "</codigo>’n";
  13:          milista = milista + "<nombre>" + Convert.ToString(resp["nombre"]) + "</nombre>’n";
  14:          milista = milista + "</provincia>’n";
  15:      }
  16:   
  17:      milista = milista + "</provincias>’n";
  18:      msgbd.cerrar();
  19:      return milista;
  20: }

y ..... por fin terminamos como verán anidar combos no es muy sencillo que digamos y varia con respecto al lenguaje que usemos al menos en el presente articulo intento mostrar algo que nos puede servir para todos los lenguajes ya que solo tendríamos que reemplazar nuestro ajaxserver en el lenguaje que necesitemos
Suerte y hasta que me den ganas de escribir otro articulo :P