sábado, 3 de mayo de 2008

Relaciones (1:1, 1:n: m:n) con AppEngine

Encontré un link donde se explican las distintas formas de relacionar entidades. Está muy simple y describe los pro y contras de cada opción.
http://daily.profeth.de/2008/04/er-modeling-with-google-app-engine.html

jueves, 6 de marzo de 2008

Salto de páginas con OpenOffice

En la página de OpenOffice están las instrucciones para incorporar una carátula a un documento, pero de forma tal que NO afecte a la numeración de nuestras páginas.

http://wiki.services.openoffice.org/wiki/Documentation/OOoAuthors_User_Manual/Writer_Guide/Numbering_pages

lunes, 11 de febrero de 2008

Limpieza de paquetes de Ubuntu / Debian

Buscando algunos consejos para limpiar mi instalación de Ubuntu 7.10 (luego de hacer el upgrade desde 7.04) encontré http://www.tuxapuntes.com/tux/content/view/416/122/.

En resumen, el comando más útil para esta tarea es deborphan. Por ejemplo, para limpiar los archivos de configuración de paquetes eliminados podemos usar:

deborphan --find-config | xargs -r aptitude -y purge

Para ver la información de los paquetes que purgaríamos con el comando anterior, podemos usar:

deborphan --find-config | xargs -r dpkg -l

El comando deborphan posee varias opciones más de "busqueda" de paquetes ('deborphan --help' las lista)

jueves, 7 de febrero de 2008

Herramientas de testing para Python

Encontré un link muy bueno con una listado bastante extenso de las herramientas existentes para realizar el testing de programas desarrollados con Python.

http://pycheesecake.org/wiki/PythonTestingToolsTaxonomy

lunes, 7 de enero de 2008

Cheat sheet de PostgreSql

Encontré 2 páginas con "cheat sheets" de PostgreSql (no sé cuál sería la traducción de "cheat sheets", quizá "machetes", pero para lo que no saben: son resúmenes sobre lenguajes, programas, etc. con información normalmente usada de referencia cuando no nos acordamos cómo especificar ciertas cosas).
Estas "cheat sheets" las bajé de aqui y aqui.

StaticGenerator para aplicaciones Django

Esta herramienta convierte un sitio dinámico desarrollando de Django en un conjunto de HTMLs listos para servir. Es una forma muy común de mejorar significativamente la performance de un sitio. Es distribuido bajo la licencia MIT. http://superjared.com/projects/static-generator/

En el sitio declaran que se puede mejorar la performance de 500 request por segundo a 7000 req/s:

  • mod_python, no caching: 100 req/s
  • mod_python, memcached: 500 req/s
  • StaticGenerator file: 7,000 req/s

sábado, 29 de diciembre de 2007

Tamaño de tablas/BD en PostgreSql

PostgreSql posee algunas funciones muy útiles para determinar el tamaño en disco que ocupa una tabla o una base de datos. Estas son:
  • pg_relation_size
  • pg_total_relation_size
  • pg_database_size
Para visualizar mas facilmente el resultado de las funciones anteriores, de puede utilizar pg_size_pretty. Por ejemplo:

intranet=# select pg_size_pretty(pg_total_relation_size('requerimiento'));
pg_size_pretty
----------------
23 MB
(1 row)


Estas y otras funciones están documentadas en el sitio de PostgreSql.

miércoles, 12 de diciembre de 2007

Threads en JavaScript usando XPCOM

Encontré una pagina con algunos ejemplos de como utilizar threads con XPCOM, muy útil para desarrollar extensiones de Firefox (y supongo también Thunderbird y el resto de los "primos" de Mozilla).

Las instrucciones están en http://skrul.com/blog/projects/threaddemo y el código accesible via SVN en http://skrul.com/svn/threaddemo/trunk/

lunes, 10 de diciembre de 2007

Download Statusbar + Checksum para bajar

He "empaquetado" en un XPI los cambios en Download Statusbar... Es realmente facil! Simplemente descomprimi el XPI original, le aplique los parches, cambie el nro. de versión y lo volví a comprimir!

Pueden bajar Download Statusbar + Checksum desde aqui.

Tooltips con prototip

Encontré una librería para manejar tooltips, está bastante completa y permite generarlos de varias formas: http://www.nickstakenburg.com/projects/prototip/ (utiliza scriptaculous y prototype).

Download Statusbar + Checksum

Empecé a investigar para aprender a desarrollar extensiones para Firefox, y se me ocurrió empezar implementado una mejora a la extensión "Download Statusbar", que consista en mostrar las opciones para calcular el MD5 o SHA1 del archivo bajado.
Inicialmente mi idea era utilizar el comando correspondiente de linux (md5sum, sha1sum, etc), pero luego descubrí que Firefox ya posee una implementación de varios algoritmos de hashing.

En esta primera versión la interface se ve así:




En el caso anterior, elegí calcular el SHA256 del archivo bajado. El resultado se muestra en un popup:



Pueden bajar el diff (a aplicar al código en CVS del día 2007-12-08), o ver el diff coloreado.

Si te interesa empezar en el desarrollo de extensiones, te recomiendo que inicies con las siguientes páginas (y sigas los links de esas páginas... hay mucha información!!):

http://developer.mozilla.org/en/docs/Setting_up_extension_development_environment
http://kb.mozillazine.org/Getting_started_with_extension_development
http://kb.mozillazine.org/Dev_:_Extensions

miércoles, 28 de noviembre de 2007

Cómo configurar Gnome para que parezca MacOSX

Encontré un HOWTO muy detallado sobre como configurar todos los aspectos de tu linux para que parezca MacOSX (incluyendo sonidos, temas de firefox, splash de gnome y grub, etc.).

http://www.howtoforge.com/mac4lin_make_linux_look_like_a_mac

viernes, 23 de noviembre de 2007

viernes, 9 de noviembre de 2007

Prototype checklist

Para los que estamos aprendiendo Prototype, es bueno ver artículos que te enseñan buenas prácticas, ya que normalmente hay muchas formas de hacer lo mismo, pero entre las diversas formas hay unas mejores que otras.

Estos dos artículos tratan del buen y mal uso de ciertas funcionalidades de Prototype
http://thinkweb2.com/projects/prototype-checklist/
http://thinkweb2.com/projects/prototype/?p=3

jueves, 8 de noviembre de 2007

La NSA accede a productos y redes de Windows

"Los amplios rangos de IP publicados por Cryptome son utilizados por la NSA, por contratistas del sector privado que trabajan con la NSA y por agencias gubernamentales no estadounidenses amigas de la NSA para acceder tanto a sistemas independientes como a redes ejecutando productos de Microsoft. Esto incluye el espionaje de "smart phones" ejecutando Microsoft Mobile."

Cada vez existen más razones para pasarse a Linux!!!!

Artículo completo

viernes, 5 de octubre de 2007

Comunicación Java / Python con XML-RPC

Estuve investigando cómo conectar Java y Python. Lo primero que se me ocurrió fue XMLRPC, y verdaderamente fue muy facil!
La info la saqué de:

El servidor Java:



1 package ar.com.hgdeoro.xmlrpc;
2
3 import java.util.ArrayList;
4 import java.util.HashMap;
5 import java.util.List;
6 import java.util.Map;
7 import java.util.Random;
8
9 import org.apache.xmlrpc.server.PropertyHandlerMapping;
10 import org.apache.xmlrpc.server.XmlRpcServer;
11 import org.apache.xmlrpc.server.XmlRpcServerConfigImpl;
12 import org.apache.xmlrpc.webserver.WebServer;
13
14 public class Server {
15
16 private static final int port = 8000;
17
18 public static void main(String[] args) throws Exception {
19
20 final WebServer webServer = new WebServer(port);
21 final XmlRpcServer xmlRpcServer = webServer.getXmlRpcServer();
22 final PropertyHandlerMapping phm = new PropertyHandlerMapping();
23
24 phm.addHandler("Calculator", Calculator.class);
25
26 xmlRpcServer.setHandlerMapping(phm);
27 XmlRpcServerConfigImpl serverConfig = (XmlRpcServerConfigImpl) xmlRpcServer.getConfig();
28 serverConfig.setEnabledForExtensions(true);
29 serverConfig.setContentLengthOptional(false);
30 webServer.start();
31 }
32
33 public static class Calculator {
34
35 public int add(int i1, int i2) {
36 return i1 + i2;
37 }
38
39 public List<Integer> randomList(int num) {
40 if (num <= 0) {
41 throw new RuntimeException("num debe ser > 0");
42 }
43 final List<Integer> list = new ArrayList<Integer>();
44 for (int i = 0; i < num; i++) {
45 list.add(new Random().nextInt());
46 }
47 return list;
48 }
49
50 public Map<Integer, Integer> randomMap(int num) {
51 if (num <= 0) {
52 throw new RuntimeException("num debe ser > 0");
53 }
54 final Map<Integer, Integer> list = new HashMap<Integer, Integer>();
55 for (int i = 0; i < num; i++) {
56 list.put(Integer.valueOf(i), Integer.valueOf(new Random().nextInt()));
57 }
58 return list;
59 }
60
61 public Map<String, Integer> randomMap2(int num) {
62 if (num <= 0) {
63 throw new RuntimeException("num debe ser > 0");
64 }
65 final Map<String, Integer> list = new HashMap<String, Integer>();
66 for (int i = 0; i < num; i++) {
67 list.put(Integer.valueOf(i).toString(), Integer.valueOf(new Random().nextInt()));
68 }
69 return list;
70 }
71
72 }
73 }



El cliente Java:



1 package ar.com.hgdeoro.xmlrpc;
2
3 import java.net.MalformedURLException;
4 import java.net.URL;
5
6 import org.apache.xmlrpc.XmlRpcException;
7 import org.apache.xmlrpc.client.XmlRpcClient;
8 import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;
9
10 public class Client {
11
12 public static void dump(Object obj) {
13 System.out.println("======================================================================");
14 System.out.println("Clase: " + obj.getClass());
15 System.out.println("toString(): " + obj.toString());
16
17 if (obj.getClass().isArray()) {
18 Object[] objs = (Object[]) obj;
19 System.out.println("---------- ARRAY ----------");
20 System.out.println("Tamanio: " + objs.length);
21 for (int i = 0; i < objs.length; i++) {
22 System.out.println("Object[" + i + "]: " + objs[i]);
23 }
24 }
25 }
26
27 public static void main(String args[]) throws MalformedURLException, XmlRpcException {
28 final XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
29 config.setServerURL(new URL("http://127.0.0.1:8000"));
30 final XmlRpcClient client = new XmlRpcClient();
31 client.setConfig(config);
32
33 Object obj = client.execute("add", new Object[] { new Integer(33), new Integer(9) });
34 dump(obj);
35
36 obj = client.execute("random_list", new Object[] { new Integer(14) });
37 dump(obj);
38
39 obj = client.execute("random_map", new Object[] { new Integer(9) });
40 dump(obj);
41
42 try {
43 obj = client.execute("random_map", new Object[] { new Integer(-1) });
44 throw new RuntimeException("La llamada remote deberia haber generado excepcion");
45 } catch (XmlRpcException e) {
46 e.printStackTrace();
47 }
48 }
49
50 }



El servidor Python:



1 from SimpleXMLRPCServer import SimpleXMLRPCServer
2 import random
3
4 def add(x,y):
5 return x + y
6
7 def random_list(num):
8 num = int(num)
9 if(num <= 0):
10 raise Exception("num debe ser mayor a 0")
11 list = []
12 for i in range(num):
13 list.append(random.randint(1, 999999))
14 return list
15
16 def random_map(num):
17 num = int(num)
18 if(num <= 0):
19 raise Exception("num debe ser mayor a 0")
20 map = {}
21 for i in range(num):
22 key = "elem_%d" % i
23 map[key] = random.randint(1, 999999)
24 return map
25
26 if __name__ == '__main__':
27 server = SimpleXMLRPCServer(("127.0.0.1", 8000))
28 server.register_function(add, 'add')
29 server.register_function(random_list, 'random_list')
30 server.register_function(random_map, 'random_map')
31 server.serve_forever()



El cliente Python:



1 import xmlrpclib
2 from pprint import pprint
3
4 if __name__ == '__main__':
5 proxy = xmlrpclib.Server('http://localhost:8000/xmlrpc')
6 pprint(proxy.Calculator.add(2,3))
7 pprint(proxy.Calculator.randomList(8))
8 pprint(proxy.Calculator.randomMap2(8))



Al ejecutar el cliente Python, obtengo:


5
[-816678161,
1435519307,
-648064553,
1198345419,
-332555131,
1349182312,
1286868314,
1756261972]
{'0': -1238582501,
'1': -711045786,
'2': 1242324380,
'3': 453035820,
'4': 727377110,
'5': 1443025388,
'6': -280665009,
'7': -1336015917}


y al ejecutar el cliente Java (esa excepcion que se muestra es un error producido adrede, para ejemplificar qué pasa cuando en el servidor se produce una excepción):


======================================================================
Clase: class java.lang.Integer
toString(): 42
======================================================================
Clase: class [Ljava.lang.Object;
toString(): [Ljava.lang.Object;@11a698a
---------- ARRAY ----------
Tamanio: 14
Object[0]: 140980
Object[1]: 917718
Object[2]: 951678
Object[3]: 405149
Object[4]: 758315
Object[5]: 412932
Object[6]: 488689
Object[7]: 721836
Object[8]: 658873
Object[9]: 590256
Object[10]: 667364
Object[11]: 552500
Object[12]: 784894
Object[13]: 865306
======================================================================
Clase: class java.util.HashMap
toString(): {elem_8=85992, elem_7=47193, elem_6=599464, elem_5=331449, elem_4=982397, elem_3=88299, elem_2=723048, elem_1=462681, elem_0=565753}
org.apache.xmlrpc.XmlRpcException: :num debe ser mayor a 0
at org.apache.xmlrpc.client.XmlRpcStreamTransport.readResponse(XmlRpcStreamTransport.java:186)
at org.apache.xmlrpc.client.XmlRpcStreamTransport.sendRequest(XmlRpcStreamTransport.java:145)
at org.apache.xmlrpc.client.XmlRpcHttpTransport.sendRequest(XmlRpcHttpTransport.java:94)
at org.apache.xmlrpc.client.XmlRpcSunHttpTransport.sendRequest(XmlRpcSunHttpTransport.java:44)
at org.apache.xmlrpc.client.XmlRpcClientWorker.execute(XmlRpcClientWorker.java:53)
at org.apache.xmlrpc.client.XmlRpcClient.execute(XmlRpcClient.java:166)
at org.apache.xmlrpc.client.XmlRpcClient.execute(XmlRpcClient.java:136)
at org.apache.xmlrpc.client.XmlRpcClient.execute(XmlRpcClient.java:125)
at ar.com.hgdeoro.xmlrpc.Client.main(Client.java:43)

sábado, 29 de septiembre de 2007

Como usar modelos de Django en programas python

Encontré un tutorial (en inglés) que explica los pasos necesarios para utilizar las clases de modelo definidas en Django, pero desde un script python (o sea, 'fuera' de la aplicación web donde están los modelos).

http://www.cotellese.net/2007/09/27/running-external-scripts-against-django-models/

miércoles, 12 de septiembre de 2007

Tomcat, Apache y "All threads (200) are currently busy"

Por alguna cuestión cuyo origen no he podido detectar, me ha traido muchos problemas un apache que se conecta a Tomcat (JBoss 4) utilizando AJP. Luego de unos días, Tomcat empezó a generar estos mensajes de error:

ERROR [org.apache.tomcat.util.threads.ThreadPool] All threads (200) are currently busy, waiting. Increase maxThreads (200) or check the servlet status

Pero definitivamente el problema no está en la cantidad de threads necesarios para servir el sitio, sino que por alguna razón las conexiónes quedaban "ocupadas", y en la página de status de Tomcat aparecían todos los threads como en "Stage KeepAlive"...
La solución es bastante sencilla, sólo hace falta configurar el timeout (connectionTimeout) en el contector AJP:

<!-- A AJP 1.3 Connector on port 8009 -->
<Connector port="8009" address="${jboss.bind.address}" emptysessionpath="true" enablelookups="false" redirectport="8443" protocol="AJP/1.3" connectiontimeout="60000">
</Connector>


Seteando el timeout en 60 segundos solucioné el problema.

viernes, 31 de agosto de 2007

Acceso al request desde template en Dango

Con su instalación por default, Django no permite acceder al request actual desde los templates, pero esto no es muy complicado de realizar.

Para soportar esto, la forma que más me gustó es a través de los "context processors". Configurando esto le indicamos a Django que injecte en el contexto del template una referencia al request actual.

Hay que agregar en settings.py:
TEMPLATE_CONTEXT_PROCESSORS += (
'django.core.context_processors.request',
)
y utilizar render_to_response de la siguiente manera:

from django.template import RequestContext

def view(request):
return render_to_response(
'path/to/template.html',
{},
context_instance=RequestContext(request)
)
y listo!

martes, 28 de agosto de 2007

Responsabilidad Social Empresaria

El viernes pasado asistí a la presentación de ActivaRSE, donde integrantes del IARSE y AIESEC, y de empresas locales (Neyra, Matricería Austral y Arcor) expusieron la importancia de la responsabilidad social empresaria (el Lic. Alejando Roca, del IARSE hizo una exposición tremenda y fue súper claro explicando los conceptos y el funcionamiento de la RSE).
El 17 de nov. de 2007 se realizará la 2da presentación, en este caso las empresas expondrán sus experiencias en la implementación de RSE.