lunes, 26 de septiembre de 2011

iDNX demo online

Al esta online el sitio demo del idnx rs online con todas las actualizaciones mencionadas ahi mismo (sólo las escribía más no atualizaba el sitio porque lo tenía en mi localhost). Les recuerdo que con esto concluye la fase alpha 1 del sitio, ya que faltan algunas cosas que programar pero la estructura principal ya esta hecha y así será más fácil darle continuidad al mismo. Espero les agrade ya que le metí bastante ajax con jquery y css (1,2,3), por lo que les recomiendo utilizar el Firefox 5.0+.

viernes, 23 de septiembre de 2011

Ahora en el .com

Pues al fin me decidí a semi redireccionar el index del dominio (que aparecía sólo con un letreo de "is back") a lo que es el blog principalmente porque no quise hacer un index por ahora pero tampoco quería ese viejo letrero (fue la solución más rápida jaja).

Bueno, el demo del idnx online lo pospuse por un par de semanas (por una distracción con lua) pero ya estoy de regreso en ello así que este fin de semana debe quedar terminada la primera parte.

jueves, 22 de septiembre de 2011

Bases de datos (3ra parte)

En el pasado post escribí acerca de la importancia de una buena estructura en una base de datos, así que hoy toca escribir acerca de dicha estructura pero para protegernos de un posible un tanto común pero con escasa información de como resolverlo.

A este error le llamo "Ruptura de interrelación" y se origina cuando en un par de tablas relacionadas, a través del primary key, para accesar a los campos de una de otra se elimina un registro. Un ejemplo sería el siguiente, donde la tabla notas se interrelaciona con la tabla usuarios:

Tabla1: usuarios
Campos: id, nombre, edad
Fila1: 1, juan, 15
Fila2: 2, pedro, 20

Tabla 2: notas
Campos: id, id_usuario, nota
Fila1: 1, 2, hola
Fila2: 2, 1, como

La consulta de selección (select query) empleado para este ejemplo es (ansi):

SELECT DISTINCT notas.id, usuarios.nombre, usuarios.edad, notas.nota FROM notas, usuarios WHERE notas.id_usuario=usuarios.id

Con esta consulta el resultado sería:

1, pedro, 20, hola
2, juan, 15, como

Pero que pasaría sí se eliminara el registro 1 de la tabla usuarios con una consulta como:

DELETE FROM usuarios WHERE id=1

Al volver a ejecutar la consulta de selección sólo retornaría un resultado, siendo éste:

1, pedro, 20, hola

Ésto sucede por el error que denominé "Ruptura de interrelación" porque en la consulta sólo se seleccionan los registros cuyo campo notas.id_usuario = usuario.id ignorando aquellos que son notas.usuario = null.

Hay varias soluciones:

1.- Usar una cláusula como ésta: WHERE (notas.id_usuario=usuario.id OR notas.usarios=NULL).
2.- Usar los equivalentes a cada lenguaje sql de IF NOT EXISTS(usuario.id, 'algo',usuario.nombre)

Otra opción más es hacer uso de triggers y funciones para cambiar el campo notas.id_usuario a 0 cuando dicho id de usuario es eliminado y luego usar consultas como IF(notas.id_usuario=0, 'sinregistro', usuario.nombre).

En fin, como podrán leer existen varias formas, aparte de las mencionadas (como el if not null), para evitar esas rupturas de interrelación que pueden finalizar en registros innaccesibles por consultas de selección como la primera expuesta.

Así que les recomiendo por mucho que lean a fondo los manuales de consultas selección, triggers, funciones y reserved keywords propias del sql que esten usando.

Spawner-Ex.dll

Excelente dll para trabajar con lua, y aunque sé que fue creada en un principio para el debugger de SciTE, ya que permite ejecutar otras aplicaciones iniciando un proceso (thread) nuevo, sin bloquear el proceso principal (main thread) y devolviendo el código de cierre de dichas aplicaciones.

Pero no solo eso, sino también permite ejecutar aplicaciones que usualmente mostrarían la ventana del shell pero sin ella. Hay 2 modos de ejecución, donde la primera solo es basicamente para ejecutar y leer el stdout y luego se finaliza (suelen bloquear el main thread). La segunda es para poder incluso interactuar con la aplicación permitiendonos enviar strings al stdin sin bloquear el main thread.

Ya me compile la dll modificando los tamaños de buffer habiéndolos incrementando bastante y con excelentes resultados. Si alguien la ocupa sólo dejen comentario (jojojo).

Para ejecutar programas con argumentos y rutas de archivo con espacios es recomendable que usen los corchetes (square brackets).

Les dejo un link al post donde comencé a leer de esta dll: http://groups.google.com/group/scite-interest/browse_thread/thread/b57760317f6bf688?pli=1

viernes, 16 de septiembre de 2011

Corutinas en Lua [Parte 2]

En el anterior post escribí una corutina creada con la función "coroutine.wrap()". Ahora toca hacerlo con "coroutine.create()":

function Print(valor1, valor2)
  while true do
    valor1, valor2 = coroutine.yield(valor1, valor2);
  end
end

PrintCo = coroutine.create(Print);
print(PrintCo);-->thread 0xXXXXXX
local a, b, c = coroutine.resume(PrintCo,"Hola", "mundo!")
print(a, b, c);-->true, Hola, mundo!
a, b, c = coroutine.resume(PrintCo,"Cómo", "estas?!");
print(a, b, c);-->true, Cómo, estas?!

Así es como se vería el mismo código pero creado con la función "coroutine.create()", la cual retorna un tipo definido como "thread". Para resumir una corutina creada con éste método debemos usar la función "coroutine.resume()", la cual retornará un valor booleano en el primer argumento y en el resto de los argumentos los valores que la función de la corutina regrese.

La principal diferencia de crearla así (en lugar de hacerlo con coroutine.wrap) es que podemos obtener el estado de ejecución de la misma (suspended, normal, dead) y además podemos manejar los errores sin propagarlos al invocador (con wrap el error se propaga directo al invocador).

Es importante volver a mencionar que todo lo que se escriba dentro del paréntesis de "coroutine.yield()" es lo que se retornará (ó en su defecto un simple return que finalizaría la corutina) al invocador de "coroutine.resume()" o a la función creada con wrap. El contenido del paréntesis no indican los nuevos valores a recibir/evaluar, así que podemos tenerlo vacío y aún así seguir recibiendo valores dentro de la corutina:


function Print(valor1, valor2)
  while true do
    print(valor1, valor2);
    valor1, valor2 = coroutine.yield();
  end
end

PrintCo = coroutine.create(Print);
print(PrintCo);-->thread 0xXXXXXX
local a = coroutine.resume(PrintCo,"Hola", "mundo!")
---->Hola, mundo!
print(a);-->true
a= coroutine.resume(PrintCo,"Cómo", "estas?!");
---->Cómo, estas?!
print(a);-->true

Todo esto es algo que, como ya mencioné en la publicación anterior, no esta muy bien documentado en los manuales de lua.

Ahora bien, la principal cualidad de una corutina es la de poder controlar varias corutinas desde 1 principal (resumiendo otras, pausando, etc.) logrando lo que se llama "multitasking" (multitareas) y no una función tan simple como la expuesta en los ejemplos. Pero, la finalidad de estos ejemplos es explicar de forma más detallada el uso básico de las corutinas.

NOTA: Todas éstas funciones pueden ser probadas para verificarlas en el demo online que ofrece el sitio de lua.org (http://www.lua.org/cgi-bin/demo).

jueves, 15 de septiembre de 2011

Corutinas en Lua

Hoy escribiré acerca de las corutinas de Lua (coroutines en inglés). Sé que la documentación de lua, manuales, etc. no logran explicar bien qué son ni cómo funcionan (y los ejemplos vaya que son difíciles de entender) así que trataré de facilitarlo para todos.

Las corutinas son nuevos procesos (threads) que se ejecutan independientemente de otros procesos. No se pueden ejecutar en paralelo, pero si en forma secuencial.

Muchos dirán: "De que sirven las corutinas si podemos simplemente ejecutar X función". Bueno, la corutinas son más rápidas en ejecución que una función porque ademas de estar cargadas en la memoria tambien se ejecutan en procesos independientes. Es decir, al ejecutar una función simplemente corremos una serie de instrucciones cargadas en X dirección de la memoria (pero sigue siendo el mismo proceso), y al ejecutar una corutina se ejecuta un proceso alterno que ya tiene cargadas la serie de instrucciones a seguir siendo más rápida la respuesta.

Pero no solo esto, sino también dichas corutinas (en procesos distintos) pueden pausarse, resumirse, etc.

En resumen, la ventajas son:

- La ejecución más rapida de funciones
- Poder controlar el flujo de otras corutinas desde dentro, o fuera, de otras.

Pero bueno, para dejarlo más claro escribiré un ejemplo muy básico de cómo crear una corutina:

function Print(valor1, valor2)
  while true do
    valor1, valor2 = coroutine.yield(valor1, valor2);
  end
end

PrintEx = coroutine.wrap(Print, a, b);
print(PrintEx("Hola", "mundo!"));
print(PrintEx("Cómo", "estas?"));

Con éste código creamos una corutina infinita (nunca se terminará) llamada "PrintEx" basada en la función "Print" que cada vez que la llamemos imprimirá los argumentos que le enviemos (bien podríamos simplemente usar la función print("Hola", "Mundo"); pero el caso es explicar las corutinas).

Bueno, ahora paso por paso.

1.- La función que será nuestra corutina es la función "Print" y recibe 2 argumentos.

2.- Dicha función inicia un loop infinito dónde por cada vuelta pausará la corutina usando "coroutine.yield()";

3.- La función "coroutine.yield(valor1, valor2);" lo que hace es retornar los argumentos suministrados por la función. Algo así como el clásico "return valor1, valor2;" en la funciones normales.

4.- Noten la línea de código "valor1, valor2 = coroutine.yield(valor1, valor2)". Como ya sabemos, la función "coroutine.yield();" retornará al invocante los argumentos que pongamos dentro del paréntesis. Pero si anteponemos "variable1, variable2 = " a dicha función entonces le estamos indicando a la corutina que la próxima vez que sea invocada los argumentos suministrados por el nuevo invocador serán guardados en las variables que antepongamos a "coroutine.yield()". De otro modo cada que la corutina seá invocada sólo retornaría los valores suministrados la primera vez que se le invocó.

5.- Usé como generador de corutina la función "coroutine.wrap()" (porque es más adecuado para este ejemplo), la cual retornará una nueva función que cada vez que sea invocada resumirá o ejecutará la corutina. En otras palabras, es lo mismo que usar "coroutine.resume(corutina, argumentos)" sólo que no retorna el primer valor boleano, sino sólo los argumentos que retorna la corutina.

Espero no sea tan complicada esta explicación, y más adelante escribiré otro ejemplo pero ahora si usando la función generadora "coroutine.create()".

jueves, 8 de septiembre de 2011

Aprender lenguajes de programación

Para quienes comienzan a aventurarse en el mundo de la programación hay ciertos puntos que les pueden ayudar:

1.- Diagramas de flujo: Si bien es algo latoso hacerlos (tareas, clases, etc.) no significa que sean inútiles. La mayoría de las empresas que se dedican a desarrollar aplicaciones hacen los diagramas de flujo (de X aplicación) por mucho tiempo antes de siquiera sentarse a programar. No significa que uds. lo requieran pero es una buena costumbre. Lo primordial de un diagrama de flujo es precisamente entender paso a paso todas las acciones que se ejcutarán desde que inicia el programa. Al entender este flujo entenderán en realidad como se procesa la información por las computadoras y podrán desarrollar mejores aplicaciones libres de bugs.

2.- Controles de estructura, loops, signos de comparación y palabras reservadas: Son escenciales en todo lenguaje de programación así que son de las primeras cosas que deben aprender y memorizar (en más fácil de lo que creen).

3.- Variables: Aprendan todo lo básico de las variables, desde los distintos tipos hasta la forma correcta de declararlas. Los ámbitos (global ó local) de las variables también son importantes porque les ayudarán a que sus códigos se ejecuten más rápido.

4.- Funciones: Aprender a crear sus propias funciones les ayudará a ahorrar líneas de código y a ejecutar más rápido sus funciones. Eso de escribir series líneas de código idéntico en distintas zonas de su aplicación no es óptimo.

5.- Por último serían las funciones propias del lenguaje de programación.

Conforme más programemos en X lenguaje más rápido memorizaremos lo anteriorente mencionado.

Si ya se conoce por lo menos 1 lenguaje de programación de alto nivel será mucho más fácil aprender el resto.

Base de datos (2da parte)

Anteriormente ya hablé (escribí) de las bases de datos y su importancia en todo tipo de aplicaciones. Pero ahora toca el turno de las estructuras de éstas bases de datos.

La estructura de una base de datos es igual de importante que el código que usemos para leerla y insertarle datos (independientemente del lenguaje de programación usado). De ella dependerá que nuestra aplicación sea adaptable a futuras versiones sin mayores actualizaciones.

Un ejemplo de ello sería una aplicación de ventas donde podemos controlar el inventario en una tabla de nuestra base de datos. Pero también podemos ver quien realizó la compra. En un futura actualización podriamos incluir quien realizó la venta a través de un campo llamado (siguiendo el ejemplo) "vendedor_id".

Así que si van a usar una bse de datos en su aplicación les recomiendo que creen tantos campos como sean necesarios más los que de momento podrían no serlo, ya que en un futuro podríamos llegar a usarlos.

martes, 6 de septiembre de 2011

Stupidware: Noob

La verdad que es un tanto irritante y desgastante encontrar a cada rato la misma gata pero revolcada (una disculpa por el lenguaje coloquial figurativo). Pero es molesto que los noobs/newbies/novatos (en su afán de sobresalir) renombren programas o packs de programas/archivos/etc. con nombres que inician con alguno de los siguientes ejemplos:

- Mega
- Súper mega
- Ultimate
- Masters

Entre otros. Incluso llegan a inventar versiones de programas cuando la oficial ni siquiera se ha actualizado en años.

A lo único a lo que conducen es a generar basura de versiones no probadas que pueden resultar en el mal funcionamiento, por mencionar un ejemplo. Me pregunto: ¿Qué tanto les cuesta sólo poner el nombre del programa/pack/etc. tal cual es? En lugar de verse "conocedores" resultan hilarantes ante dicha muestra de complejos.

Otra cosa que también he escuchado es: "No son páginas web, es software". Es verdad que es software, pero si nos vamos a definiciones entonces todo aquello no físico de una computadora es SOFTWARE (llámense juegos, aplicaciones, sitios web, etc.). Pero ¿Para qué molestarse en catalogar/dividir el software según sus características comunes? ¡Es obvio! ¿Para qué molestarse en dividir a los perros según su raza ó a los animales según su especie si al final todos son animales? La respuesta esta intrínseca en la pregunta (¿Retórica?).

lunes, 5 de septiembre de 2011

Ver código generado por jQuery/Ajax

Bueno, mucho dirían que no es posible ver el código (html) que genera jQuery a través de sus funciones Ajax pero no es así. Hay varias formas siendo las más sencillas las siguientes (con firefox):

1.- Usar addons como Live HTTP Headers que capturarán todo el intercambio de datos entre el navegador y el servidor (pero mostrando incluso cabeceras, etc.).

2.- Viendo la página cuyo contenido fue generado por $.load, $.post, etc. y sólo seleccionar los elementos generados por el jQuery y que no aparecen en el CTRL+U (por ejemplo un DIV con algo de text), dar clic con el botón derecho del mouse y elegir la opción de "Mostrar código fuente seleccionado".

Listo, con esas 2 opciones podrán ver el código generado por jQuery en sus funciones ajax (o algunas otras, no se limiten). A lo mejor no es de mucha ayuda, pero sirve para ver de forma más rápida lo que se esta generando y así poder depurar el código.