Friday, December 22, 2006

Visual Studio 2005 SP1 para Windows Vista (Beta)

esta disponible, justo a tiempo para navidad

Wednesday, December 20, 2006

funcion para generar numeros aleatorios, con todos los digitos distintos

El codigo para este articulo aplica a C#

Leyendo blogs, me encontre con este post (en italiano), donde Marco quiere escribir una funcion que le genere numeros aleatorios de 5 digitos, el resultado se requiere en un string, donde todos los digitos son diferentes, es decir, cada numero (de 5 digitos) generado, no puede tener 2 digitos iguales, la funcion que el escribio es la siguiente:

private string GetRandom()
{
Random rn = new Random();
string resultnum=string.Empty;
do
{
string a = rn.Next(0, 9).ToString();
if (resultnum.Contains(a)!=true)
resultnum = resultnum + a;
}
while (resultnum.Length<5); style="color: rgb(0, 0, 255);">return resultnum;
}

Inmediatamente me dio curiosidad por ver que areas que podria mejorar, y me puse a escribir una funcion que obtuviera el mismo resultado, pero en forma mas optimizada

cosas que saltan a mi mente inmediatamente son:

  1. concatenacion de strings
  2. el loop y la comparacion para encontrar numeros que no tengamos previamente

Entonces lo que quise lograr en mi funcion es: evitar la concatenacion, y ejecutar el loop exactamente 5 veces, esto es el resultado:

static char[] allNumbers = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
Random r = new Random();
public string GetRandom2() {

char[] result = new char[5];
int max = 9, pos=0;
for (int i=1; i<6; pos =" r.Next(0," style="color: rgb(0, 128, 0);">//*** swap positions
allNumbers[pos] ^= allNumbers[max];
allNumbers[max] ^= allNumbers[pos];
allNumbers[pos] ^= allNumbers[max--];
}
return new string(result);
}

La tecnica que use,

- fue tener un arreglo predefinido de caracteres con todos los digitos,

- luego tengo una variable max que uso para llamar el metodo Random.Next(0, max),

- en cada iteracion del loop decremento esta variable,

- y cambio el numero que resulto elegido a la ultima posicion, con esto lo dejo fuera de las posibilidades para la siguiente llamada

Estos cambios me dieron una ganancia realmente minima (3 milesimas por cada 1000 llamadas), luego se me ocurrio mover la declaracion de la variable Random afuera de la funcion, para que se reusara con cada llamada a este metodo, y eso si que me dio una ganancia tremenda, llamando la funcion 10,000 veces, el metodo original me da 114ms, y el metodo nuevo 6ms, asi que ahi era donde estaba realmente el problema, lo demas es casi insignificante =o(

Seguro alguien mas puede crear una funcion mas rapida, pero yo cumpli mi objetivo =o)

salu2

Signo de que estas blogueando mucho: blog Deja Vu

Antonio Ganci nos platica (blog en italiano) que algunas veces cuando va a postear algo, le da la sensacion de que ya escribio eso antes en su blog, algo asi como blog Deja Vu, luego se pone a checar sus posts viejos, para cerciorarse que no lo habia escrito realmente

Se me hizo chistoso, personalmente aun no me ha pasado algo asi, pero probablemente le pasa a bastante gente en estos dias; el efecto Deja Vu me parece un tema muy interesante... y hace algunos dias fui a ver la pelicula Deja Vu, que se me hizo bastante buena, aunque creo que le encontre unos errores en la secuencia, pero haber ustedes que piensan

salu2

Como borrar elementos de una lista generica

El codigo para este articulo aplica a C# 2.0

Una tarea mas o menos comun cuando usamos una lista generica, es borrar elementos de esta, vamos a ver que alternativas tenemos:

#1 La forma definitivamente equivocada de hacerlo:

List<Person> l1 = GetList();
//*** The wrong way
foreach (Person p in l1) {
if (p.Age > 30)
l1.Remove(p);
}

Este codigo nos dara una excepcion InvalidOperationException: "Collection was modified; enumeration operation may not execute."

#2 Funciona mas o menos (y nos permite ejecutar una accion en cada elemento que vamos a borrar)

List<int> ints = new List<int>();
ints.Add(1);
ints.Add(2);
ints.Add(3);
ints.Add(4);
ints.Add(5);
ints.Add(6);

ints.ForEach(delegate(int i) {
if ((i % 2) == 0) {
Console.WriteLine("removing"+i.ToString());
ints.Remove(i);
}
});

Si corres este codigo funcionara perfectamente, pero la verdad es que tiene un problema grande, si agregaras los numeros pares primero, verias que no los borra todos, y no te da una excepcion ni nada, simplemente se sale del foreach y continua; asi que este metodo funciona, pero solo en condiciones especiales, lo cual lo hace codigo peligroso

#3 La forma correcta: recorremos la coleccion hacia atras y borramos elementos cuando necesitamos
int x = ints2.Count;
while (--x>=0) {
if (ints2[x] < 4)
ints2.RemoveAt(x);
}

#4 Una mejor manera: La lista generica trae un metodo ya incluido que nos sirve para borrar multiples elementos

ints2.RemoveAll(delegate(int i) {
return i <4;
});

#5 Pero que pasa si quiero ejecutar una accion en cada elemento que se borre?

ints2.RemoveAll(delegate(int i) {
if (i < 4) {
//*** Perform action here
Console.WriteLine("removing :" + i.ToString());
return true;
}
else
return false;
});


Si el elemento fuera una clase, podrias mandar llamar uno de sus metodos antes de borrarlo (por ejemplo una llamada a la base de datos)

Mas adelante escribire en detalle porque exactamente las alternativas #1 y #2 no funcionan

salu2

Monday, December 18, 2006

poner el focus en el campo UserName de un control ChangePassword

Estaba intentando todo tipo de cosas para poner el focus en el control UserName del control ChangePassword, resulta que es tan simple como:

if (!Page.IsPostBack)
ChangePasswordControl.Focus();

Funciona para el control Login tambien

if (!Page.IsPostBack)
LoginControl.Focus();

macros en el buen amigo DOS

Acabo de leer este post (por Jeffery Hicks?): Make an old friend do your work Donde explica como puedes usar el buen "doskey" para facilitarte la vida (en la linea de comando), y me motivo a escribir este post por 2 razones:

- Le faltaron un par de cosas
- Quiero recordar estos comandos, ya que parece que comienzo a olvidar cosas =o(

Vamos a ver, primero el define una macro asi:
doskey xl="%programfiles%\Microsoft Office\Office11\Excel.exe" $1 $2 $3 $4 $5

y explica "Puedes usar variables como $1 y $2 (hasta $9)".
Pero porque limitarnos con solo 9 parametros? puedes escribir la macro asi:
doskey xl="%programfiles%\Microsoft Office\Office11\Excel.exe" $*

Y tomara cualquier numero de parametros que le pases. Para probar que tomaba mas de 10 parametros cree un archivo 1.xls y luego corri este comando (muchisima gente no sabe de esta capacidad del CMD):

for /l %e in (2,1,11) do copy 1.xls %e.xls

Esa linea quiere decir algo asi como: un loop del 2 al 11, incrementos de 1, copia el archivo 1.xls a [variable].xls;
Ahora tengo 11 archivos para jugar, ahora llamo la macro:
xl 1 2 3 4 5 6 7 8 9 10 11

Lo cual nos lleva a otro punto que le falto: "de la linea de comando puedo escribirxl file1.xls file2.xls file3.xls y Excel abrira los 3 archivos"
Pues no tienes que especificar la extension, puedes pasar el nombre del archivo sin extension y Excel lo abrira sin problemas

Esto tambien nos lleva a otro punto: Si solo quieres abrir un solo archivo, solo tienes que escribir el nombre del archivo:
1.xls
Y Windows lo abrira usando la aplicacion asignada a ese tipo de archivo (Excel en este caso), asi que para archivos simples, no necesitamos la macro

finalmente, esta macro no funciona para Notepad (o Notepad2), si ejecutas
np 1.txt 2.txt
trata de abrir el archivo "1.txt 2.txt"

Asi que solo puedes abrir un archivo a la vez =o(

un ultimo truco, para borrar una macro, simplemente ejecutas
doskey myMacro=

salu2

Sunday, December 17, 2006

Como obtener todos los campos privados de otra clase

Hace casi 2 meses escribi unos articulos acerca del uso de refleccion, especificamente sobre como ejecutar metodos privados, alguien dejo una pregunta sobre como podria obtener todos los campos privados de una clase, apenas hoy me di tiempo para contestar aqui mismo en el blog; primero vamos a crear una clase de prueba

class TestClass {
private int prop1;

public int Prop1 {
get { return prop1; }
set { prop1 = value; }
}

private string prop2;

public string Prop2 {
get { return prop2; }
set { prop2 = value; }
}

private bool prop3;

public bool Prop3 {
get { return prop3; }
set { prop3 = value; }
}

public bool field4;

public TestClass() {
prop1 = 10;
prop2 = "20";
prop3 = false;
field4 = true;
}
}



luego creamos una instancia de esta clase, y utilizamos el metodo GetFields para obtener la lista de campos, pasando como parametros que queremos los campos privados que pertenezcan a una instancia (que no sean estaticos), una vez que tenemos la lista podemos hacer lo que queramos, en este caso imprimo el tipo del campo y el valor de este

TestClass test = new TestClass();
FieldInfo[] fields = test.GetType().GetFields(BindingFlags.NonPublic BindingFlags.Instance);
foreach (FieldInfo f in fields)
Console.WriteLine(string.Format("type:{0} \t value:{1}", f.FieldType.ToString(), f.GetValue(test)));




listo, eso es todo. Ahora solo para hacerlo un poquito mas interesante me puse a crear una funcion generica para realizar esta tarea y puede reutilizarse con cualquier otra clase:

static void PrintPrivateFields<T>(T theInstance) where T:class {
Type t = theInstance.GetType();
FieldInfo[] fields = t.GetFields(BindingFlags.NonPublic BindingFlags.Instance);
foreach (FieldInfo f in fields)
Console.WriteLine(string.Format("type:{0} \t value:{1}", f.FieldType.ToString(), f.GetValue(theInstance)));
}



para usarla simplemente creamos la instancia de la clase, y pasamos esta instancia a nuestra funcion:


TestClass test = new TestClass();


PrintPrivateFields(test);


noten que no necesito pasarle el tipo generico asi


PrintPrivateFields<TestClass>(test);


sino que el compilador es inteligente y puede derivar el tipo generico.


Espero les sea util, el codigo completo lo encuentran aqui, salu2

Termine de navegar "El Internet"

From tecblog

O dicho de otra manera, por fin termine de leer todos los blogs que tenia pendientes!, la cosa es que he estado enfermo y bastante ocupado este ultimo mes, lo cual tambien ha sido la razon de que no he escrito mucho en mi blog. Pero los escritores de los blogs que leo no me dan descanso, apenas si me paso 2 dias sin leer blogs y me atrazo bastante; aqui les dejo una lista de los posts que me han parecido mas interesantes (de los 266 blogs a los que estoy subscrito), tratare de incluir los links interesantes en español en algun lado en esta pagina, creo que en el link que les dejo todo es en ingles =o(
Posts interesantes

Friday, December 15, 2006

Como instalar Visual Studio SP1 en menos de una hora

La noticia de que el Service Pack 1 para Visual Studio esta listo anda por todos los blogs, pero hay un problemita, estan reportando que se tarda muchisimo para instalar (mas de 2 horas), yo lo que hice es que cerre todos los programas de windows y esta lista de servicios:

- Print Spooler
- Tu programa antivirus, ej. yo tengo: "Symantec Antivirus Client"
- Task Scheduler
- TCP/IP NetBIOS Helper Service
- VNC Server
- IIS Admin Service (junto con los otros servicios que dependen de este)
- MSSQL* (Puede haber varios de estos, yo los apagaria todos)
- cualquier otro servicio que reconozcan y que puedan apagar sabiendo que no va a afectar nada (sincronizador de PDA, etc)

y listo, la instalacion completa salio como en media hora, ojala que esto le sirva a alguien
salu2

Actualizacion: en mi maquina vieja (que le acabo de instalar Windows Vista) la actualizacion de Visual Studio me tomo solo 20 minutos =o) siguiendo mi simple recomendacion

Monday, December 11, 2006

Tour Juarez-Chihuahua 2006

Pues es esa temporada del año en la que tengo la oportunidad de regresar a visitar a la familia y amigos por alla en mi tierra, voy a estar en Juarez y Chihuahua (y Cuauhtemoc talvez 1 o 2 dias) entre el 23 de Diciembre y el 1 de Enero, si alguien esta interesado en tener una cena geek, platicar o lo que sea, dejenme un comentario y ahi nos arreglamos

salu2

Saturday, December 09, 2006

Windows is unable to find a system volume that meets its criteria for installation

Tuve algunos problemitas (bueno, realmente solo uno, el error mencionado en el titulo) instalando Windows Vista en mi maquina vieja ( hey, mi maquina ya tiene mas de un año... y hey!, ya tengo mas de un año en esto del blog!!)... en que estaba, ah si, lo del mensaje ese de error, pues por mas que trataba, seguia recibiendo ese mensaje al tratar de instalar Vista en cualquiera de las (3) particiones de mi disco SATA, borre particiones, las formatee, las recree, nada funcionaba. Por supuesto anduve buscando informacion acerca de este problema, y lo mejorcito que encontre fue una respuesta en un foro "Vista debe ser instalado en la particion activa", y eso que se supone que quiere decir???

En un ultimo y desesperado intento, desconecte el otro disco duro (que no mencione antes =o) ), dejando solo el disco SATA conectado, corri la instalacion y voila!, era todo lo que necesitaba, la instalacion corrio sin ningun problema despues de eso, y todo esta funcionando perfectamente hasta ahorita, creo que hasta Internet Explorer 7 me gusta mucho mas en Vista, y esto de los efectos Aero Glass esta chido chido chido!

Aqui esta una lista de teclas de rapido acceso para aquellos de ustedes que sean nuevos usando Vista (no halle un link en español =o(... tendre que poner una recopilacion aqui pues =o))

Y pues espero que mi experiencia le sea de ayuda a alguno, ahora si me disculpan tengo que ir a jugar, siguiente paso: Office 2007

Thursday, December 07, 2006

Wednesday, December 06, 2006

Comandos de Novell para recordar

Yo "creci" usando servidores Novell y DOS, recuerdo que era bastante bueno para administrar servidores Novell, pero hace un buen que no toco un servidor de estos; ayer unos colegas estaban teniendo problemas con uno de estos servidores y me hablaron para pedirme ayuda, y yo no me podia acordar de esos comandos, asi que este post es para guardar en mi memoria digital esos comandos para en caso de que se me ofrezca despues, y talvez tambien tu eres bien suertudo y los puedas usar algun dia

Comandos para el servidor

  • server - En un prompt de DOS, inicia el servidor
  • restart server - resetear el servidor pues
  • VRepair - Usalo para corregir problemas con los volumenes (no puedes usar vrepair en un volumen montado)
  • enable/disable login - para que los usuarios no nos molesten
  • mount/dismount - poner un volumen disponible a los usuarios (mount all para montar todos los volumenes)
  • volume - obtener una lista de volumenes montados, o la informacion acerca de un volumen en particular (parametro)
  • down - bajar el servidor (amablemente)
  • load/unload monitor - cargar/descargar el monitor (para administrar el servidor con un bonito UI)
  • tcpcon - un bonito monitor con bastante informacion sobre TCP y otros protocolos de red
  • display environment/processors/servers/networks / modified environments / interrupts -
  • list devices - obtener una lista de dispositivos de almacenamiento (discos duros, cd-rom, etc)
  • memory - muestra el total de memoria instalada a la cual el sistema operativo tiene acceso
  • mirror status - ver el estado de las particiones de disco espejeadas(???), ver el porcentaje de datos espejeados en cada particion
  • modules - obtener una lista de los modulos cargados

Commands para las maquinas de usuario

  • attach - connectar a otro servidor, pero mantenerse conectado al servidor actual
  • caston/castoff - habilita mensajes de la red de otras maquinas de usuario y del servidor si se usa la opcion ALL
  • chkvol - muestra informacion del volumen, espacio libre, uso, archivos borrados, etc
  • login/logout - pues eso mismo...
  • rights - muestra los derechos para archivos y directorios
  • rconsole - consola remota, para controlar el servidor desde un cliente; si el servidor no se especifica, nos muestra una lista
  • purge - remover archivos (previamente borrados) permanentemente, archivos purgados no pueden ser recuperados
  • slist - lista de servidores
  • syscon - administrar usuarios, grupos, derechos, etc
salu2

Tuesday, December 05, 2006

Haz estado usando patrones de diseño desde hace tiempo...

Por ejemplo aqui esta este, llamado Composed method:
Divide tu programa en metodos que realizan una tarea identificable. Manten todas las operaciones de un metodo al mismo nivel de abstraccion. Esto resultara naturalmente en programas con muchos metodos pequeños, cada uno con pocas lineas de codigo.
Es tan simple como extraer codigo de metodos grandes, y crear metodos mas pequeños, algo que haces todos los dias que programas algo, hay muchos patrones simples como este, lo unico que hacen es describir (con un nombre corto) las tareas que realizas diariamente.

La idea es que conociendo estos patrones por nombre, te puedes comunicar mucho mas rapido, facil y mejor, y usandolos te conviertes en un programador mas educado, un mejor desarrollador; recuerda que un gran desarrollador es aquel que no solo escribe codigo increiblemente eficiente, sino que ademas es capaz de comunicar ideas y trabajar en equipo.

"El mejor codigo en el mundo no tiene sentido si nadie sabe acerca de tu producto."

Asi que como ves, ya has estado usando patrones de diseño desde que estas programando, ahora aprendete los nombres de estos, aprende mas patrones, usalos y educa a tu equipo (tambien a compañeros, lectores de tu blog, etc) sobre estos.

Ademas de todo lo anterior, tambien aprendes mas tu al enseñar a los demas.

salu2

Monday, December 04, 2006

si eres talentoso, las herramientas no importan tanto

Este es el primer post usando blogger beta, haber que tal... mientras chequense este chavo, lo que puede hacer usando solamente Paint

Sunday, December 03, 2006

trucos css: encabezado, pie de pagina y area principal cubriendo 100% del documento

En los viejos tiempo (no hace ni tanto) yo empezaba una pagina con una table html con 3 rows, uno para el encabezado, uno para el area principal (al 100% de tamaño) y uno para el footer

En estos dias esto ya no funciona, y ademas nos dicen que debemos usar CSS puro, que nada de html y no se que... pero como logramos esto con puro CSS?

Vamos a necesitar algo de CSS y un poco de javascript, primero vamos a ver el CSS

html,body,form
{
margin:0;
padding:0;
}//prevent some default spacing on some browsers
.header
{
text-align:center;
background-color:Navy;
color:White;
width:100%;
}
.footer
{
background-color:Orange;
color:Navy;
position:absolute;
bottom:0;
border:0;
}
div.scrollable{
overflow:auto;
border-left-width:0px;
border-bottom-width:0px;
border-top-width:0px;
border-right-width:0px;
background-color:Gray;
color:White;
position:absolute;
}

Lo mas interesante es la clase div.scrollable; la propiedad overflow:auto hace que el DIV sea scrollable, y el resto es para eliminar los border y poner algo de color.

Ahora vamos a ver el html:

<html>
<head>
</head>
<link rel="stylesheet" type="text/css" href="test.css" />
<body>

<div>
<div id="header" class="header" height="20px">
This is the header
</div>

<div id="mainDiv" class="scrollable">
This is the main body<br>
There is a lot of stuff in the main
<br><br><br><br><br><br><br><br><br><br>
There is a lot of stuff in the main
<br><br><br><br><br><br><br><br><br><br>
There is a lot of stuff in the main
<br><br><br><br><br><br><br><br><br><br>
There is a lot of stuff in the main
<br><br><br><br><br><br><br><br><br><br>
There is a lot of stuff in the main
<br>
<br><br><br>
This is the last line
</div>

<div id="footer" class="footer" height="20px">
<div style="float:left">This is a div on the left</div>
<div style="float:right">This is a div on the right</div>
</div>

</div>

</body>
</html>

A proposito he puesto muchas lineas en la seccion media, para que se pueda apreciar que el documento hace scrolling (solo en la parte de enmedio, el header y footer siempre se quedan en su lugar). Tambien como un "bono" puse 2 divs en el footer, uno alineado a la izquierda y otro a la derecha, ambos a la misma altura, ya que me he dado cuenta que esta es una de las cosas que mucha gente batalla para lograr. Ya mero terminamos, solo necesitamos un poco de Javascript:

var mainDivHeight;
var mainDivWidth;

function AdjustFullSize() {
var screenHeight = 450;
var screenWidth = 610;

if (window.innerHeight) {
screenHeight = window.innerHeight;
screenWidth = window.innerWidth;
}
else if (document.body) {
screenHeight = document.body.clientHeight;
screenWidth = document.body.clientWidth;
}

mainDivHeight = screenHeight - 20 - 20; //20+20 for header and footer
mainDivWidth = screenWidth - 0;

document.getElementById('mainDiv').style.height = mainDivHeight + 'px';
document.getElementById('mainDiv').style.width = mainDivWidth + 'px';
}

Diferentes browsers tienen diferentes propiedades para accesar el tamaño del documento, asi que nos encargamos de eso y luego asignamos el tamaño al maindiv que es nuestra area principal, mandamos llamar esta funcion en el "onload" (y tambien en el onresize!) y listo, el resultado final es este, puedes obtener el codigo completo de ahi, espero que les sea util.

salu2

Wednesday, November 29, 2006

dos chequeos en uno usando bool.TryParse

Me acabo de encontrar un codigo mas o menos asi:

bool b = bool.TryParse(ConfigurationManager.AppSettings["SomeSetting"].ToString(), out b);

Pueden ignorar el hecho de que no estoy checando valores NULL en el appsettings.

A primera vista pense que era un bug, pero luego leyendo la documentacion, escribi un pequeña prueba y algo de investigacion usando Reflector, resulta que hace exactamente lo que necesitaba

bool.TryParse no regresa el valor que resulta de la conversion del string que le pasamos; sino que regresa true o false, indicando si la conversion se realizo exitosamente, el valor de la conversion se regresa en el parametro out (que es la misma variable en este caso). Asi que la unica forma de regresar true es

  • Que la conversion se realize exitosamente
  • Que el valor sea true

Asi que ya no necesito hacer 2 chequeos

if (bool.TryParse(someVariable, out b))

  if (b)...

...De esas pequeñas pero peligrosas lineas de codigo que luego nos muerden...

Monday, November 27, 2006

Impulsando las bitacoras en español

Creo que sería interesante ver como nuestro ranking crece en Google y cualquier buscador de blogs. Para ello es que se creó GoMeme 4.0. Parece además interesante que cada bloggero en el círculo de UBH, se adhiera al proyecto y ayude a que su propio blog sea mas visible a las máquinas de búsqueda, no por el simple link, sino porla múltiple interrelación entre los enlaces que se generan gracias a todos aquellos que entran en el ‘juego’. Fervientemente los invito a continuar y a ayudarnos en el experimento, porque éste nos es un artículo ordinario. Se ha agregado información especial al final. Lea el artículo completamente y trate de seguir las instrucciones para su debida propagación.

La fuente siempre merece el crédito.Por qué no continuamos los enlacen en español?

NOTA: Asegúrese de agregar links reales en el listado de abajo.

Por ahora se estima que existen más de un millon de bitácoras. Pero la mayoria de ellas no son visibles para los robots de búsqueda. Solo algunas “A-List” bitácoras aparecen a la cabeza en los resultados mostrados para un determinado tópico, mientras que la mayoria de las bitácoras ni siquiera son identificados. La razón es que las bitácoras más pequeñas no tienen suficientes enlaces(links) que se dirijan a ellos mismo. Pero este post podria solucionar eso!. Ayudemos a que las bitácoras más pequeñas sean más visibles a las maquinas de búsqueda!

El post aunque esta en Inglés es GoMeme 4.0. Esto es parte de un experimento para ver si nosotros podemos crear un post que ayude a 1000 bitácoras, a obtener posicionamientos mas altos en Google. Hasta ahora hemos tratado tres primeras variaciones. Nuestro primera prueba, GoMeme 1.0, se difundió a cerca de 740 bitácoras en dos y medio dias. Esta nueva version 4.0 es mas corta, mas simple, y encaja mas fácilmente dentro de tu bitácora.

Por qué estamos haciendo esto? Queremos ayudar a que miles de bitácoras obtengan mayor visibilidad en Google y otras máquinas de búsqueda. Cómo funciona? Solo sigue las instrucciones de abajo y republica este post en tu propia bitácora y agrega tu URL al final de la lista mostrada abajo. De la misma manera que este “meme” se propague en forma progresiva desde tu bitácora, asi mismo lo hará tu URL. Mas tarde, cuando tu bitácora sea puesta enlistada en las máquinas de búsqueda, ellas verán los enlaces apuntando hacia tu bitácora desde todo ese flujo de bitácoras que se enlazaron a través de ti, lo cual hará que ubiquen tu bitácora en una posicion superior cuando se muestren los resultados. Todos los que estan en la lista de abajo se beneficiarán en forma similar cuando este “meme” se difunda. Únete!

Instrucciones: Copia y pega este post completamente en un post de tu bitácora. A continuación agrega tu URL al final de la lista, y continúa la cadena!

Lista de Origen

1. Memes en español
2. Madurando con sentido
3. Cavaju
4. Momentanea
5. Imagenes de un talibano
6. MordorBlog
7. El oso
8. Sin imprenta
9. ALT1040
10. WR276
11. El Ecuador de hoy
12. Juan Javier
13. kevinhurlt
14. metablog
15. Mi mundo
16. Derrames intelectuales
17. Fatima Protesta
18. Erebe
19. Calú
20. Alex Vera
Mas enlaces
21. Bloggus
22. DeVilSoulBlack
23. Solo dehajo ser
24. Cero Cuatro
25. Enfoque de usuario
26. Jesús Nieves Montero
27. Gandika
28. El Catalejo
29. Curioseando
30. El especialista
31. Victor Solano
32. Alvaro Sanchez
33. A veces hace falta
34. Un mundo de ideas
35. Ciberescrituras
36. Cuarenton
37. Not etra be
38. Blogófago
39. Urbe y existencia
40. Blogpocket
41. eCuaderno
42. El ventanuco
43. Opiniones
44. Si puedo
45. El arbol de Diana
46. Desarrollo en la red
47. Sergio Rastafurbi
48. Hipótesis21
49. Con valor
50. My Space
51. Un poco de cada
52. Rufadas
53. La paradoja posible
54. Oabareload
55. Territorio enemigo
56. Hachemuda
57. il Maistro
58. Apocalypsofacto
59. Cladestinidad Pedagógica
60. Methos 189
61. Colombia Hoy
62. Redtales
63. Alambre
64. Domingo 1967
65. Veo y pienso
66.Union de Bloggers Hispanos
67.Celica
68.Netcódigo e Internet
69.AlexSanhz Blog
70.Negocios e Internet en Hispanoamérica
71.Aspirar la cultura
72.Recuerdos Inútiles
73.K-minos
74.…Y otras escusas para conocerte
75.Ursula Zabaleta
76.Anime-Tronic
77.Carballada
78.Magabe
79.El Mar de las Tormentas
80.Poeta Multimedia
81.agaponeo´s
82.Venezuela descubierta
83.Marujeitor
84.De todo un poco de aqui y de allá
85.equinoXio
86.Cartas de Miramar(Original cartas de Cuba)
87.Blog and Roll
88.De la vida y algo más
89.True Blog en Espaniol
90.Globalizado
91.El Útero de Marita
92.El que nace pa martillo
93.El Blog de Paki
94.All Cuzco
95.Moebius
96.Blog-o-Corp
97.Magazín Oscarín
98.Seguridad en línea
99.Semiótica
100.Lino Resende
101.Any way you want it
102.La Maldición de Sisifo
103.Otro día trabajando
104.El geek
105.Area 303
106.El blog de rianvanu
107.Detrás del viento norte
108.14 de Abril
109.En sus narices
110.http://zeitan.blogsome.com/go.php?http://www.lacoctelera.com/tazzie
111.Erotízate
112.Tijuana
113.Miralmundo
114.La nueva historia
115.Que tiro
116.Simplemente un voyeur
117.Chiara
118.Sin nombre fijo
119.Energy Blog
120.Compartiendo
121.Reflexologia Podal
122.Geomujer XXI
123.Laberinto de Pasiones
124.El blog del Cowboy
125.Historias Intimas Subtropicales
126.El Blog de la Bruja
127.Hispanos por la Causa
128.Santuario Atziluth
129.G3nergy
130.12 de septiembre
131.Lamerse el codo
132.Patton en el país del sagrado corazón
133.Apodérate
134.Los 80´s
135.Ejemplos Liberales para gente de Izquierdas
136.Quo vadis?
137.Iveldie, cine independiente y de terror
138.Sin Miedo
139.Mario House
140.Mi rincón favorito
141.Aquellos años dorados
142.Barrio Los Rosales de La Coruña
143.Crónicas de Zeitán
144.El Blog de Percy Reyes™ : Evolucionando [Geeks.ms]

145.Que quieres desarrollar hoy?

146.(Tu URL va aquí! Pero primeramente, por favor copia esta linea y múevela un espacio hacia abajo para que sea usada por la proxima persona)

Thursday, November 09, 2006

Reusando codigo, siguiente nivel

El codigo para este articlo esta escrito en C# (probado en VS2005)

Hace algunos dias (mientras andaba de vacaciones) lei un articulo en latindevelopers: Ordenando objetos con IComparer; el cual me recordo un error muy comun que cometen muchos programadores: usar sentencias condicionales dentro de (no muy obvios) ciclos (por ejemplo en callbacks o eventos paint) lo cual resulta en un tipo de (no muy obvio) codigo duplicado.

En Delphi encontramos este error muy comunmente en el desarrollo de componentes, especificamente en el evento Paint donde usan sentencias "if" para decidir que font usar, colores, etc. y lo que es peor, muchas veces crean una instancia (de las clases que se necesitan) en cada iteracion; por supuesto, todos esos objetos no cambian, a menos que cambies una propiedad del componente!!, por lo cual esos objetos deberian ser "cacheados" (cached) y mantenerlos en variables donde simplemente se puedan reusar; asi es, reusar codigo no significa solamente re-usar clases, o partir el codigo en metodos mas pequeños para hacerlos reusables, cachear objetos puede ser una forma de reusar codigo ya que nos evita sentencias condicionales y las reemplaza con llamadas directas al codigo que requerimos.

Vamos a ver el codigo del ejemplo original, especificamente la clase PersonComparer, esta tiene un constructor que toma un parametro SortField y lo guarda en un campo que se usa despues en el metodo Compare

public PersonComparer(SortField sortField) {
this.sortField = sortField;
}
public int Compare(object x, object y) {
if (!((x is Person) & (y is Person))) {
throw new
ArgumentException("Los objetos deben ser de tipo Person.");
}

switch (sortField) {
case SortField.Name:
return
Comparer.DefaultInvariant.Compare(
((Person)x).Name, ((Person)y).Name);

case SortField.LastName:
return
Comparer.DefaultInvariant.Compare(
((Person)x).LastName, ((Person)y).LastName);

case SortField.Age:
return
((Person)x).Age - ((Person)y).Age;

default:
throw new
ArgumentException("Tipo de ordenamiento desconocido.");
}
}

Talvez no es tan facil verlo aqui porque el ejemplo no usa genericos, vamos a ver que podemos hacer usando genericos (si hay un tipo TimeZone2 en el .NET framework, porque no puedo yo escribir una clase PersonCompare2? =oP)

    public class PersonComparer2<T> : System.Collections.Generic.IComparer<T> where T:Person {
delegate int ComparerDelegate(T x, T y);
ComparerDelegate comparerDelegate;

Ahora tenemos la declaracion de un delegado, una variable de ese tipo, y eliminamos la variable del tipo SortField, vamos a ver el constructor:

public PersonComparer2(SortField sortField) {
switch (sortField) {
case SortField.Name:
comparerDelegate = delegate(T x, T y) {
return x.Name.CompareTo(y.Name);
};
break;
case SortField.LastName:
comparerDelegate = delegate(T x, T y) {
return x.LastName.CompareTo(y.LastName);
};
break;
case SortField.Age:
comparerDelegate = delegate(T x, T y) {
return x.Age - y.Age;
};
break;
default:
throw new
ArgumentException("Tipo de ordenamiento desconocido");
}
}

En vez de cachear la variable SortField, aqui estoy cacheando el metodo que se ejecutara cuando la comparacion se lleve a cabo; finalmente, vamos a ver el metodo Compare:

public int Compare(T x, T y) {
return comparerDelegate(x, y);
}

Puedes ver el beneficio? (si quieres ve una pagina arriba para que veas el codigo original) la decision de que metodo usar para la comparacion se ejecuta solo una vez (en el constructor), y ya despues podemos usarlo directamente, en vez de hacer la misma pregunta una y otra vez en cada iteracion.


Cada vez que veas una sentencia condicional dentro de un ciclo o un metodo que se ejecute en algun tipo de loop (como eventos Paint, callback, etc) considera usar esta tecnica, te ayudara a construir codigo mucho mas estructurado y mas rapido, tambien considera usar arreglos o diccionarios de metodos para reemplazar tus sentencias condicionales.


El concepto aplica a programacion en general, pero la implementacion puede variar (bastante) de un lenguage a otro, la idea principal es cachear objetos / metodos de alguna manera que no tengas que repetir sentencias condicionales para crear objetos o decidir que bloque de codigo ejecutar.


El codigo completo (junto con el codigo original) lo puedes encontrar aqui, como siempre, juega con el, aprende de el, y mejoralo

Sunday, October 29, 2006

Como instanciar una clase que tenga un constructor privado

Este articulo aplica a C# (probado en VS2005)

Hace poco hablaba sobre como podemos ejecutar metodos privados (de otra clase) usando refleccion; parece que no mucha gente esta enterada de que se puede hacer esto y siempre genera todo tipo de comentarios. Pues aqui les tengo otra para ustedes, tambien podemos crear una instancia de una clase, aun si los constructores de esta son privados.

Aqui estoy incluyendo un ejemplo para un constructor privado, un protegido y un (normal) publico, todos ellos usando refleccion.

Vamos a crear una clase para poder jugar:

public class TestClass {
private TestClass() {
Console.WriteLine("private TestClass constructor");
}
protected TestClass(int i) {
Console.WriteLine(string.Format("protected TestClass constructor (int:{0})", i));
}
public TestClass(string s) {
Console.WriteLine(string.Format("public TestClass constructor (string:{0})", s));
}
}

Ahora vamos a ver que facil es crear instancias de esta clase usando cualquiera de sus constructores, sin importar su visibilidad:


- Para este codigo necesitas incluir System.Reflection en el uses.


El primero es un constructor privado simple que no tiene ningun parametro, no se requiere mucho para este

//*** Private constructor
ConstructorInfo ci1 = typeof(TestClass).GetConstructor(
//*** Non public and instance (non static) constructor
BindingFlags.NonPublic | BindingFlags.Instance,
//*** No binder, no parameters, so no parameter modifiers
null, new Type[0], new ParameterModifier[0]);
//*** Call our constructor
TestClass tc1 = (TestClass)ci1.Invoke(new object[0]);

El segundo es protected (aun cuenta como "no publico"), aqui inclui un parametro asi que tenemos que pasarle el tipo del parametro

//*** Protected constructor
ConstructorInfo ci2 = typeof(TestClass).GetConstructor(
//*** non public and instance (non static) constructor
BindingFlags.NonPublic | BindingFlags.Instance,
//*** no binder, 1 parameter of type int, no modifiers for the param
null, new Type[1] { typeof(int) }, new ParameterModifier[0]);
//*** Call our constructor
TestClass tc2 = (TestClass)ci2.Invoke(new object[1] { 10 });

El tercero es publico, asi que podriamos crear la instancia sin tener que usar el metodo de refleccion, pero le deje aqui solo como ejemplo

//*** Public constructor
ConstructorInfo ci3 = typeof(TestClass).GetConstructor(
//*** public and instance method
BindingFlags.Public | BindingFlags.Instance,
//*** no binder, 1 parameter of type string, no parameter modifiers
null, new Type[1] { typeof(string) }, new ParameterModifier[0]);
//*** Call our constructor
TestClass tc3 = (TestClass)ci3.Invoke(new object[1] { "test" });

Eso es todo, asi de sencillo; esta tecnica realmente es muy raro que la tengamos que utilizar, mas que todo me interesa que sepan que es posible y cuan facil es lograrlo


Uno podria incluso combinar los flags: BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance y podriamos crear la instancia de la clase sin importar si esta fuera private, protected o public (por ejemplo en el caso de que cargaramos un assembly dinamicamente y solo nos interesara que la clase estuviera ahi)


Pueden encontrar el codigo completo aqui,


por cierto, en estos momentos estoy en Guadalajara, estare aqui hasta el martes y luego voy a Tulancingo Hidalgo y de ahi a Aguascalientes, si alguien esta interesado en echar una platicada o ir a cenar aqui estamos a la orden


salu2 

Thursday, October 26, 2006

curiosidades en Javascript

Me encontre esto en el blog de Javi Moya's

1. Resalten el texto de aquí abajo (marquenlo completamente)
2. Pulsen Ctrl+C (para copiarlo al portapapeles)
3. Pulsen Alt+D (o vaya a la barra de direcciones del navegador)
4. Pulsen Ctrl+V (para pegar el código javascript)
5. Pulsen Enter

javascript:scroll(0,0); R=0; x1=.1; y1=.05; x2=.25; y2=.24; x3=1.6; y3=.24; x4=300; y4=200; x5=300; y5=200; DI=document.getElementsByTagName("img"); DIL=DI.length; function A(){for(i=0; i-DIL; i++){DIS=DI[ i ].style; DIS.position='absolute'; DIS.left=(Math.sin(R*x1+i*x2+x3)*x4+x5)+"px"; DIS.top=(Math.cos(R*y1+i*y2+y3)*y4+y5)+"px"}R++}setInterval('A()',5); void(0);

6. Puedes navegar a otros sitios y pegar el codigo en la barra de direccion 

7. Aun mejor en sitios que tienen muchas imagenes 

8. No andes por ahi navegando en sitios copiando y pegando javascript en tu barra de direccion! =oP

Caracteres de escape para usar palabras reservadas como nombres de variables en .NET

Este articulo es en referencia al articulo de Jean-Paul: Nombrando variables usando el tipo de la variable como nombre (truco inservible #1).(articulo en ingles)

Pues bien, resulta que el truco no es tan inservible, solo tenemos que ver mas alla de nuestra nariz.

en la documentacion MSDN en español (que creo que mucha gente todavia no sabe de este gran recurso) encontramos el siguiente texto:

Las palabras clave son identificadores predefinidos reservados que tienen un significado especial para el compilador. No se pueden utilizar como identificadores en un programa a menos que incluyan el carácter @ como prefijo. Por ejemplo, @if es un identificador válido pero if no, por ser una palabra clave.

.NET vino a resolver lo que era uno de los problemas mas grandes en el area de desarrolo, esto es (o era) el poder interactuar facilmente con codigo escrito en otro lenguaje, esto se resuelve en .NET porque los compiladores convierten el codigo a Lenguaje Intermedio.

Hoy en dia uno puede escribir codigo en cualquier lenguaje de .NET y usar el codigo (las librerias generadas) en cualquier otro lenguaje de .NET; esto crea un problema, ya que las palabras reservadas en un lenguaje pueden (y muchas veces es asi) no significar nada en otro lenguaje, por ejemplo podrias estar programando en C# y usar una variable begin, la cual es una palabra reservada en Delphi, y entonces cuando alguien quisiera usar tu codigo C# desde Delphi, no podrian; para resolver este problema los lenguajes deben (para su propio "bienestar") implementar algun tipo de caracter de escape que permita usar palabras reservadas como nombres de variables en caso de que estes usando codigo escrito en otro lenguaje en el que hallan declarado una variable con el nombre de una palabra reservada en el lenguaje que estas usando (uff, no se si se entendio esto)

en C# usamos el prefijo @

string @while = "something"
Console.WriteLine(@while);

en Delphi usamos el prefijo &

&begin:Integer;
begin
  &begin := 10;
  Console.WriteLine(&begin);

en VB.NET encerramos la palabra reservada en brackets

Dim [Dim] = 20
Console.WriteLine([Dim])

obviamente (es una de las primeras cosas que se aprenden) uno no usa palabras reservadas como nombres de variables cuando estas en el lenguaje mismo, pero si tienen un uso valido cuando empezamos a interactuar con codigo escrito en otros lenguajes, si no tuvieramos esos caracteres de escape, mucho codigo no funcionaria

Si alguien sabe de los caracteres de escape para otros lenguajes de .NET dejenme un comentario para actualizar el articulo

p.d. despues de escribir esto, me encontre con que Jeff les llama escaped identifiers

Monday, October 23, 2006

Como ejecutar metodos privados de otra clase

Este articulo aplica a C# (probado en C# 2.0)

De acuerdo a la documentacion de MSDN el modificador de acceso private es el nivel de acceso mas restrictivo (acceso es limitado solo al tipo que contiene dicho miembro)

De vez en cuando quisieramos poder accesar un metodo privado en alguna clase para la cual no tenemos el codigo fuente, generalmente no deberiamos tener que hacer esto, pero pues en caso de que se ofrezca, esta es una manera de lograrlo:

primero que nada, tenemos una clase para nuestro ejemplo:

public class TestClass {
public TestClass() {
}
private void HiddenMethod() {
Console.WriteLine("secret method, should only be called from the containing class itself");
}
private string HiddenMethodWithParams(string firstName, int age) {
return string.Format("hello {0}, you are {1} years old", firstName, age);
}
}

basicamente esta clase no sirve de nada, porque no expone ningun metodo que podamos usar... a menos que tengamos acceso a los metodos privados (aun asi no sirve de nada, pero esto es solo un ejemplo =oP ):


Ahora vamos a ver como accesar los metodos privados

TestClass tc = new TestClass();
Type testClaseType = typeof(TestClass);

MethodInfo hiddenMethod =
testClaseType.GetMethod("HiddenMethod",
BindingFlags.NonPublic | BindingFlags.Instance);
hiddenMethod.Invoke(tc, null);

MethodInfo hiddenMethodWithParams =
testClaseType.GetMethod("HiddenMethodWithParams",
BindingFlags.NonPublic | BindingFlags.Instance,
null, new Type[2] { typeof(string), typeof(int) }, null);
string result = (string)hiddenMethodWithParams.Invoke(tc, new object[2] { "Eber", 25 });
Console.WriteLine("result: "+ result);

Console.Read();

vamos a ver:



  1. la primera linea simplemente crea una instancia (tc) de la clase que contiene los metodos en los que estamos interesados

  2. la segunda linea obtiene el tipo de la clase, que en este caso seria TestClass, esta variable nos servira para preguntarle informacion sobre los metodos que se encuentran en ella.

  3. luego viene lo interesante, adquirir un puntero hacia la funcion privada "HiddenMethod", los parametros BindingFlags.NonPublic y BindingFlags.Instance quieren decir: quiero un metodo no-publico (osease privado en este ejemplo), que sea un metodo proveniente de una instancia (lo opuesto de este ultimo seria estatico, ya que los metodos estaticos no se ejecutan de una instancia, sino llamandolos directamente)

  4. acto seguido, ya que tenemos un puntero a esta funcion, solo queda mandarla llamar, esto lo hacemos ejecutando el metodo Invoke, y pasando tc, la cual es la instancia en la cual se va a ejecutar el metodo (tc fue la instancia creada en la primer linea)

Basicamente eso es todo lo que hay que hacer, pero claro que una funcion que no regrese nada y que no acepte parametros pocas veces es util, asi que inclui tambien un ejemplo de llamar un metodo el cual acepta parametros y regresa algo.


Lo unico que tenemos que agregar para hacer que esta funcione, es lo siguiente:


en el paso 3, al obtener el puntero hacia el metodo que queremos ejecutar, necesitamos pasar informacion sobre los tipos de datos de los parametros de la funcion, esos datos los pasamos un arreglo; si te vas hasta arriba a ver la declaracion del metodo HiddenMethodWithParams, veras que acepta 2 parametros, un string y un int, ahora de regreso aca, eso lo especificamos asi:


new Type[2] { typeof(string), typeof(int) }


Lo cual quiere decir: 2 parametros, el primero es un string, el segundo un int


Por supuesto, podemos pasar cualquier tipo de parametro


Ahora ya tenemos el puntero al metodo que necesitamos, pero como este metodo regresa algo, pues tambien tenemos que cambiar la forma en como lo mandamos llamar:


string result = (string)hiddenMethodWithParams.Invoke(tc, new object[2] { "Eber", 25 });


aqui creamos una variable para guardar el resultado, luego mandamos llamar el metodo, haciendole una conversion al tipo de datos que sabemos que regresa (string), el parametro tc sigue igual, recuerda que ese es la instancia en la cual se esta ejecutando el metodo, por ultimo tenemos que pasar los parametros a la funcion, la manera de hacerlo es muy similar a la forma en la que le definimos el tipo de datos de los mismos


new object[2] { "Eber", 25 }


que se traduce a: 2 parametros, el primero es "Eber", el segundo es:25


Señores (y señoritas) eso todo por hoy; no abusen de esta tecnica! el codigo completo lo encuentran aqui

Como obtener el primer y ultimo elemento de un Enum

Este articulo aplica a C# 2.0

Hay veces que tenemos un tipo enumeracion y queremos asegurarnos que cierto parametro esta dentro del rango de nuestra enumeracion, la gran mayoria del codigo que he visto checa haber si X valor es mayor al ultimo elemento de la enumeracion, algo asi:

enum TestEnum {

  Enum1 = 1, Enum2 = 2, Enum3 = 3;

}

TestEnum myValue; //generalmente esto pasa cuando esta variable viene como parametro a una funcion

if (myValue > TestEnum.Enum3) //algun codigo para manejar este problema

y cada vez que tuvieran que actualizar la enumeracion tendrian que modificar esta parte del codigo.

Esta funcion nos regresa el primer y ultimo elemento de un tipo Enum, la escribi de forma generica para que pueda ser usada con cualquier tipo enum, pero podrian modificarla para ser para un tipo especifico y se podria usar en C# 1.0 (VS2003), creo que el uso seria raro pero pues aqui esta para cuando se ofrezca

public void GetLowHighFromEnum<T>(out T lowElement, out T highElement) {
if (!typeof(T).IsSubclassOf(typeof(Enum))) //make sure we got an Enum
throw new ArgumentException("parameterized type should be Enum");
T[] values = (T[])Enum.GetValues(typeof(T));
lowElement = values[0];
highElement = values[values.Length - 1];
}

para usarla seria algo mas o menos asi

TestEnum te1, te2;
GetLowHighFromEnum<TestEnum>(out te1, out te2);
Console.WriteLine(te1.ToString());
Console.WriteLine(te2.ToString());

Sunday, October 22, 2006

Es posible convertir cualquier valor entero a un tipo Enum, aun si el valor entero esta fuera de los valores definidos en tu Enum

Este articulo aplica a C# (probado en C# 2.0 (VS2005))

Pues si, casi se los cuento todo en el titulo, pero asi es, ultimamente he estado investigando bastante sobre Enums y he encontrado unas cosillas muy interesantes, esta es una de ellas; por ejemplo este codigo es valido y se ejecuta sin ningun problema:

public enum TestEnum {
  Enum1 = 1,
  Enum2 = 2,
  Enum3 = 3
}
...
TestEnum t = (TestEnum)10; //WTF?
Console.Write(t.ToString()); //cual creen que sea la salida?
Console.Read();

Si a eso le agregas que el valor que estas convirtiendo viene (por ejemplo) de una base de datos, podras entender como esto podria esto afectar la logica en tu programa.

Si estas trabajando con Enums, te recomiendo que leas este articulo de Krzysztof Cwalina (solo en ingles), que es una referencia / guia muy completa para los tipos de enumeraciones; ahora que cuando uno se mete con Nullable Enums, la cosa se pone aun mas interesante, ya les platicare algunas cosillas que estoy haciendo en esa area

Wednesday, October 18, 2006

Usando el mouse: sabias que...?

Sabias que el boton medio del mouse (ironicamente ahorita no quiero hablar de ratones por razones muy desagradables) nos sirve para cerrar ventanas en la mayoria de las aplicaciones de navegacion por pestañas (tabbed-documents)? (para cerrarlas solo damos click con el boton de enmedio en la pestaña)

por ejemplo todos los navegadores nuevos: Internet Explorer 7, Firefox, Flock, Opera, etc tienen esta funcionalidad, pero tambien Visual Studio, aplicaciones como Notepad++, MSN Messenger, etc, en general la mayoria de este tipo de aplicaciones implementan esta funcionalidad.

Aparte de esto, en los browsers, dando "middle click" en un link, abre el link en una pestaña nueva

decidi bloguear sobre esto, porque he conocido mucha gente que no sabe sobre este pequeño pero util truco

En busca de un mejor sistema CAPTCHA

Recientemente, Geoff empezo a preocuparse con el SPAM en los comentarios a su blog y con las alternativas actuales que existen para combatirlo, desde entonces se puso a trabajar en una opcion mas simple (para los usuarios) en la cual se proveen fotos en vez de texto, luego tienes que dar click en ciertas imagenes dependiendo de unas instrucciones que se te dan; la idea es original y me parece que si es mas facil para el usuario, pero yo creo que tiene algunos problemitas:

  • Las imagenes necesitan bajarse para cada usuario (ancho de banda)
  • Creo que tienes que tener un numero considerable de imagenes para que esto realmente se pueda usar, esto para hacer mas dificil la creacion de un robot, con esto tambien tenemos mas problemas de ancho de banda
  • Cada implementacion tendria que tener sus propias imagenes y reglas asociadas con las imagenes
  • Es algo grande

De cualquier manera, esto me ha dado una idea, porque no combinamos texto regular con la idea de Geoff?

osease que podemos tener texto (convertido a imagenes) y las preguntas, algo mas o menos asi:

Da click en los numeros pares: 123641

Da click en los simbolos matematicos: 123+45/6*21

Da click en las ultimas 2 letras mayusculas: 1A654aPaK

etc, el font por supuesto seria diferente (y mas grande), las ventajas que le veo son:

  • Imagenes muy pequeñas
  • numero infinito de CAPTCHAS pueden ser generados con un pequeño programita, ni siquiera necesitas guardar las preguntas o respuestas en ningun lado
  • Es bastante legible
  • Tomando las debidas precauciones (para evitar confusion con algunos caracteres) puede ser muy claro y simple lo que el usuario necesita hacer (algunas veces no se si Geoff esta riendose o esta enojado =o| )

Hay algo que no estoy viendo, o me acabo de inventar la idea del siglo contra SPAM? =o)

Si aun prefirieras la idea de Geoff, creo que al menos las imagenes (y las preguntas asociadas) podrian ser generadas programaticamente, por ejemplo lineas en diferentes angulos, circulos, triangulos, etc. solo con eso resolveriamos la mayoria (o todos?) los problemas que veo con la solucion de Geoff... y es hasta cierto punto, otra idea mas

como ven?

Thursday, October 12, 2006

cuidado con las comas en comandos SQL

Ayer tuvimos un pequeño bug con un codigo mas o menos asi:

select field1, field2, field3
field4, field5
from SomeTable
where field1 = 'someValue'

pueden ver el bug?

el comando se ejecuta sin errores, pero el resultado podria no ser el deseado

El problema es que le falta una coma entre field3 y field4, entonces es como decir:

field1, field2, field3 as field4, field5

Lo que, como se podran imaginar, uno espera ciertos datos (y cierto tipo de datos) en ese campo pero recibe algo totalmente diferente y aparte que hay un campo que no sale en el resultado

La sintaxis yo creo que es estandar Ansi 92 SQL, asi que el problema lo podrian tener usando MSSQL, MySQL, Oracle, etc (en nuestro caso el codigo corrio bien en MySQL pero nos salio el error corriendo el mismo codigo contra Oracle porque ahi teniamos diferentes datos que hicieron que saliera a la vista)