
Soy César Olea, programador desktop, Web y de sistemas embebidos. Originario de Ciudad Obregón, Sonora, México.
Actualmente he terminado mi maestría en Ciencias de la Computación y me dedico dar mantenimiento, administrar y programar el sitio aVeralCine.com, escribir en Geek&Roll, el Web-comic geeksofacto y distintos proyectos de programación. Mi trabajo oficial (o sea, el que paga las cuentas) es en Tiempo Development como Senior Software Engineer. Si eres un buen programador, hablas Inglés y te interesa trabajar en una empresa con excelente ambiente laboral y projectos interesantes, estamos buscando gente como tu.
Para contactarme puedes ![]()
enviarme un mensaje si estoy conectado a gTalk.

Geek&Roll es el blog donde escribo sobre programación, cracking, cultura geek, Software Libre, Internet, y más. En conjunto con Axel y Rafyta mantenemos un blog de contenido (casi todo) original.
Mi relación con GWT es una de amor – odio. Por un lado, tenemos a un toolkit que me permite utilizar mis conocimientos de Java para crear aplicaciones Web dinámicas, aplicando mejores prácticas en la arquitectura del código del cliente, mejorando el tiempo de respuesta gracias al uso de técnicas como agrupar imágenes para usarlas en el cliente con una sola descarga y código segmentado.
Por el otro lado, algunas tareas se vuelven más complicadas. Estoy convencido que las herramientas como GWT son el futuro, más no me queda claro si la actual implementación sea adecuada para toda la programación del lado del cliente. Además la curva de aprendizaje es más inclinada de lo que debería de ser; existen muchos gotchas todavía que hacen que el programador tenga que estar consciente de que esto es Web y no una aplicación regular.
En esta ocasión el requerimiento era el siguiente: tengo una aplicación que hace uso extensivo de formas para captura de datos. Necesito una manera de declarar dichas formas y que la aplicación automáticamente las ordene en diferentes tabs cuando estas crezcan demasiado. Las formas generadas deben poder ser insertadas en cualquier sitio, además de poder aplicarles estilos con CSS.
Como dije anteriormente, lo que me gusta de GWT es que puedo generar la solución a mis requerimientos de la misma manera en la que estoy acostumbrado a hacerlo. En este caso, creo una clase DynaForm que representa mi forma dinámica:
/*Represents the client side DynaForm*/
public class DynaForm {
private String formSource;
private ArrayList<String> panelTitles;
private ArrayList<HTML> panels;
private Node root;
public DynaForm(String formSource){
setFormSource(formSource);
}
Ahora viene algo interesante. El método setFormSource(). Es aquí donde vamos a parsear el código de la forma para extraer los valores que nos interesan, y descomponerla en sus partes para después volverla a construir pero con las propiedades que nos interesan, en este caso los tabs.
public void setFormSource(String formSource){
try{
Document d = XMLParser.parse(formSource);
root = d.getFirstChild();
XMLParser.removeWhitespace(root);
setPanels(root, formSource);
}catch(Exception e){
System.out.println(e.getMessage());
e.printStackTrace();
}
this.formSource = formSource;
}
Como vemos, parseamos la fuente y de esa manera nos aseguramos que es código válido. Aquí podríamos aplicar otras reglas, como por ejemplo eliminar cualquier tag o propiedad maliciosa como una llamada a JavaScript. El método setPanels() es el que se encarga de construir los páneles necesarios.
/*
* This method creates an array of HTML panels. Both panels and panelTitles must
* contain the same number of elements. In case a <span> element doesn't provide
* a 'name' attribute, it is replaced by an empty string.
*
* The number of HTML panels created is = # of <span> elements. All elements inside <form>
* without a <span> are ignored.
* */
private void setPanels(Node root, String formSource){
panelTitles = new ArrayList<String>();
panels = new ArrayList<HTML>();
NamedNodeMap attribs;
NodeList allElements = root.getChildNodes();
/*
* Start looping all elements, and create new HTML panels as needed
* */
for(int i=0; i<allElements.getLength(); i++){
Node n = allElements.item(i);
//if it's a span, create a new empty HTML panel and set its name.
if(n.getNodeName().equals("span")){
//Set the panel title entry
attribs = n.getAttributes();
panelTitles.add(getAttribValue(attribs, "name"));
panels.add(new HTML());
}else{
try{
//get the last panel
HTML panel = panels.get(panels.size()-1);
//add the node source to the panel HTML
panel.setHTML(panel.getHTML() + n.toString());
}catch(Exception e){
System.out.println(e.getMessage());
}
}
}
}
El método setPanels() toma todos los elementos de la forma y los analiza de la siguiente manera: Si es un elemento span, quiere decir que es el inicio de un nuevo tab. Toma la propiedad name del span y lo convierte en el título de la nueva tab. Si el elemento no es un span, entonces lo agrega a la lista de elementos que forman el tab actual.
Después, en el punto de entrada de la aplicación:
TabPanel tabPanel = new TabPanel();
dynaForm = new DynaForm(formSource);
//All each HTML panel to the tabPanel
for(int i=0; i<dynaForm.getPanels().size(); i++){
quirksTabPanel.add(dynaForm.getPanels().get(i), dynaForm.getPanelTitles().get(i));
}
RootPanel.get("dynaForm").add(tabPanel);
Utilizando el siguiente código HTML como fuente de la forma:
<form method='POST' action='contactengine.php' name='contact'>
<span name='Datos' />
<label for='Nombre'>Nombre:</label>
<input type='text' name='Nombre' id='Nombre' />"
<label for='Correo'>Correo:</label>
<input type='text' name='Correo' id='Correo' />
<label for='Mensaje'>Mensaje:</label>
<textarea name='Mensaje' rows='20' cols='20' id='Mensaje'></textarea>
<span name='Enviar' />
<input type='submit' name='submit' value='Enviar' class='submit-button' />
</form>
Claro que se deben usar estilos para hacer que la forma se vea más presentable. También creo que se puede lograr exactamente el mismo resultado utilizando una combinación de jQuery, selectores CSS y jQuery UI.
Muchos usuarios han reportado problemas al utilizar Everlasting Flame con la BlackBerry Bold 2. Más particularmente, con el OS 5. Dicho problema no se presentaba en versiones anteriores a la 1.3.
El problema ha sido resuelto en la siguiente versión (2.0) sin embargo no se encuentra lista para consumo masivo. Por lo mismo, he subido de nuevo la versión 1.2 ligeramente modificada. Esta versión ha sido probada en la Bold 2, pero debería funcionar en cualquier dispositivo con OS 5.
Pueden descargar la versión 1.2 en el sitio oficial de Everlasting Flame. En la sección de descarga se encuentra la versión 1.2 para dispositivos anteriores.
Sus comentarios son bienvenidos.
Por medio de Google Buzz me enteré de una noticia que me sorprendió de manera muy positiva: Sonora se pasa al Software Libre para sus sistemas de información. El Buzz en cuestión es de mi amigo y colega Roberto Ramirez, y linkea a un blog de Martin Llamas.
Cuando leí el post por primera vez, pensé que era una broma. Al leerlo por segunda ocasión y checar otros posts del mismo blog, me di cuenta de que no, no era una broma. Este señor esta convencido de que el cambio al software libre es una pérdida de dinero, ya que todo lo que se ha pagado hasta ahora en licencias se va a tirar a la basura, como si el pago de licencias fuera sólo una vez en la vida y ya.
El autor cita varios problemas con este cambio, veamos:
Y bueno, después el autor habla de interoperabilidad, como si tener todos tus datos en un sistema privativo fuera la mejor idea. Hay en el post una sarta de opiniones desinformadas que sinceramente da tristeza que alguien quiera hacer un punto a favor del software privativo en el gobierno, siendo tan ignorante de la alternativa.
Señor Martin Llamas, si no sabe mejor limítese a decir “Chiquitibum a la bin bon ban, Microsoft! Microsoft! RA RA RA!!!!”
¿Estás aburrido este fin de semana? ¿O simplemente necesitas una manera de tener acceso a tu música (y de video) desde cualquier parte del MUNDOOO, o bien compartírsela a tu amigo en Tombuctú?
Hay muchas maneras de accesar archivos remotamente: servidor FTP, servidor web, algún servicio externo, pero de alguna manera he probado todas y creo que esta es la más chingona, y bueno, al menos para música.
Empecemos enumerando las posibles alternativas:
Orb – Es un servicio que te permite accesar a tus archivos multimedia y hasta televisión local, si tienes conectado el cable o antena a tu PC. Utiliza un cliente que reside en memoria el cual monitorea el contenido multimedia de tus discos duros y también “llama a casa” con tu IP y otras cosas, para que puedas accesar a tus datos utilizando el portal en myorb.com, ya que la mayoría del tiempo estas detrás de un firewall.
Slimserver – Este servidor con licencia GNU, fue particularmente creado para darle soporte a clientes de hardware, es decir, lo instalas en tu servidor para poder escuchar la música en tu cliente hardware; Slimdevices. Esta compañía fue comprada por Logitech, pero el desarrollo de slimserver, el cual ahora se llama Squeezebox server, sigue dando soporte a softclients por medio de cualquier navegador web. El problema es que afuercitas necesitas un “fat client” para poder aterrizar el stream; Algo como Winamp, WMP, cualquier otro media player que acepte URLs.
Apache/Songbird – Si, ya se! Este es un servidor web, y pues que tiene de chilo utilizarlo para que te despliegue el contenido de tus carpetas. Por más bonito que estén los index de tu Apache, no sirven de nada si no tienes Songbird. Este tiene la abilidad de crear playlists desde websites. De manera que si navegas tu index te crea listas, desde las que puedes streamear o bajar directamente. Esta fue mi solución por mucho tiempo, y es buena tenerla como respaldo. El problema es que los archivos no están indexados en una base de datos, entonces tienes que realmente ordenar tu estructura del sistema de archivos y olvídate de tener un icono con una lupa para buscar algo.
Y aquí fue donde me hice a la tarea de investigar otras soluciones. Ahora ya tenía requisitos:
Encontre dos posibles candidatos: Ampache y Jinzora.
Para terminar pronto, Jinzora apesta, al menos para mí. La documentación es tan mala como escasa. Prácticamente nula. Y una vez instalado, buena suerte importando toda tu música. Simplemente no la importa toda y ni siquiera te dice por qué.
Ampache. Alertas con el nombre ehh!, no es ni Tepache, ni tampoco Empache, ni la combinación de las dos: Empache de tepache.
Muy parecido a la idea del jizora ese pero con la diferencia de que este sirve.
Con Ampache puedes stremear tu música, bajarla, y crear playlists. Todo esto desde cualquier navegador. Utilza XSPF para hacerlo desde el navegador o puedes utilizar cualquier reproductor para streamear desde URL (incluso el cerrado itunes).
Lo que hace a Ampache mas poderoso es la implementación de su API, para que tengas control del contenido de tu servidor desde digamos, tu celular o un cliente, así no solo streameas sino puedes navegar por el contenido de tu base de datos. Así como si tuvieras los archivos localmente.
Además, tiene soporte para Scrobblear a Last.FM y existen algunos clientes que funcionan perfectamente para dispositivos móviles como Android (la neta es el único que he probado)
“Boynas, debiste de haber sido un vendedor de aspiradoras o de enciclopedias en tu otra vida, porque estoy completamente vendido con la idea. Dime como instalarlo YA!”
Ampache es muy ligero, la instalación es rapidísima, es mas ni siquiera te tienes que meter a MySQL a crear las bases de datos. Solamente descargas el archivo en un folder público y navegas a él y proporcionas credenciales para tu MySQL y punto.
Después creas tu catalogo de canciones. Las cuales, si las tienes bien identificadas con su respectivos ID tags, no necesitas nada, sin embargo el sistema también puede identificar los tags por medio de la estructura de carpetas.
Requisitos
Baja la última versión estable, de ampache.org; Ahora, si celebraste la caída del “Perro Aguayo” es porque no eres “técnico”, sino “rudo”; tu elección seria el “nightly snapshot”.
Estaba a punto de escribir instrucciones pero me di cuenta que sería una especie de falta de respeto a la comunidad que ha batallado tanto para crear documentación, la cual en este proyecto en particular fue clave para adoptar Ampache y no otra cosa. (http://ampache.org/wiki/install)
Eso sí, después de que tengan todo instalado, liberen el API para que tenga contacto con el mundo exterior. De esa manera podrán accesar la base de datos y las canciones desde tu Android (Amdroid) o incluso iPhone (amphone), o bien algún cliente como Amarok o winamp. Para hacer esto, te vas a la cejilla “admin” y a ACL para configurar o agregar un “Access List” para que las IPs exteriores puedan accesar el API. Asegúrate de abrirlo lo suficiente como para que un IP de Tombuctú pueda tener acceso.
Nota del autor: Si alguien sabe una manera menos pendeja de decir “stremear” en español diganmelo por el amor de Dios.
La única razón por la que rento películas es por los BluRay. No que sea imposible descargarlos, pero el PS3 no soporta archivos MKV, y mi laptop no es lo suficientemente poderosa como para reproducirlos por medio de streaming. Así que la única manera que tengo para ver películas en HD en el PS3 son los BluRay.
Probablemente los lectores de este blog coincidan con que la idea de rentar una película, es decir ir al lugar, ver si tienen una copia disponible (o ver las portadas para elegir una), pagar y regresar a tu casa, sólo para unos días después tener que regresar al establecimiento a devolverla a tiempo o de lo contrario ser penalizados con recargos… la idea es un poco obsoleta, poco práctica, algo que debería ser del pasado.
Sin embargo lo sigo haciendo, por las razones antes mencionadas. Y es extremadamente idiota que cada vez que voy a rentar al mismo establecimiento me hacen las mismas preguntas: ¿Cuál es su teléfono? ¿Desea obtener la promoción de socio distinguido?
De las dos preguntas, la que más me molesta es la primera. En teoría es para prevenir que otra persona rente con tu misma credencial, pero entonces ¿para qué piden credencial, si no basta como método válido de identificación? Además de la credencial, me piden una identificación oficial y mi teléfono. Ni en el cajero me piden tanta cosa para sacar dinero. Además no aceptan otro teléfono que no sea fijo, así que la gente como yo que no tiene teléfono fijo en su casa tiene que dar el teléfono de un conocido.
Si van a ofrecer un servicio que está destinado a compartir la fortuna de la venta de CDs, ya de jodido deberían de hacerlo un poco más amigable. Yo se que cambiar al modelo digital de la noche a la mañana no va a suceder, pero en el inter podrían:
No me queda duda que en el futuro cercano, la renta de películas pasará a ser digital en su mayoría, quedando algunos nichos como los pequeños videoclubs a la “Be Kind Rewind“. En México nos queda el reto de los costos de las telecomunicaciones, para hacerlas más accesibles a la población, a su vez haciendo económicamente viable esto de los servicios de video digital.
Mientras todo esto sucede, seguiré bajando películas por medio de bittorrent, viéndolas en el PS3 y rentando BluRay… hasta que el hack de Geohot permita soporte para MKV, entonces sí al demonio con Blockbuster.
Crear un control custom para una aplicación de BlackBerry es muy similar a crearlo para una aplicación Java con Swing. La arquitectura del toolkit de Swing es una de las cosas que más me gustan de Java, haciendo muy claro el cómo reemplazar algo por una implementación propia.
En este caso, mi requerimiento era tener una gran “palomita” o checkmark cuando cierta variable era verdadera, y una gran cruz o tache cuando la misma variable era falsa. En otras palabras, un checkbox pero con otra interfaz, más bonita (aunque bonita es una variable que depende del observador, y como eso no lo puedo controlar…)
Como muchas cosas en Java, todo comienza extendiendo una clase, en este caso la clase CheckboxField
public class CustomCheckBox extends CheckboxField
Este checkbox, contrario al checkbox normal, no va a tener un texto asociado, solo la parte gráfica. Así que sobreescribimos el constructor:
public CustomCheckBox(){
super();
}
public CustomCheckBox(boolean check){
super("",check);
}
Similar a Swing, hay que sobreescribir el método paint para ahí pintar lo que nosotros queremos. Cuando el checkbox esta check dibujamos la palomita, y cuando esta uncheck, dibujamos la cruz:
public void paint(Graphics g){
if(getChecked()){
drawCheck(g);
}else{
drawCross(g);
}
}
Esos dos métodos drawCheck y drawCross son los responsables de pintar el control. El método getChecked heredado de CheckboxField nos dice si el control esta checked o unchecked.
Primero veamos drawCheck
private void drawCheck(Graphics g){
int left = getBorderLeft();
int top = getBorderTop();
int x0 = left, x1 = x0, x2 = x1+20, x3 = x2+50, x4 = x3,
x5 = x4-50, x6 = x5-20;
int y0 = top, y1 = y0+30, y2 = y1+15, y3 = y2-45,
y4 = y3+25, y5 = y4+45, y6 = y5-15;
g.setColor(0x5B9058);
g.setBackgroundColor(isFocus() ? 0xEEEEEE : 0xFFFFFF);
drawBackground(g);
g.setDrawingStyle(Graphics.DRAWSTYLE_AAPOLYGONS, true);
int[] xPts = {x1, x2, x3, x4, x5, x6};
int[] yPts = {y1, y2, y3, y4, y5, y6};
g.drawFilledPath(xPts, yPts, null, null);
g.setDrawingStyle(Graphics.DRAWSTYLE_AAPOLYGONS, false);
}
De antemano perdonen ustedes el uso de números mágicos. Lo interesante es el método drawFilledPath, que toma dos arreglos con coordenadas XY y dibuja, como su nombre lo indica, un polígono. Es algo como dibujar con Logo, uno de mis primeros lenguajes de programación muy similar a Lisp. Primero preparamos las coordenadas, después verificamos si nuestro control tiene el foco para dibujarle un fondo distintivo.
El otro método, drawCross, es muy parecido solo que las coordenadas cambian para formar una cruz:
private void drawCross(Graphics g){
int left = 0;
int top = 10;
int x0 = left, x1=x0, x2=x1+25, x3=x2+10, x4=x3+10, x5=x4+25,
x6=x4+5, x7=x5, x8=x4, x9=x3, x10=x2, x11=x1, x12=x2-5;
int y0 = top, y1=y0,y2=y1, y3=y2+15, y4=y2, y5=y4, y6=y5+25,
y7=y6+25, y8=y7, y9=y8-15, y10=y8, y11=y10, y12=y6;
g.setColor(0xB54E41);
g.setBackgroundColor(isFocus() ? 0xEEEEEE : 0xFFFFFF);
drawBackground(g);
g.setDrawingStyle(Graphics.DRAWSTYLE_AAPOLYGONS, true);
int[] xPts = {x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12};
int[] yPts = {y1,y2,y3,y4,y5,y6,y7,y8,y9,y10,y11,y12};
g.drawFilledPath(xPts, yPts, null, null);
g.setDrawingStyle(Graphics.DRAWSTYLE_AAPOLYGONS, false);
}
Y finalmente la clase completa
public class CustomCheckBox extends CheckboxField{
public CustomCheckBox(){
super();
}
public CustomCheckBox(boolean check){
super("",check);
}
public void paint(Graphics g){
if(getChecked()){
drawCheck(g);
}else{
drawCross(g);
}
}
protected void drawFocus(Graphics g, boolean focus){
//do nothing
}
protected void onFocus(int direction){
super.onFocus(direction);
invalidate();
}
protected void onUnfocus(){
super.onUnfocus();
invalidate();
}
protected void layout(int width, int height){
width = 71;
height = 71;
setExtent(width, height);
}
private void drawCheck(Graphics g){
int left = getBorderLeft();
int top = getBorderTop();
int x0 = left, x1 = x0, x2 = x1+20, x3 = x2+50, x4 = x3,
x5 = x4-50, x6 = x5-20;
int y0 = top, y1 = y0+30, y2 = y1+15, y3 = y2-45,
y4 = y3+25, y5 = y4+45, y6 = y5-15;
g.setColor(0x5B9058);
g.setBackgroundColor(isFocus() ? 0xEEEEEE : 0xFFFFFF);
drawBackground(g);
g.setDrawingStyle(Graphics.DRAWSTYLE_AAPOLYGONS, true);
int[] xPts = {x1, x2, x3, x4, x5, x6};
int[] yPts = {y1, y2, y3, y4, y5, y6};
g.drawFilledPath(xPts, yPts, null, null);
g.setDrawingStyle(Graphics.DRAWSTYLE_AAPOLYGONS, false);
}
private void drawCross(Graphics g){
int left = 0;
int top = 10;
int x0 = left, x1=x0, x2=x1+25, x3=x2+10, x4=x3+10, x5=x4+25,
x6=x4+5, x7=x5, x8=x4, x9=x3, x10=x2, x11=x1, x12=x2-5;
int y0 = top, y1=y0,y2=y1, y3=y2+15, y4=y2, y5=y4, y6=y5+25,
y7=y6+25, y8=y7, y9=y8-15, y10=y8, y11=y10, y12=y6;
g.setColor(0xB54E41);
g.setBackgroundColor(isFocus() ? 0xEEEEEE : 0xFFFFFF);
drawBackground(g);
g.setDrawingStyle(Graphics.DRAWSTYLE_AAPOLYGONS, true);
int[] xPts = {x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12};
int[] yPts = {y1,y2,y3,y4,y5,y6,y7,y8,y9,y10,y11,y12};
g.drawFilledPath(xPts, yPts, null, null);
g.setDrawingStyle(Graphics.DRAWSTYLE_AAPOLYGONS, false);
}
private void drawBackground(Graphics g){
g.clear();
}
public boolean isFocusable(){
return true;
}
}
Look ma! custom controls with no images!
El tema caliente de la semana es Google Buzz. Para muchos un quierosertwitter, para otros Twitter como debió ser desde el inicio. ¿Pero que opinan los Geek&Rollers del tema? Veamos:
Axel
No lo he checado porque me enmulé porque no hay en google apps for your domain, pero lo checo y te envío la opinión.
Rafyta
O sea que como no pego el wave a ver si con esta onda se arma?
Boynas
Cuantas veces hemos discutido en twitter y hemos sentido que es molesto para los que siguen nuestro timeline (respeto a los demas en contra de la funcionalidad).
La integracion a otros servicios tanto de fotografias, videos y contenido en general, se me hace menos forzada que la de twitter. Tiene mas features nativos.Lo mas importante es que es mainstream. No necesito enseñar a un amigo a usarlo, es simple y amigable. A mi me interesa seguir a todo mundo no solo a geeks o a media freaks pesudo-periodistas, que son los que se meten a twitter. Esa es la unica razon por la que tengo FB!
Creo que Buzz es como twitter made right, tiene las threaded comments de FB sin las molestas apps; Sin embargo es ordenado no necesitas brincar de timeline en timeline para seguir una conversacion en la que comento una persona que no conoces.Buzz esta tapando ese gap. Es lo que debio haber hecho twitter con su red de usuarios hace mucho tiempo.. Es perfectamente un twitter killer. (no mames, hasta rima)
César
Tiene más sentido que Twitter, para mi. Gmail siempre esta abierto en mi navegador. Ahora nomas falta que todos dejen de usar Hotmail y se pasen a Gmail, cosa que no se por qué no ha sucedido todavía. Ah, y que le arreglen eso de que se autorefresca el sitio pero te sigue marcando items no leídos. Y una opción para que cuando leo algo en Buzz, no me aparezca como no leído en la bandeja de entrada de Gmail.
Lo mejor de todo es que, en mi opinión, los clientes exclusivos van a perder relevancia, haciendo mucho más relevantes cosas como lo que está haciendo Ubuntu con su Me Menu y Gwibber. Si todo sale bien, vamos a estar un paso adelante. Eso si, su uso desde el Web siempre va a ser una mejor experiencia, como Google nos tiene acostumbrados.
¿De acuerdo? ¿Desacuerdo? Usen la caja de comentarios. Nos vemos en Buzz.
Un proceso es un instrumento de autoridad. Un proceso es una proclamación de qué hacer, cómo debemos de hacerlo y en qué orden. Un proceso es conservador, jerárquico y formal. Un proceso mantiene el status quo. Es la administración imponiendo orden y control desde arriba. Si los procesos fueran un partido político, sería de derecha.
Es fácil ser seducido por las bondades de la metodología ágil. Promesas de equipos auto suficientes, entregas frecuentes y listas para producción, Yippi-kay-ay. Demasiado proceso y en vez de avanzar nos quedamos llenando reportes y formas; muy poco proceso y todo se vuelve un manojo de actividad descontrolada y poco empuje (y entrega).
El artículo discute la etiqueta “ágil” que tanto se usa en administración de proyectos de software hoy en día. Por ahí leí que “scrum” (intercambiado por ágil en esta ocasión) no es una bala de plata para tener proyectos exitosos. Existen factores como la experiencia y motivación del equipo, así como también la naturaleza del proyecto, por lo que una aproximación orientada a personas tiene más sentido que orientado a procesos, y viceversa.
Lean el artículo fuente (en Inglés), y los invito a dejar sus comentarios sobre el tema, experiencias personales, etc.
Debido a que ocurrió un overflow cuando intentamos pagar el dominio, GoDaddy no permitió el acceso a este blog por medio de nuestro dominio. Los detalles no los se, solo que el BigInt que utilizan para guardar la cantidad del pago no alcanzó, y por tanto el overflow, causando todo tipo de problemas.
Gracias por su paciencia. Estamos de vuelta, keep on Geek&Rolling!
Hace poco decidí cambiar de modelo de BlackBerry, de la viejita 8110 a la un poquito más moderna 8520. Al ir a Telcel me dijeron que con mi plan era imposible cambiar al equipo que yo quería, aún cuando quisiera pagar el costo total del mismo.
Como en Telcel me la hicieron difícil, compré el equipo aparte y le cambié el chip. Hasta ahí todo bien, sin embargo al llegar la factura veo que me cobran la conexión de datos, aún cuando mi plan incluye datos ilimitados. En la factura me cobran el plan (con datos ilimitados incluidos) más los datos consumidos. Obviamente algo andaba mal. Después de dos visitas al centro de “atención” al cliente – que de atención no tiene nada – no me pudieron resolver mi problema. Las dos personas que me atendieron coincidían en que “que raro!?!?” y levantaron un reporte.
Gracias a que tengo a una persona conocida que trabaja en el corporativo, después de unos cuantos SMS’s el problema quedó aclarado y resuelto. Bueno, resuelto a medias porque voy a tener que pagar el cargo excesivo.
El problema, y lo que nunca me pudieron explicar en el centro de pseudo-atención, fue que al cambiar de equipo si tienes un plan de datos ilimitados, esto no se te respeta. En ningún lugar te lo indican, tampoco te lo advierten en Telcel. Y lo que es peor, nunca me lo superion resolver. Tuve que usar “palancas” del corporativo para que me resolvieran, ya que los asesores del centro de atención se limitaron a rascarse la cabeza. Nunca me preguntaron ¿No cambió su equipo señor?
Así que si tienen una BlackBerry y deciden cambiar de equipo, antes de meter su chip en el equipo nuevo, vayan a su centro de atención y pidan que les hagan el cambio para evitar cargos excesivos. Esta información la deberían de proporcionar de primera mano en Telcel, pero como siempre con prácticas poco éticas para sacar hasta el último centavo.
No iba a proporcionar información, pero por el coraje que me hicieron pasar les muestro una captura de pantalla de lo que será Everlasting Flame 2.0. Descárguenlo y eviten pagarle más de la cuenta a Telcel.

Everlasting Flame 1.2 w/OS 5 fix.
A TextMate syntax compatible source editing widget. Current adapters are for SWT.

Your question is about GWT supporting ProcessBuilder, but the error you get is from Google App Engine and not GWT related.
If you are using ProcessBuilder from a GWT RPC method you shouldn't have any problems. However, you are using Google App Engine as your application server. Google App Engine doesn't support ProcessBuilder, and a bunch of other things are not supported by GAE.
Check out the Will it play in Google App Engine? as a reference to know if your particular feature is supported in GAE.
It's important to note that ProcessBuilder is not supported by Google App Engine. GWT uses regular Java in its RPCs so ProcessBuilder can be used there.
Hi, I have the following requirement: Based on some user input, I need to generate a HTML form that the user can embed on a separate Web application. I thought on doing this with GWT since I'm familiar with it.
I'm clear on the input parsing and widget generation part. What I don't know how to do is how to export the root widget's (most probably a Panel) compiled code, so the user can take the code and include it in some other page.
Something like:
String rootPanelCode = rootPanel.exportCode();
Dialog codeDialog = new DialogBox();
codeDialog.setText(rootPanelCode);
Then the user copies the displayed code in some HTML file:
<script type="text/javascript" language="javascript">
//copied code goes here
</script>
Requiring a particular <div id="required_id" /> in the HTML file is not a problem. Or maybe javascript code is not enough, and the user is required to download a zip file with js and html files, copy those to a directory and reference them in the page. This again is not a problem.
Is my use case possible with GWT?
Thanks in advance.
Try this:
public class DisposeJFrame extends JFrame{
JPanel panel = new JPanel();
JButton button = new JButton("Dispose JFrame");
public DisposeJFrame(){
super();
setTitle("Hi");
panel.add(button);
add(panel);
pack();
button.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent arg0) {
dispose();
}
});
}
public static void main(String args[]){
SwingUtilities.invokeLater(new Runnable(){
public void run(){
DisposeJFrame jf = new DisposeJFrame();
jf.setVisible(true);
}
});
}
}
You can use ant to run your tests with a single command with the junit ant task. Here's an example on how to use it:
<target name="runtests" depends="clean,compiletests">
<junit printsummary="yes" haltonfailure="no">
<classpath>
<path refid="test.classpath" />
<pathelement location="${test.classes}"/>
</classpath>
<formatter type="xml"/>
<batchtest fork="yes" todir="${test.reports}">
<fileset dir="${test.src}">
<include name="**/*Test*.java"/>
</fileset>
</batchtest>
</junit>
</target>
That target uses batchtest which is part of the junit ant task. It sets your test classpath so all your tests that contain the Test.java pattern in their class name will be included. Check out the JUnit Task documentation.
With my current customer we are required to develop on Windows (virtualized, running on client owned servers) and deploy on AIX. With other customers I develop on Ubuntu and deploy to whatever OS the customer requires or already have. Just be sure to have a staging server mirroring the production architecture as close as possible and test there.
It's possible to do it with PHP. Not a typical use case scenario but it can be done. Since you are on Windows, a bat file would be better suited since then you don't need the PHP parser to run the script.
Put the same commands you would run in the console to convert your audio files with LAME in a *.bat. Then run the bat as if it was a regular executable file.
I don't see anything wrong with using JPanels. Here's my implementation:
First a ChessSquare, this represents one cell on the board:
public class ChessSquare extends JPanel{
int x,y;
public ChessSquare(int x, int y){
super();
this.setPreferredSize(new Dimension(50,50));
this.setBorder(BorderFactory.createLineBorder(Color.black));
this.x = x;
this.y = y;
}
}
Now the main board panel:
public class ChessPanel extends JPanel{
JPanel positions[][] = new JPanel[8][8];
ChessSquare move[] = new ChessSquare[2];
public ChessPanel(){
initComponents();
}
private void initComponents(){
setLayout(new GridLayout(8,8));
for(int i=0;i<positions.length;i++){
for(int j=0;j<positions[i].length;j++){
ChessSquare square = new ChessSquare(i,j);
square.addMouseListener(new MouseListener(){
public void mouseClicked(MouseEvent me) {
ChessSquare cs = (ChessSquare)me.getComponent();
if(isValidMove(cs)){
System.out.println("Valid move!");
System.out.println("x1: "+move[0].x+" y1: "+move[0].y);
System.out.println("x2: "+move[1].x+" y2: "+move[1].y);
System.out.println("");
resetMove();
}
}
//Other mouse events
});
positions[i][j] = square;
add(square);
}
}
}
private boolean isValidMove(ChessSquare square){
//here you would check if the move is valid.
if(move[0] == null){
move[0] = square;
return false; //first click
}else{
move[1] = square;
}
//Other chess rules go here...
return true;
}
private void resetMove(){
move = new ChessSquare[2];
}
}
We keep a JPanel matrix to represent the board, and ChessSquare array to represent the current move. In isValidMove() we check to see if the current move is complete (both squares have been clicked, thus the move array already has one element). Once a move is complete, we reset the move and start again.
Use git. You have all the version control system benefits, but working locally. If your project code is already in SVN, it's possible to use git-svn to make both git and svn collaborate. Here's an easy to follow guide on git-svn by example.
With git it's easy to branch so you'll want to branch very often. Git branches are different from SVN branches: they are stored locally and it's not simply a copy of your whole project like in SVN. Finally, Set up Dropbox in both computers so your changes are synched automatically.
So your workflow could be something like this:
git-svn clone http://mysvnrepo local_dir to get your local repositorygit checkout -b my_new_branch when you want to work on a new featuregit merge my_new_branchgit-svn rebase and then commit with git-svn dcommitYou need to use a ListIterator you use that to traverse the List in either direction. The iterator contains methods such as previous() and next(). Check it out in the Javadocs.
To get the ListIterator for your current list, call its listIterator(int index) method.
There's no way you used the JRE to compile Java programs. javac, the Java compiler, only comes with the JDK.
Even when approaches like serializing objects and then deserializing them is useful, you have to make sure you understand first why your objects "disappear".
HTTP, the protocol used to retrieve pages and other resources from Web servers, is stateless. It basically means one request knows nothing from another request, even when it came from the same user. Think of it this way, when you request your PHP page, the script is run and after it finishes Apache sends out the result to you. When you request the page again, it does the same thing as if it was the very first time you did it. It's stateless.
There are techniques to keep state between requests (make it to not forget your objects) and those involve things like cookies or URL rewriting. But you have to keep in mind the stateless nature of HTTP (and thus your PHP script) when developing Web applications.
I don't know what you are looking for. But after installing the Subclipse plugin, you should have a new entry in the File | New | Project dialog. Something along the lines of "Checkout project from SVN"
Then when you hit continue, you can enter your SVN repository details, check the branch you are interested in, etc. After checking out a project, you can right click on it and go to the "Team" submenu to get the features provided by Subclipse like check in code, diff, merge, etc.
If your target is Windows, you need to look at the autorun.inf file specification. This file needs to be located in the root directory, and you can use it to specify any program you want to run when the device is inserted. Please note that the feature can be disabled by the user.
The part to check if there's a new version and download it, etc... that depends heavily on the language you are using to develop such program.
While reading about OO design and programming you'll come across two concepts: coupling and cohesion. The former is about how each class depends on each other, and the later is about a class focusing on those things that are its responsibility.
Without getting deeper on the topic, I bring up those two concepts because it has helped me a lot to thing on those terms. The first step is to be clear on what your application must do. Think about the "happy path" as well as what happens when things go wrong, for example the user not filling in the right information.
Now start designing your classes, how those relate and what each class provides to the system as a whole. This design phase is typically represented as a set of UML diagrams, but some written paragraphs would do if you are not familiar with UML. If you see a class is doing things that don't belong there, change your design. It's inexpensive to change it while on paper.
Don't start thinking on how to implement certain functions just yet. For example if your application will use the GPS hardware, don't worry on how to access it. Suppose that part is solved. Start thinking on what you'll do with the data? Which class will receive that data? Who's going to process it?
If what you want is minimum dependency with external files or DLLs you could statically compile all the required DLLs with the tool exe. Then you could use something like Visual C++ to develop such tool.
You defined AssocCovList to have the following properties:
Integer id
Integer association_id
Integer cov_list_id
Date edit_date
And then try to create a new AssocCovList(association_id:3) using only the association_id. However, by default all properties are both persistent and required. To create a new AssocCovList you would need to provide also the id, cov_list_id and edit_date.
An AJAX request contains the same request/response information as a traditional HTTP request. You can set cookies on the client once the async callback is executed, etc.
REST stands for Representational State Transfer, and it was proposed in a doctorate dissertation (see here). It uses the four HTTP methods GET, POST, PUT and DELETE to execute different operations. This in contrast to SOAP for example, which creates new arbitrary commands (verbs) like getAccounts() or applyDiscount()
A REST API is a set of operations that can be invoked by means of any the four verbs, using the actual URI as parameters for your operations. For example you may have a method to query all your accounts which can be called from /accounts/all/ this invokes a HTTP GET and the 'all' parameter tells your application that it shall return all accounts.
If you want to create your own borderless window, instead of using a Frame/JFrame use a Window/JWindow. Frame/JFrame are extensions to Window/JWindow that provide borders and the maximize, minimize and close buttons. Usually those widgets are provided by the OS, but you can override them.
When you compile something in Java, the compiler generates bytecode. This is native code for the Java Virtual Machine. The JVM then translates the bytecode to native code for your processor/architecture, this is where the JIT happens. Without JIT, the JVM would translate the program one instruction at a time, which is very slow.
While XPath is a great choice, I would recommend JDom if your XML document is not huge, since it loads the entire document in memory.
Using JDom:
try {
SAXBuilder builder = new SAXBuilder();
Document firstDocument = builder.build(firstFile);
Document secondDocument = builder.build(secondFile);
Element firstRoot = firstDocument.getRootElement();
Element secondRoot = secondDocument.getRootElement();
List<Element> sourceListPost = secondRoot.getChild("listPost");
firstRoot.addContent(sourceListPost);
Document merged = new Document(firstRoot);
} catch(JDOMException e) {
e.printStackTrace();
} catch(IOException e) {
e.printStackTrace();
}
Now merged contains the merged Document. You can serialize it to a file with XMLOutputter.
You don't need an applet, from a grails controller you may use any Java library. Use the Java printing services available to the runtime in javax.print. This is assuming that the printer is installed where the grails runtime is running.
URLDecoder.decode(url);
See related question http://stackoverflow.com/questions/623861/how-do-you-unescape-urls-in-java
I think you would benefit greatly with a build tool, such as ant or maven. You can have a target to compile only one class without building the whole code, or any other related task.
There's nothing wrong with the way you are compiling, it's just cumbersome but certainly not wrong.
That being said, create a src directory to store your .java files, keeping your directory structure coherent with the package structure of your classes. In this case you would have src directory and inside it, directory A and directory B. Inside A put Test1.java and inside B put Test2.java
Then:
javac B/Test2.java
Why Test2.java? Because it depends on A, then the compiler is smart enough to first compile A/Test1.java and then B/Test2.java. At this point you have each .class files inside A and B
To run it:
java B.Test2
My only advise would be don't go that way. As Bill K already said, most implementations would be significantly faster and more complete. Even more important is that there are excellent resources to achieve what you are trying to do: OSGi for example which has Eclipse and Glassfish v3 under its belt.
Personally I implemented something similar to your description, loading plugins at runtime without needing to restart the container. It was a nightmare to maintain and debug. And more important, while it was relatively easy for me to implement new modules (after all, I designed the thing), it was very difficult to program to. I ended up learning a lot about classloaders, but that was it.
If you fix the scaleMod and initialDistance to powers of 2 you could use shifts for faster multiplication and division.
See here for reference.
Check out Web Harvest. It's both a library you can use and a data extraction tool, which sounds to me that's exactly what you want to do. You create XML script files to instruct the scraper how to extract the information you need and from where. The provided GUI is very useful to quickly test the scripts.
Check out the project's samples page to see if it's a good fit for what you are trying to do.
JComboBox constructor can take a ComboBoxModel as argument. DefaultComboBoxModel is a concrete implementation of the ComboBoxModel interface.
So, if you have a Personel class:
class Personel{
String personelName;
int personelId;
//getters, setters
//This will be your display member
@Override
public String toString(){
return this.personelName;
}
}
And supposing you obtained all personel via JDBC and have it stored in a new Vector, you can do:
DefaultComboBoxModel comboModel = new DefaultComboBoxModel(personel);
JComboBox myCombo = new JComboBox(comboModel);
At runtime, you can getModel and setModel to access the JComboBox model. The display member will be Personel's toString() method. The value member will be the actual object stored in the DefaultComboBoxModel vector, in this case a Personel instance.
I suggest you take a look at the API documentation for ComboBoxModel and DefaultComboBoxModel.
You would use a regular expression to search for @username and then turn that to the corresponding link.
I use the following for the @ in PHP:
$ret = preg_replace("#(^|[\n ])@([^ \"\t\n\r<]*)#ise",
"'\\1<a href=\"http://www.twitter.com/\\2\" >@\\2</a>'",
$ret);





