
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.
… O por qué el .torrent debe morir y dar paso al siguiente escalón evolutivo.
Recientemente The Pirate Bay, uno de los sitios con más cojones que existe en el planeta, anunció que relegaría el uso de archivos .torrent y se enfocaría principalmente en los llamados magnet links. Sus argumentos son muy válidos, e inmediatamente se dejaron venir olas de desinformación. Que si The Pirate Bay habían doblado las manitas y cedieron ante la presión de alguna organización. Que si SOPA. Que si PIPA. Que si es el fin del mundo como lo conocemos, o por lo menos del P2P facilitado por el protocolo Bittorrent.
Nada de eso puede estar más alejado de la verdad. Como todo, el uso de la Distributed Hash Table (DTH) y Magnet Links sobre los ya tradicionales archivos .torrent tiene sus ventajas y desventajas que es lo que precisamente vamos a explorar aquí.
Durante mis estudios de maestría, hice investigación en el tema de las redes inalámbricas de sensores (WSN por sus siglas en Inglés) y cómo múltiples dispositivos de bajo poder de procesamiento, podían colaborar para cubrir una área extensa. Esto tiene retos interesantes muy bien documentados en la literatura, pero una de las cosas que más llamó mi atención es la diseminación de datos entre los pares que forman la red. Estamos hablando de una red creada impromptu, sin infraestructura previa, que necesita compartir datos de manera continua. Tal vez definirla como una red P2P tenga sentido, pero quiero dejar al lado las connotaciones negativas que arrastra este término, similar a lo que sucede con “Pirata” o “Nazi”.
En aquella época pensaba en una WWW descentralizada. La arquitectura actual de Internet ha pasado la prueba de escalabilidad: millones de nodos conectados, compartiendo millones y millones de paquetes. Además, cualquiera puede entrarle al juego, conectarse y compartir. Sin embargo uno de los servicios clave de Internet, o por lo menos de los más populares, es completamente centralizado. Estoy hablando de la Web y protocolos relacionados. La “simplicidad” en la arquitectura de la Web es tanto su mayor bendición, como su talón de Aquiles ya que la hace altamente vulnerable a distintos ataques. Los ataques de negación de servicio (DoS, infames ahora gracias en parte al colectivo Anonymous) son un ejemplo claro, aunque en este caso la solución no está al nivel de la implementación de la Web, sino dos capas más abajo (o 3 si consideran HTTP como capa de aplicación o de presentación) en la capa de transporte.
Otro ataque menos complejo (y menos efectivo) es el que enmarca la referida como ley “SOPA”. Esto no es más que eliminar el registro DNS de un sitio determinado. Una vez que esta eliminación sea diseminada en la mayoría de los servidores DNS que forman la World Wide Web, prácticamente nadie podría acceder al sitio atacado via URL. El sitio seguiría existiendo y sería accesible via IP, solo el nombre que hace referencia al sitio dejaría de funcionar. Una Web descentralizada resolvería estos problemas; una Web que no dependiera de un solo servidor central para operar. Donde fuera posible hacer privadas secciones de la Web, o conectarlas a la nube para formar parte de la Web pública. Donde todo, desde la resolución de nombres hasta las peticiones HTTP se basen en un protocolo P2P y no en un servidor central. Una Web imposible de censurar, controlada por todos y por nadie. Una Web apoyada en redes centradas al contenido como fue propuesto por Ted Nelson e investigado por Van Jacobson.
Lo que tenemos actualmente
Internet no fue concebido para una Web de tal naturaleza. En sus orígenes, Internet fue concebido para habilitar la transferencia de datos no solo entre computadoras incompatibles, sino también entre distintas redes de computadoras. Esta red de redes proporciona un medio adecuado para la comunicación de datos entre dos computadoras que se encuentran, posiblemente, distribuídas alrededor del mundo. Sin embargo, con el uso masivo que se le da a Internet actualmente, el problema básico que se trató de solucionar con la arquitectura de Internet ha cambiado. El nuevo modelo de uso de Internet impone otro tipo de retos a la arquitectura unicast y multicast sobre la que está basado, caracterizándose por:
Ejemplos de aplicaciones que utilizan a Internet con este nuevo modelo incluyen aplicaciones Web populares, redes de intercambio de información, agregadores de noticias, redes inalámbricas de sensores, descubrimiento de servicios y juegos masivos multijugador, entre otras. ¿Qué tienen en común estas aplicaciones? que el flujo de comunicación se determina por los intereses específicos de quien recibe información, contrario a lo que sucede actualmente en Internet, donde se utiliza una dirección específica asignada por quien envía los datos.
Van Jacobson propone una red en donde cualquier dispositivo que pueda mover datos, y tenga datos válidos, tenga la oportunidad de atender la petición. En dicha red se eliminan dos cosas:
Actualmente existen aplicaciones que implementan algunas de las ideas expuestas en la teoría de redes centradas al contenido. Estas aplicaciones crean una capa sobre la red existente (denominada overlay) y proporcionan servicios orientados al contenido, utilizando como transporte a la pila TCP/IP. Uno de estos overlays es precisamente Bittorrent.
Bittorrent como overlay centrado al contenido
Bittorrent es un protocolo de aplicación, es decir forma parte de la capa 6 en el modelo OSI. Bittorrent sirve para la distribución de archivos de gran tamaño sin la necesidad de un repositorio central. ¿Suena conocido? Los clientes inician una transferencia conectándose a un servidor central, que les comparte información de otros clientes que se encuentran compartiendo el mismo archivo. Una vez obtenida esta información, los clientes se conectan entre si para iniciar la transferencia.
Analicemos un poco más de cerca cómo se inicia una transferencia:
El overlay creado por los nodos participantes en una transferencia Bittorrent forman una arquitectura híbrida descentralizada, en donde el tracker facilita la comunicación entre los distintos clientes. Una vez que varios clientes se conectan entre si, se elimina la necesidad del tracker siempre y cuando los clientes mantengan su conexión. Si eliminas el tracker, ningún otro cliente puede unirse a la red formada por los clientes conectados (llamada swarm o enjambre).
Ya podemos determinar dos puntos críticos de Bittorrent:
Mejorando Bittorrent. Magnet Links y Distributed Hash Table.
Eliminando los dos puntos críticos expuestos anteriormente, Bittorrent se convierte en un overlay completamente descentralizado. ¿Pero cómo pueden encontrarse los clientes entre ellos, sin la existencia de un servidor central que los coordine? Tanto los Magnet Links como la Distributed Hash Table (DHT) juegan un papel determinante en la descentralización de Bittorrent.
El concepto de una DHT no es nuevo, su investigación y desarrollo fue motivado en parte por las redes P2P como GNUtella y Napster. Dos aproximaciones muy distintas al mismo problema:
Bittorrent adoptó una DHT para sustituir o complementar el tracker. De hecho, algunos clientes Bittorrent permiten al usuario evitar el uso del tracker, y solo recibir clientes que vengan directamente de la DHT. La implementación de la DHT de Bittorrent es basada en Kademlia. Los nodos que forman el overlay se comunican utilizando UDP y son asignados un ID, y es este mismo ID el que es utilizado por la red para localizar el valor buscado (usualmente un hash de un archivo). Las búsquedas son restringidas a O(log(n)) nodos, por aquello de la eficiencia.
Todo bien, pero aún es necesario que un cliente se conecte al enjambre formado por la DHT. A esto se le conoce como proceso de inicialización o bootstrap. En esta fase, el cliente necesita conocer la dirección IP de alguno de los nodos participantes, quien se encargará de diseminar el ID del nuevo nodo al resto de la red.
Aún eliminando la necesidad del tracker con la DHT, queda el inconveniente del proceso de inicialización, para lo cual el .torrent sigue siendo necesario. Para solucionar este inconveniente se desarrollaron los Magnet Links. Un Magnet Link en realidad es un esquema URI nuevo. ¿Un que? Un esquema URI se refiere a la estructura para nombrar recursos de manera uniforme. Seguramente se habrán topado con direcciones como file:, news:, http:, ftp:, mailto:, entre otros. Bueno pues esto forma parte de un esquema de nombramiento regulado por la IANA, y tiene una estructura fija.
Entonces, el esquema URI Magnet forma lo que llamamos Magnet Links, que son utilizados principalmente para referirnos a recursos disponibles para ser descargados de redes P2P. Un Magnet Link, contrario a un link regular, apunta a un archivo basado en su contenido o metadatos y no en donde se encuentra el archivo. Si encontramos similitudes con el contenido de un archivo .torrent, no es ninguna casualidad. Al igual que la investigación y el desarrollo de las DHT, el esquema Magnet fue desarrollado como parte de otros esquemas URIs utilizados en los proyectos eDonkey2000 (esquema ed2k:) y Freenet (esquema freenet:).
Un Magnet Link contiene uno o mas parámetros, que le indican al cliente de donde iniciar la descarga. Por ejemplo, un link puede contener el nombre del archivo, su tamaño en bytes, el hash del archivo, un link Web tradicional que se considere aceptable para descargar el archivo, palabras clave para realizar búsquedas del archivo, la dirección de un tracker Bittorrent, entre otras cosas. Ventajas del uso de magnet links sobre archivos .torrent es que pueden ser compartidos simplemente copiando y pegando el text en correos o mensajería instantánea, en comparación de los archivos .torrent en donde se tiene que enviar el archivo para iniciar la transferencia.
The Pirate Bay elimina el uso de .torrent
Lo que nos lleva finalmente a la decisión de The Pirate Bay de dejar de ofrecer archivos .torrent como fuente de información principal (los .torrent siguen estando disponibles, pero no son la opción por defecto) para conectarse a un enjambre, favoreciendo a los Magnet Links.
La decisión anterior les ahorra mucho ancho de banda ya que no se tienen que descargar archivos .torrent. Además los Magnet Links son mas difíciles de bloquear, y aún no se ha probado en la corte que tener Magnet Links en una página sea algo ilegal (aunque seguramente no tardarán en probarlo).
Pero mucho más importante que esto es el paso que se da hacia un overlay completamente descentralizado, en donde no sea necesario el tracker ni el uso de archivos .torrent por los usuarios (en realidad el protocolo Bittorrent depende de los archivos .torrent, pero usando Magnet Links los usuarios no tienen que descargar el archivo manualmente). Si, sigue existiendo la necesidad de un directorio en donde se puedan buscar Magnet Links, y el bootstrap es mas lento, pero el ahorro de ancho de banda, además de descentralizar la localización del .torrent justifica su uso.
Conclusión
Como vemos, es posible actualmente usar Bittorrent para compartir archivos de gran tamaño de manera descentralizada. Esto tiene la gran ventaja de ser menos propenso a ataques de censura (como SOPA y PIPA) y permite distribuir la carga de distribución entre los mismos clientes, en vez de en un solo servidor central.
En mi opinión, el futuro de la red es hacia una red completamente descentralizada, centrada al contenido. Ya sea implementada a nivel físico, o como un overlay sobre la existente. Las redes centradas al contenido se presentan como una evolución a la estructura tradicional de las redes actuales. No es que la solución actual (el protocolo TCP/IP) no sirva, sino que el problema original ha cambiado. La necesidad actual es una forma de diseminar datos y no de simplemente tener conversaciones entre dos puntos finales. La diferencia entre diseminación y conversación es que una diseminación puede ser uno a uno, uno a muchos o muchos a muchos. Claramante se observa que una conversación es solamente un caso especial (uno a uno) de una diseminación.
Una red centrada al contenido como la que propone Jacobson soluciona, por diseño, muchos de los problemas con los que se enfrenta Internet actualmente (siendo la censura uno de ellos). El hecho de que los datos mismos puedan ser validados y no se dependa de la seguridad del canal por el cual fueron transmitidos permite una diseminación oportunista, es decir, una red en donde cualquier dispositivo capaz de mover datos puede y será utilizado. La diseminación oportunista haría prácticamente imposible situaciones como la negación de servicio por parte de proveedores de Internet, o la eliminación de la neutralidad de Internet. Los usuarios se vuelven administradores de sus propios canales de comunicación, ya que pueden solicitar solo aquel contenido que le interesa, y la prioridad de éste (deseo obtener el correo electrónico de mi lugar de trabajo, y el noveno juego de la serie mundial de béisbol). La habilidad de definir solamente el contenido de interés elimina ataques del tipo negación del servicio ya que los altos volúmenes de tráfico no solicitado nunca llegarían a los canales de comunicación de la víctima si éste no lo solicita explícitamente.
A lo largo de la historia, hemos visto como la guerra impulsa a la ciencia. Por un Internet libre, abierto, neutro y sin censura.
Rocksmith que promete ser la evolución natural de los juegos de ritmo, con una diferencia muy interesante: el gancho no son trofeos virtuales, o un 100% en la dificultad más alta. El gancho y recompensa es el aprender a tocar la guitarra.
Apenas llevo un día con el juego/tutor de guitarra y esta es mi experiencia con la versión para PS3. Lo primero que haces es meter el juego en la consola y… claro, hay que descargar una actualización. 11 MB después ya puedes ver la pantalla de inicio del juego, que incluye un video en donde se ve a una persona tocando la guitarra nota por nota empezando en un nivel muy básico y progresando hasta un nivel decente, lo cual en la vida real lleva años de práctica y dedicación. El video hace un buen trabajo en animarte a tomar el juego y dedicarle tiempo, hype si asi lo quieren.
Lo que sigue es conectar la guitarra. El paquete del juego incluye instrucciones de como es mejor conectar todo para evitar el lag, desde los pickups de la guitarra hasta las bocinas de la TV o el sistema de sonido que tengan conectados a la TV. La mejor opción es usar HDMI para el video, pero solo para el video. El audio conectarlo ya sea por cables compuestos, y de preferencia a un teatro en casa o sistema de sonido externo. En mi caso lo tengo conectado de la salida óptica del PS3 al sistema de sonido externo, y el lag es práticamente negligible.
El paquete incluye el llamado Real Tone Cable, que es el que conecta la guitarra a la consola. La longitud del cable es adecuada, y se siente bastante profesional, no como algo de juguete. Si creían que no se podía tener más periféricos, esperen a tener una guitarra real conetada a su consola. Al inicio del juego te indica que no conectes nada extra entre tu guitarra y la consola, es decir el cable debe ir directo de la guitarra al PS3. Después te pide que selecciones entre derecho o zurdo y si el headstock de tu guitarra es de 3+3 o de 6 en línea, con imágenes descriptivas por si no sabes de lo que estoy hablando.
Entonces si, viene lo bueno. Primero te dice como agarrar el pick, pero como en 2 segundos lo cual no es suficiente porque siendo un novato tienes muchas dudas sobre cual es la manera correcta de agarrarlo, o por lo menos así fue en mi caso. Luego te indica el concepto de nota, fret, nota abierta y te hace tocar un riff, que luego te das cuenta que es el famoso riff de (I can’t get no) Satisfaction por los Rolling Stones, así que si conoces la canción te emocionas porque crees que ya sabes y estas listo para rockear a lo grande.
El juego es difícil, pero así es como debe de ser. Aquí no puedes aventarte una canción sin conocerla y sacarla perfecta como en Guitar Hero o Rock Band. Recuerda que estas tocando guitarra real, así que lo mas recomendable es ir paso a paso, practicar la canción hasta que los riffs y los acordes salgan decentes y de hecho te memorices las partes, de otra manera es casi imposible improvisar y mover tu mano a los frets correspondientes.
En mi caso tuve algunas ocaciones en las que el juego no detectaba correctamente la nota. Es decir, el juego me pedía el tercer fret de Mi (o la cuerda E para los gringos) y presionaba eso precisamente, pero el juego lo detectaba como una nota más arriba, o más abajo, lo cual hace las cosas muy frustrantes. En modo práctica pasa más seguido al grado que hace imposible pasar la práctica. Leyendo en los foros me entero que la tonalidad puede afectar, o el treble, así que intentaré moverle a todos los switches y potenciómetros de mi guitarra a ver si puedo arreglarlo. Me gustaría tener la oportunidad de probarlo con otra guitarra, a ver si el efecto es el mismo.
Cuando menos lo pensé, ya tenía 2 horas de práctica en la guitarra. Creo que Rocksmith cumple con su cometido de una manera excelente. Falta ver los resultados, pero en un par de iteraciones más, yo veo una potencial revolución en la manera en la que se enseña a tocar guitarra. Si se complementa con algo más serio como videos que muestren técnicas al tiempo que el software califica tu ejecución, creo que existe la posibilidad de lecciones interactivas que no aburran.
¿Veredicto? Si son aficionados a la guitarra, probablemente ya tengan una en su casa. Si nunca han podido dominarla y solo la tienen agarrando polvo, van a disfrutar mucho Rocksmith. No es un juego de fiesta como Guitar Hero o Rock Band, necesita tiempo y dedicación. Piensen en Rocksmith como lecciones virtuales entretenidas.
Rock on!
Desde que salió el primer iPad me hicieron y me hice yo mismo la pregunta ¿Para qué querría yo una tablet? En mi casa tengo una laptop y una desktop, y trabajo en mi oficina en casa así que siempre tengo una computadora disponible. Si me voy a la sala a ordenar los recibos del mes, para eso tengo la laptop. Si voy a enseñarles las fotos de nuestro último viaje a mis Papás, generalmente lo hago con el PS3 para poderlas ver en la TV.
Si estoy en movimiento y tengo que trabajar, para eso tengo la laptop. Si solo quiero perder algo de tiempo puedo usar mi iPhone para escuchar música, leer noticias, un juego rápido, entre otras cosas. Aquí es donde muchos podrán decir “para eso te sirve una tablet” pero no realmente. Verán, el tamaño de las tablets las hace lo suficientemente grandes para propósitos de entretenimiento, pero además las hace que llevarlas conmigo no sea automático. Tengo que planear llevarlas conmigo, hacerles lugar, lo que no sucede con el teléfono. Por eso el iPhone siempre va conmigo: es lo suficientemente chico como para llevarlo a todas partes, y suficientemente grande como para pasar un rato leyendo noticias, navegar, platicar y escuchar música. Claro, si tuviera una tablet en ese momento disponible para mi, de seguro leer noticias y navegar sería más cómodo, pero después tengo que guardarla y llevarla conmigo, lo cual no sería tan cómodo.
Una excepción a esto es en el aeropuerto. Probablemente ya llevas una maleta de mano, entonces llevar una tablet es fácil. Pero es la única que se me ocurre.
La pregunta es, si usas una tablet… ¿Cuando y para qué la usas?
It’s time to be immortal, ’cause heroes never die.
Yo fui uno de esos niños que entraron a la primaria de 5 años, gracias a la tenacidad de mis padres al lograr que me aceptaran de esa edad, ya que cumplía los 6 años en Septiembre. A los 8 años tuve mi primera clase de computación en la escuela, y mis padres otra vez preocupados por nuestra educación, nos compraron nuestra primera computadora: Una PC con MSDOS, sin disco duro todo tenía que ser cargado por medio de floppies cada vez que se encendía.
Sin embargo, cuando iba a mi clase de computación, las computadoras eran diferentes. Eran más pequeñas y tenían una colorida manzana mordida como logo. “¿Que computadora te tocó? ¿De la manzanita?” era una pregunta típica al entrar al laboratorio. Todos querían usar las Apple, y yo pasaba horas en el intérprete de Logo tratando de crear figuras interesantes, sin saber que realmente estaba aprendiendo a programar en un dialecto de Lisp. Y esa fue mi primera aproximación a Apple como compañía, y la última por mucho tiempo.
Nunca dejé de sentir curiosidad por las computadoras, y sabía de alguna manera que sea lo que fuere que quisiera hacer con mi vida, involucraría una computadora. Seguí por el mismo camino, observando como Apple se hiciera poco más que irrelevante. En el transcurso, mi interés se movía del mundo de Windows hacia alternativas mejores, que fue como descubrí GNU/Linux allá por el ‘97 o ‘98 en un Red Hat Linux en caja, la versión 5 si mal no recuerdo. Y seguí por ese camino, volteando a ver lo que sucedía en el mundo de las alternativas a Windows.
De pronto y sin mayor aviso (por lo menos a mi), comencé a ver una marea de productos provenientes de Cupertino. Lo primero que captó mi atención fueron las feas (para mi gusto) iMacs e iBooks con el mouse menos ergonómico de la historia. Unas venían con Mac OS 9, un sistema operativo inferior en todos los sentidos a mi querido GNU/Linux (sus “novedades” incluían una herramienta para actualizaciones del OS y soporte multiusuario, cuando GNU/Linux y especialmente Debian lo había tenído desde el día con con APT/Synaptic y su herencia de ser un clon de Unix), pero otras venían con algo nuevo que nunca había visto antes: OSX. Mi curiosidad era demasiada, y cada que me encontraba uno de estos cascos de motociclista de colores, tenía que detenerme a usarlas por un rato. Pero no era por el hardware, sino por el software.
Ya había yo tenido un “acercamiento” a lo que sería OS X, en la forma de Litestep y OpenStep. Antes de dar el salto definitivo a GNU/Linux, probé varios reemplazos para el shell de Windows al mismo tiempo que trataba de pasar el mayor rato posible en GNU/Linux. Uno de tantos reemplazos para el shell era Litestep, inspirado en AfterStep a su vez inspirado de NeXSTEP, el Papá de OS X. Pero OS X era una bestia completamente diferente: una interfaz gráfica con aceleración gráfica, transparencias, efectos de escritorio, todo muchísimo antes que cualquiera lo viera en el escritorio sino hasta varios años después. No solo eran efectos bonitos (bueno, algunos si), había otros que en realidad te ayudaban a ser más productivo (léase exposé). La nueva interfaz gráfica pegó fuerte, y sus efectos se sintieron en otros campos. Windows comenzó a tomar nota aunque reaccionó demasiado tarde, y no se diga la comunidad Open Source, que se pavoneaban con orgullo al salir Compiz (un manejador de ventanas que utiliza OpenGL para aceleración gráfica).
¿Yo? yo solo envidiaba a aquellos con una Mac, y no por la interfaz o por el OS, sino porque podían utilizar un aparato que yo realmente deseaba: un iPod. En aquel entonces una exclusiva para Macs. Es por estas fechas cuando sale el video de 50 Cent “P.I.M.P.” en donde el iPod primera generación recibe tanto tiempo de cámara como el artista. Cuando el iPod estuvo disponible con compatibilidad para Windows (y de manera extraoficial en GNU/Linux), fue cuando volví a usar algún producto de la manzana de manera diaria. Un iPod Nano, segunda generación. Nunca tocó iTunes, y el estilo pragmático de administrar la librería de música de Amarok y/o GTKPod hicieron que nunca extrañara a iTunes.
Siempre me ha gustado experimentar con diferentes sistemas operativos, lo cual me llevó a usar cuanta distribución de GNU/Linux me encontrara en mi camino, desde Red Hat y Mandrake hasta Linux From Scratch. Inclusive algunos BSDs como FreeBSD y NetBSD. Cuando Apple hiciera la transición hacia intel y salieron los primeros hackintosh, sabía que tenía que probarlo. En la maestría sobraban personas que gustan de los productos de Apple, lo cual hizo mi transición hacia OSX86 más sencilla.
Después ocurrió algo que lo cambiaría todo. Si bien el iPod fue toda una revelación, el iPhone cambió las reglas del juego en muchos niveles. Fue la primera vez que sentí lo que otros fanboys sentían con cuanto producto Apple salía de la fábrica de sueños de Cupertino. No fui de los primeros en comprar uno, y de hecho me retrase tanto en comprar el mio que para ese entonces el firmware ya estaba en su versión 1.2 por lo que tuve que aguantarme una pequeña eternidad para poder usarlo como teléfono, y no iPod glorificado.
Todavía recuerdo las palabras que le dije a un amigo, sentados en un restaurante de Ensenada: “Esto lo cambia todo. Es tener Internet en la palma de tu mano” y eso que todavía no se podían instalar aplicaciones de terceros de manera oficial. En ese tiempo “la API era la Web” la cosa más ridícula que había escuchado decir a Steve Jobs. Aquí le faltó visión, o mi propia falta de visión no me permitió ver que ese era el plan desde el inicio. Sea como sea, el iPhone fue el dispositivo que me hizo voltear a ver a Apple de nuevo.
No fue fácil, de hecho su ecosistema cerrado es un gran punto negativo. Pero gracias a la comunidad del jailbreak, es un poco más manejable. Al ver los equipos actuales con Android, superiores en todos los aspectos técnicos, batallar con las animaciones y el despliegue de gráficos confirma la eterna apuesta de Apple de controlar tanto el hardware como el software.
Mi relación con los productos de Apple nunca fue de ciego fanatismo, o deseo incontrolable. Cuando todos morían por Aqua yo deseaba la simplicidad de Gnome 2. Cuando las iMacs y iBooks estaban de moda, yo pasaba mi tiempo libre construyendo mis propias computadoras e instalándones cuanto sistema operativo se cruzara en mi camino. Pero todo este tiempo he admirado el trabajo de una persona que tuvo la visión de llevar una computadora personal a todos los hogares… siempre y cuando tengan los USD $2500 para comprar una MacBook Pro.
El ingenio y las pelotas para llevar tus ideas a cabo siempre va a ser motivo de gran admiración en mi libro. Y por esta razón no puedo más que lamentar la pérdida, y admirar los logros a lo largo de la vida de Steve Jobs.
Esta es la situación: Domingo por la tarde, nada que ver en la TV. Me entero que That Metal Show tiene un episodio con Tony Iommi, pero el stream no se puede ver a menos que te encuentres en Estados Unidos. ¿Como saben que no estoy en Estados Unidos? con tu IP, que puede ser geolocalizada. El player de Flash que utilizan en el sitio obtiene tu IP, lo busca en una base de datos y determina que no, no estas en Estados Unidos, así que te quedas sin That Metal Show.
La solución a esto es, obviamente, tener una IP de Estados Unidos. ¿Pero como podemos obtener una? Una posible solución es un servidor proxy dentro de Estados Unidos. El servidor proxy pedirá el contenido por nosotros y nos lo reenviará. Sin embargo estos servicios generalmente tienen un costo. Antes estaba hotspotshield, pero ahora los players (por lo menos el que usan en VH1) saben como detectar cuando se está usando un proxy y no nos entrega nuestra dosis semanal de Heavy Metal.
¿Cómo lo detectan? les presento al encabezado X-Forwarded-For. Este encabezado normalmente lo agrega un servidor proxy, para decirle a los sitios Web la IP original que pidió el contenido. Seguramente el programador de player checa si viene el encabezado y de ser así, de ahí obtiene el IP, lo revisa y determina que estas fuera de los Estados Unidos. No Streaming For You!
¿Que hacemos? Si pudiéramos modificar nuestra petición para incluir dicho encabezado, y que el encabezado en vez de reportar nuestro IP real, reportara un IP dentro de Estados Unidos, con eso sería suficiente. El player al ver que viene el encabezado tomaría esa IP en vez de la original, y sería una IP de Estados Unidos.
Gracias a Firefox y un plugin llamado Modify Headers, lo anterior es bastante posible y funciona. La potencia de Firefox al descubierto: podrá ser más lento que Chrome, pero sus extensiones son más potentes. Instalamos la extensión, la abrimos y agregamos un nuevo filtro:
Mientras tengamos la ventana de modify headers abierta, podremos ahora visitar el sitio de That Metal Show y verificar que nos entrega el stream sin problemas. Si queremos hacer esto permanente, simplemente vamos al tab de Options y seleccionamos Always On, aunque no lo recomiendo. Lo mejor es solo activarlo cuando queramos ver el stream.
Otra vez Firefox y sus extensiones al rescate. Eso me recuerda por qué siempre tengo Chrome y Firefox instalados, y aunque uso Chrome para navegación del día a día, Firefox no ha sido desplazado del todo y me preocupo por mantenerlo actualizado. En mi mente Internet Explorer, Chrome y Firefox son como los tres sistemas operativos principales:

Quise esperarme a utilizar Mac OS Lion por un día para poder experimentar o sufrir en carne propia el Natural Scrolling, una característica del sistema operativo que invierte la dirección del desplazamiento en las ventanas. Estas son mis ideas al respecto:
Me parece que el ese patrón de uso tiene sentido cuando haces scroll tocando la pantalla, como en iOS, por que el feedback visual y táctil se alinean perfectamente (tocar la “página” y empujarla hacia arriba o hacia abajo), pero cuando lo hacemos a distancia, aún cuando estemos usando el trackpad multi-touch de Apple, no es así.
Tenemos más de cuarenta años haciendo scroll utilizando las barras de desplazamiento de las ventanas en prácticamente todos los sistemas operativos con entorno gráfico, por lo que es natural que cuando se adoptaron otros métodos de interacción como la scroll wheel en el mouse común se haya seguido el mismo patron de interacción.
Apple se está peleando con ese patrón. Podría parecer (y esa fue mi opinión inicial) que el natural scrolling es una característica traida por moda y capricho de iOS al sistema operativo de escritorio, pero la cosa no es tan simple:
Lion incluye gestos multi-touch para desplazarse entre los escritorios virtuales (que en el sistema operativo se alinean horizontalmente) y para pasar de página o diapositiva en cualquier medio que lo permita (PDF, slideshows, etc.) en los que curiosamente lo natural, contrario al scrolling “tradicional” (en mi experiencia como usuario) es arrastrar en la dirección en los que queremos que se mueva el contenido de la pantalla, es decir, para ver el escritorio de la derecha, “empujamos” el escritorio actual hacia la izquierda (piensa en las interfaces de Minority Report).
¿Por qué el scroll vertical se siente ridículo y el pase horizontal de páginas se siente natural (o al revés con natural scrolling desactivado)? Por la sencilla razón de que para lo segundo no tenemos suficientes experiencias previas, es algo relativamente nuevo para nuestro cerebro.
¿Entonces? ¿Está Apple introduciendo por capricho la característica en Mac OS? ¿Está tratando de corregir el “error cognitivo” en sus usuarios, en tiempos en los que ya no es necesario arrastrar con el puntero las barras de desplazamiento, en pos de abrir el camino a nuevas formas de interacción?
Con respecto a las preguntas anteriores solamente podemos opinar. En mi caso, me puedo imaginar a un grupo de trabajo de user experience tomando la decisión de sacrificar temporalmente la experiencia en el scrolling a cambio de obtener congruencia en el comportamiento de las dos características que menciono en este artículo, sobre todo por el bien del camino futuro en el área de la interacción.
Sin embargo yo desactivé el natural scrolling y decidí chutarme el pase de páginas y de escritorios “al revés”. Terco que es uno.
¿Tú qué opinas?
Después de cambiar mi trusty old BlackBerry 8520, pasar por un periodo de luto y adaptación a un iPhone, puedo decir que aún no me encuentro tan satisfecho con la experiencia de uso del día a día de un iPhone comparado con una BlackBerry, inclusive una tan antigua como la 8520. No nos engañemos, el iPhone hace casi todo de manera muy superior a una BlackBerry, sólo por mencionar unos ejemplos:
En todas esas áreas, el iPhone le patea el trasero a cualquier BlackBerry. Pero hay una área en la que no, y da la casualidad que es crítica para lo que un teléfono (o un smartphone) fue creado: comunicarse. El sistema de notificaciones del iPhone es mas feo que un carro por abajo, y eso es crítico para una buena experiencia de usuario al estarse comunicando. Una BlackBerry podrá ser más fea, sentirse más lenta, un pain in the ass para navegar y prácticamente no tener juegos disponibles, además que su App World es tan malo como pegarle a Jesucristo en cuaresma, pero su sistema de notificaciones y la manera en la que todo se concentra en un solo lugar, es lo que hace que la experiencia al comunicarse simplemente funcione. Tengo mis esperanzas puestas en iOS 5 para que arregle el patético intento de notificaciones, y POR FAVOR, eliminen o por lo menos pongan la opción de no mostrar en la pantalla principal, centrado y con negritas cuando alguien te manda un SMS.
Véanlo de esta manera: un iPhone es una computadora de bolsillo que resulta tener un componente para hablar por teléfono. Una BlackBerry es un teléfono con soporte para aplicaciones y centrado en el email, lo que lo hace técnicamente un smartphone.
Pero hay algo que se puede hacer al respecto que sólo esperar a que Apple arregle todo, y en el proceso hacerle algunas modificaciones a nuestro iPhone para mejorar la experiencia del usuario. Este es mi top 5 de aplicaciones para instalar después de hacerle jailbreak al iPhone.
Ese es mi top 5, pero hay otras que vale la pena mencionarlas rápidamente: My3G te permite usar 3G en cualquier aplicación no solo en las que quiera Apple, MyWi te permite compartir tu conexión 3G ya sea por medio de un hotspot WiFi, por cable o por bluetooth, SnapTap te permite usar el botón de subir volumen como obturador para la cámara pero sólo funciona con la aplicación oficial y no con Camera+ y finalmente WeBe++ que te permite usar el iPhone como control de PlayStation 3.
Renuncia: el artículo en cuestión es de opinión personal, y nada tiene que ver con mi empleador. Me deslindo de toda responsabilidad que directa o indirectamente se quisiera imputar como resultado de lo aquí plasmado.
Con todo el revuelo en la Web sobre los ataques perpetrados por los distintos grupos como Anonymous, LulzSec y más recientemente TeamPoison, una pregunta se me viene a la mente: ¿Es razón suficiente el poder hacerlo, para llevarlo a cabo?
Estos antigrupos operan bajo la premisa que debido a la poca atención a la seguridad de los sitios de distintas organizaciones, ellos pueden entrar y robar información. Algunos lo esconden bajo una máscara de activismo (Anonymous), otros lo hacen solo por diversión (LulzSec) y otros por venganza (TeamPoison). El fin justifica los medios.
Aún cuando estos actos nos hayan afectado directamente – como puede ser el caso de algun usuario de la PlayStation Network del que pudieran haber obtenido sus datos de tarjeta de crédito – no tenemos que ir tan lejos para ver actos similares mucho más cercanos a nuestra vida diaria, con el potencial de afectarnos más profundamente. Uno de estos actos puede ser por ejemplo el uso de redes inalámbricas a las cuales no tenemos acceso, o el escuchar tráfico de red que no fue destinado a nosotros. Ambas posibilidades muy reales y relativamente fáciles de lograr, con repercusiones potencialmente graves. ¿Es que la poca atención a la seguridad, o el completo desconocimiento de cómo funciona nos hace vulnerables a todo tipo de ataques que atentan contra nuestra privacidad?
Algo muy típico por ejemplo, es el llamado sniffing. Por cuenta propia, el recibir paquetes en tránsito por la red es algo muy valioso para analizar problemas de red, detectar usuarios maliciosos dentro de la red, o intentos de intrusión desde fuera, o inclusive para depurar protocolos de red en desarrollo. Sin embargo, como toda herramienta puede usarse para fines cuestionables, como podría ser capturar información sensitiva en tránsito. ¿Y que información sensitiva se podría capturar? Básicamente cualquiera que se genere en un protocolo de texto plano:
No hay que ser un hacker de élite para capturar paquetes en tránsito de alguno de estos protocolos y, por ejemplo, leer conversaciones ajenas y privadas por MSN. Peor aún, están los que se creen hacker por descargar una aplicación que te permite capturar los paquetes, filtrarlos y presentarlos en un formato listo para ser consumido. Hay aplicaciones en el mercado que inclusive concentran toda esta información y la guardan o la envían a un repositorio central, efectivamente espiando a los usuarios de la red. Todo esto es accesible, literalmente, a unos cuantos click de distancia.
Claro que una vez que sabemos el peligro, a nosotros como usuarios nos parece inclusive estúpido no protegernos ante el peligro latente. ¿Pero y los que no saben? ¿Es nuestro deber como usuarios de la red conocer los detalles de la implementación de los protocolos de las aplicaciones que usamos? ¡Si yo solo quería chatear un rato con mis amigos!
Dejando a un lado operaciones militares y cuestiones de seguridad nacional, todos los seres humanos tenemos el derecho a la privacidad. Que un individuo atente contra este derecho, por ejemplo instalando un sniffer y espiando conversaciones ajenas me parece un acto despreciable. Que una entidad (llámese empresa, gobierno, organización o persona en posición de autoridad, entre otras) quiera combatir fuego contra fuego, apaciguar el impacto de un atentado contra su privacidad, a su vez atentando contra la privacidad de otros y justificando sus acciones bajo el lema de “tu me hiciste, yo te hago”, no solo es despreciable, es ventajoso, poco efectivo y potencialmente ilegal (no se sobre este punto, no soy abogado).
Es cierto que transmitir datos por un canal inseguro sin encriptación, abre la puerta a que otros escuchen. Sería como el equivalente de hablar con otra persona y esperar que la gente a nuestro alrededor no escuche lo que decimos. El problema es que en el mundo de las charlas por Internet se nos ofrece un falso sentido de privacidad, y la falta de ella no es tan clara como en el mundo real. Cuando estamos conversando con alguien en una ventana de MSN, por ejemplo, todo parece indicar que los mensajes son uno a uno y nadie más puede leerlos. La ilusión es como estar en un espacio físico privado donde nadie puede escuchar (o leer) lo que decimos. Pero la realidad es otra, la realidad es como comunicarnos enviando mensajes en un trozo de papel que pasa por varias manos antes de llegar a su destino, y esperar que nadie lea los mensajes mientras el papel es entregado a su destinatario. Solo hace falta que una de las personas que lleva el mensaje dirija su atención al papel mientras lo lleva a su destino para perder nuestra privacidad.
Afortunadamente hay cosas que podemos hacer para proteger nuestra privacidad, más allá de esperar a vivir en un mundo ideal en donde nadie use su conocimiento y herramientas de manera irresponsable. El proyecto Tor nos ofrece una excelente manera de protegernos y mantener nuestro anonimato, evitando que otros lean nuestras conversaciones, descubran nuestra localización o sepan nuestros hábitos de navegación por la Web aún cuando capturen nuestros paquetes en tránsito. Como usuarios es nuestro derecho poder hacer lo necesario para proteger nuestra privacidad, y los profesionales de las TI tienen en sus manos la responsabilidad de proteger este derecho de sus usuarios, y proveer un ambiente seguro y/o educar a sus usuarios en los límites de esta falsa privacidad.
Ahora yo les hago una pregunta: Si te encuentras en una situación en el mundo real, en donde al hablar con otra persona te das cuenta que hay otros escuchando tu conversación privada, ¿que haces?
Ok, nadie está regalando iPads; pero hoy caí en cuenta que cada vez que voy a la oficina me compro –y termino– una botella de agua que cuesta $12.50 y pensé en la banalidad que es comprar agua embotellada. En esos raros momentos de sensatez anti-consumista a veces me pongo a hacer números:
$12.50 x 2 x 5 = $125 pesos a la semana
$125 x 52 = $6,500 al año
Justo lo que cuesta la iPad 2. Claro que en la vida no podemos esperar que todo sea predecible. Están los días que no voy a la oficina, vacaciones y así. Por otro lado sólo estoy contando los días entre semana y no estoy contando los 50 centavos que el OXXO te retiene (a veces preguntan si los quieres donar). Ya contando todas las variables, creo que seguimos quedando cerca. Por lo tanto (aunque no es viable para todos):
Llevar tu propia agua = iPad gratis

Frecuentemente me encuentro con sitios que deciden atraer más visitantes, creando concursos en donde la gente vota por su participante favorito. No hay nada de malo con eso, sólo que son fácilmente abusadas si no se tiene cuidado al programarlos. Al final podemos tener un ganador que no fue la elección popular, sino el más hábil con los bits.
Supongamos que hay una encuesta para votar por la flor más bella del ejido, y tenemos a las siguientes candidatas:

De izquierda a derecha las numeramos como Flor 1, 2, 3 ,4, 5 y 6.
El programador del sitio se siente muy confiado, ya que guarda una cookie en el navegador para identificar de manera única a los usuarios y evitar que voten repetido. Empieza la votación y por alguna razón la flor #3 va en la última posición, pero esta flor tiene amigos que le saben a eso de las computadoras y les pide algo de ayuda. Lo que hacen los amigos de la flor #3 es lo siguiente (en PHP):
function xrun($email,$name){
//set POST variables
$url = ‘http://www.laflormasbelladelejido.com.mx/votar.php’;
$fields = array(
‘Nombre’=>$name,
‘Email’=>$email,
‘Voto7′=>’VOTO POR LA FLOR #3′
);$fields_string =”";
//url-ify the data for the POST
foreach($fields as $key=>$value) { $fields_string .= $key.’=’.$value.’&'; }
rtrim($fields_string,’&');//open connection
$ch = curl_init();//set the url, number of POST vars, POST data
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_POST,count($fields));
curl_setopt($ch,CURLOPT_POSTFIELDS,$fields_string);//execute post
$result = curl_exec($ch);//close connection
curl_close($ch);}
Lo que hace el script anterior es enviar un HTTP POST a la URL de votación, previa preparación de las variables que espera la forma. Esto es muy fácil saberlo utilizando Firebug por ejemplo, o la consola para desarrolladores de Chrome. Para enviar el POST, están utilizando curl que es la neta del planeta cuando se trata de transferir datos por medio de HTTP, en este caso los datos del voto.
Pero ejecutar el script manualmente para aumentar el número de votos por la flor #3 es muy tedioso, así que los emprendedores amigos de esta pobre flor decidieron llevarlo un paso más alla:
$nombres = file_get_contents(”nombres.txt”);
$correos = file_get_contents(”correos.txt”);
$nom = split(”\n”,$nombres);
$ema = split(”\n”,$correos);
$r = count($nom);for($x=0;$x<$r;$x++){
if($ema[$x] && $nom[$x]){
xrun( $ema[$x], $nom[$x]);
}}
Ahora basado en un archivo de nombres y correos, se van a enviar tantos votos como nombres existan en el archivo. Este pedazo de código se puede mejorar muchísimo, por ejemplo sólo enviar tantos votos como pares nombre – correo existan, en vez de basarse en el número de nombres. Otra posibilidad es enviar votos en un ciclo pero restringido en tiempo, es decir simular que ha pasado cierto tiempo entre voto y voto, para que no sea tan obvio que es un programa y no gente real la que está votando.
Y ya con eso la flor más bella del ejido es la #3, como podemos verla en la imagen tan contentota.
¿Y la cookie? Obviamente se la pasa por el arco del triunfo. El problema es que el programador supuso que los votos siempre vendrían del navegador, es decir confió de la entrada del usuario. ¿Y cual es la primera regla de la seguridad programación Web?
Lo repetiremos de nuevo solo para asegurarnos de que quedó claro:
Así es, desconfía de la entrada del usuario. Desconfía como desconfías del que te quiere vender un tiempo compartido, o del informe de gobierno.
¿Qué podemos hacer para evitarlo?
Lo más obvio es guardar la IP, pero eso deja por fuera a muchísimas personas que se conectan usando NAT. Me explico: en una casa puede que existan 3 personas que comparten una conexión a Internet. Estas tres personas quieren votar por la flor mas bella del ejido, pero la persona 1 ya se les adelantó y su IP fue guardado en el servidor del sitio por lo que al querer votar la persona 2 ya no puede, le aparece un mensaje que su voto ya fue registrado. La decisión de qué hacer dependerá de que tan flexible y seguro necesitamos que sea la encuesta.
Si se esta votando por la flor mas bella del ejido, probablemente sea suficiente con guardar la IP por 30 minutos o más y validar contra eso. Si se está votando por el presidente de un país, probablemente sea necesario un poco más de seguridad.


I'm trying to deserialize the following XML document:
<?xml version="1.0" encoding="utf-8" ?>
<TestPrice>
<Price>
<A>A</A>
<B>B</B>
<C>C</C>
<Intervals>
<Interval>
<A>A</A>
<B>B</B>
<C>C</C>
</Interval>
<Interval>
<A>A</A>
<B>B</B>
<C>C</C>
</Interval>
</Intervals>
</Price>
</TestPrice>
And I have three classes defined to deserialize this into an object graph:
public class TestPrice
{
private List<Price> _prices = new List<Price>();
public List<Price> Price
{
get { return _prices; }
set { _prices = value; }
}
}
public class Price
{
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
private List<Interval> _intervals = new List<Interval>();
public List<Interval> Intervals
{
get { return _intervals; }
set { _intervals = value; }
}
}
public class Interval
{
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
}
I can deserialize each part ok. That is, I can do:
var serializer = new XmlSerializer(typeof(Price));
var priceEntity = ((Price)(serializer.Deserialize(XmlReader.Create(stringReader))));
And priceEntity is correctly initialized with the XML data contained in stringReader, including the List<Interval> Intervals. However if I try to deserialize a TestPrice instance, it always comes up with an empty List<Price> Price.
If I change the definition of TestPrice like this:
public class TestPrice
{
public Price Price { get; set; }
}
It works. but of course my XSD defines Price as a sequence. I have other entities deserializing just fine, but they don't include sequences in the root element. Is there a limitation that I'm unaware of? Should I include some sort of metadata in TestPrice?
We have an ERP application. The server side is implemented as a series of Web services exposed with Hessian and Spring. The Web services make use of a DAO layer for all database operations. The DAOs are implemented using Hibernate. The client side is Java Swing. It makes use of the Web services for all the data related operations.
The problem is that there's a requirement to block certain rows from being edited if there's another client editing the same row at the same time. Also whenever a client is done editing a row, all the other clients shall update the row with the updated value. The solution has to take into consideration that the client might be displaying the same data but with a different view (for instance, the same data is filtered in one client, and non filtered in another).
A socket connection between clients is out of the question, since the application needs to work through firewalls with no additional configuration. Continuously polling the server for updates doesn't scale well, since we are looking into hundreds of concurrent clients here.
Looking at my options, I considered JMS but after spending 2 days trying to configure ActiveMQ with Spring, I finally gave up (I don't have previous experience with JMS, nor does the team). Still, it seemed way too complicated for what we need here. At the end, I implemented something using websockets using the excellent Java-WebSocket library, and after hacking a new table listener, cell editor and table model on the client, it's working.
Still I'm concerned that the client is responsible for keeping track of editable/non-editable cells, added and deleted rows, etc. From my perspective, this solution is too fragile. In any given time a message could be lost and all clients lose synchronization between their state.
My question is, how would you implement this requirement given the current architecture? If changing the backend is an option, what would you change to make this requirement easier to implement? It seems to me that the stateless nature of the Web services architecture, plus the fact we are using Hibernate and there's no way that I know of to be notified when a request is modifying a possibly detached object, is making things more complicated than they should be.
The -jar directive overrides the classpath, using whatever is defined in the jar file itself. The best way to do what you need is to use a tool such as ant, a script, or copy it to somewhere where the OS can find it (as Nejc Saje suggested).
I recommend you get the book Filthy Rich Clients. There's a chapter where they explain Swing's threading model to great detail.
Basically in Swing, any code that modifies the GUI should be executed in the Event Dispatcher Thread. The SwingUtilities class that you are using there provides you with an easy way to post events to the event queue that is then dispatched by the EDT. That's what the invokeLater method does, it takes a new Runnable() as argument which is ultimately executed on the EDT.
From the book:
The invokeLater() implementation takes care of creating and queuing a special event that contains the Runnable. This event is processed on the EDT in the order it was received, just like any other event. When its time comes, it is dispatched by running the Runnable’s run() method.
I took the code in http://download.oracle.com/javase/tutorial/uiswing/examples/layout/BoxLayoutDemoProject/src/layout/BoxLayoutDemo.java and adapted it with what you are trying to do, only using buttons instead of custom JPanels:
public class BoxLayoutDemo {
public static void addComponentsToPane(Container pane) {
JPanel rowPanel = new JPanel();
pane.add(rowPanel);
rowPanel.setLayout(new BoxLayout(rowPanel, BoxLayout.Y_AXIS));
rowPanel.add(addAButton("Button 1"));
rowPanel.add(addAButton("Button 2"));
rowPanel.add(addAButton("Button 3"));
rowPanel.add(addAButton("Button 4"));
rowPanel.add(addAButton("5"));
rowPanel.setPreferredSize(new Dimension(600, 400));
rowPanel.setMaximumSize(rowPanel.getPreferredSize());
rowPanel.setMinimumSize(rowPanel.getPreferredSize());
}
private static JButton addAButton(String text) {
JButton button = new JButton(text);
button.setAlignmentX(Component.CENTER_ALIGNMENT);
return button;
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("BoxLayoutDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Set up the content pane.
addComponentsToPane(frame.getContentPane());
//Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
The end result is this:

As you can see, the button row is perfectly aligned. If you resize the JFrame, they stay aligned. Is that what you are looking for?
public void doGet(HttpServletRequest request, HttpServletResponse response){
String uriRequest = request.getRequestURI();
//parse to obtain only the last part
String uriRequest = uriRequest.substring(uriRequest.lastIndexOf("/")+1);
}
Same thing for doPost().
ClientBundle introduced in GWT 2.0 allows you to bundle images and other resources in one file, this file is cached forever resulting in fewer server request.
That being said, GWT introduces a concept they call perfect caching. It works by splitting your application in several files named something like .cache.html and the md5 part always change when your application code or resources change. Then there's the bootstrap script, which contains the logic to look for the correct <md5>.cache.html file and load it. The bootstrap should never be cached.
In your app server, you need to configure it something like this (Apache in this case)
<Files *.nocache.*>
ExpiresDefault "access"
</Files>
<Files *.cache.*>
ExpiresDefault "now plus 1 year"
</Files>
In this case it's set to cache for one year. As far as I know there's no setting to cache forever, that only means a very high expiration time.
In the case of Tomcat, as far as I know there's no cache control so it has to be done manually by setting the proper HTTP headers. This can be automated by the use of filters.
/*Please don't use this in production!*/
public class CacheFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
//cache everything for one year
response.addHeader("Cache-Control", "max-age=31556926");
chain.doFilter(request, response);
}
public void init(FilterConfig filterConfig) {
this.fc = filterConfig;
}
public void destroy() {
this.fc = null;
}
}
Then map the filter in tomcat or derivatives (such as glassfish), in web.xml:
<filter>
<filter-name>cachingFilter</filter-name>
<filter-class>CacheFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>cachingFilter</filter-name>
<url-pattern>*.cache.*</url-pattern>
</filter-mapping>
The question is tagged as GWT so based on that... to do it entirely on the client, you can use the com.google.gwt.user.client.Window class.
Window.open(linkURL, "_self", "");
On the first println() you are overriding the toString() method from the anonymous myAbstractClass instance, therefore you get the string returned by your overriden toString() method, that's the default behavior of the println() function.
On the second println(), you are not overriding the toString() method, so println() uses the default one (inherited from Object).
On a side note, try formatting your code correctly, is much easier to read and understand.
abstract class myAbstractClass{}
public class Main {
public static void main(String[] args) {
System.out.println(new myAbstractClass(){
public String toString(){
return "myAbstractClass toString";
}
});
System.out.println(new myAbstractClass(){
public String myFunction(){
return "myAbstractClass myFunction";
}
});
}
}
3- The solr I have downloaded came with Jetty. Is Jetty a Servlet container?
Yes, Jetty is a Web server and Servlet container. A servlet container is a web server that interacts with servlets, and you need one of those to host your servlets, execute them, etc.
An application server typically hosts many other facilities, such as security, authentication, Java Mail, EJB container, and many others.
First, in your JSP import the class you are trying to use:
<%@ page import="com.mypackage.MyClass" %>
Then you can use that class as you would normally do:
<%
MyClass c = new MyClass();
c.getSomeProperty();
%>
To fill the control, you iterate your array and set the value argument of the option tag:
<select>
<%while (myList.next()){%>
<option><%out.print(c.getName());%></option>
<%}%>
</select>
As you can see, there's mixed Java code and HTML. First it outputs the select tag, then on Java code there's a while loop iterating a list of objects. This could be your ResultSet, an array or some other collection. For each iteration it creates an option tag with some value, this would be the value you want the user to see.
This is the basic approach, using only JSP. But there are many tag libraries, for example JSTL, that provide things like iteration so you can write things like:
<select name="mySelect">
<foreach collection="<%= myCollection %>" var="mybean">
<%= mybean.getOptionTag() %>
</foreach>
</select>
In the first place, your Book instance above contains errors. Here's what I suppose it should look like:
public class Book{
public String name = "myName";
public List authors = new ArrayList();
public String subject = "mySubject";
public Book(){
}
}
Now:
{"Book":{"name":"myName", "authors":"", "subject":["mySubject"]}}
Are you sure this is what xstream is returning for the Book object listed above? This doesn't seems right, since the subject property is a String and not a String[] or other type of collection. The JSON encoding for the first example you give (book without authors) should be:
{"Book":{"name":"myName", "authors":"", "subject":"mySubject"}}
Unless your Book looked something like this:
public class Book{
public String name = "myName";
public List authors = new List();
public String[] subject = {"mySubject"};
public Book(){
}
}
Bottom line: make sure you are not declaring your subject as a collection.
As a bonus tip, try to post working code on your questions. It's easier that way to get meaningful answers.
So my guess is that your Book class is declaring subject to be some kind of collection
Yes that could very well be the problem. Legacy ports (parallel and serial port) support in Java is provided by the Java Communications API, which relies on native code to support low level access to those ports. That API it's an extension to the JDK and not part of it.
Of course it could also be that on the new machine the user running your program doesn't have permissions to access the port, which is a different problem.
EDIT: For cross platform support for legacy ports, hell even if you only intend to use your program in one platform I recommend RXTX, an open source replacement for JavaComm.
If you want to store your images in the database instead of just a path to reference the image, the column that will hold your image need to be of BLOB type.
CREATE TABLE upload (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(30) NOT NULL,
content LONGBLOB NOT NULL,
PRIMARY KEY(id)
);
From your BlackBerry program (warning, untested):
//First param is a Bitmap, second is quality
JPEGEncodedImage encodedImage = JPEGEncodedImage.encode(image, 100);
byte imageBytes[]=encodedImage.getData();
//The HTTP connection stuff
HttpConnection conn = (HttpConnection) Connector.open(SERVER_URL, Connector.READ_WRITE);
conn.setRequestProperty(HttpProtocolConstants.HEADER_CONTENT_TYPE, HttpProtocolConstants.CONTENT_TYPE_MULTIPART_FORM_DATA);
conn.setRequestMethod(HttpConnection.POST);
conn.setRequestProperty(HttpProtocolConstants.HEADER_CONTENT_LENGTH, String.valueOf(imageBytes.length));
//Change this part to what your server side code expects
String contDisp="Content-Disposition:form-data; uploadedimage=YOUR_IMAGE_NAME;filename=\"Image.jpg\"";
String contEnc = "Content-Transfer-Encoding: binary";
String type="Content-Type:image/jpeg";
OutputStream out= conn.openOutputStream();
out.write(imageBytes);
out.flush();
out.close();
So basically you use HttpConnection to setup the headers for a POST request, with multipart form data as content type. There are other headers that may be needed, to know exactly what you need (not BlackBerry specific) check the HTTP/1.1 protocol specification.
How to actually store the image into the database will depend on your server side implementation. This can be anything from PHP, ASP, JSP or any server side technology that allows you to talk to your MySQL instance.
Create a dummy object:
class MyDummyRequest implements HTTPServletRequest{
//implement your own methods, for example:
public Map getParameterMap(){
Map myMap = new HashMap();
//put the params you need inside myMap
return myMap;
}
}
If you want to avoid creating dummy objects for test purposes you may look into one of the available mocking libraries for Java, such as Mockito.
With the accept attribute, you list the mime types to accept.
<form action="form_action.asp" accept="image/gif, image/jpeg">
First name: <input type="text" name="fname" /><br />
Last name: <input type="text" name="lname" /><br />
Your image: <input type="file" name="pic" id="pic" /><br />
<input type="submit" value="Submit" />
</form>
Taken from here.
As other said, as long as you have Java installed and avoid using native code, you should be good to go. One thing to note is that you can usually run a JAR file just by double clicking it, and it opens like a native executable (on Windows this is how it works by default, on other OSes you can configure this behavior).
Such JAR files are called executable JAR files. If what you want to create is an executable JAR file, then you need to add a manifest file that tells the Java virtual machine (JVM) the name of the main class. Executable JAR files also can be run on the command line by doing:
java -jar myprogram.jar
If your JAR is not an executable JAR, then to run your program you have to add the JAR to your classpath and then execute the main class. To add a JAR to the classpath:
java -classpath path/to/your/program.jar com.mypackage.Main
Option 2 doesn't make much sense, or at least it's not as clear to me as option 1. With option 1 you don't need to handle user interaction inside your space object. You could have in your main class or a separate class dedicated to handle user interaction:
public void move(Player p, int spaces){
Space landingSpace = board.getLandingSpace(p,spaces);
landingSpace.land(p); //apply your logic here
}
As you can see, the Space class is responsible for checking the Player p that intends to land on that space. It applies any custom logic, checks if it has enough money, if it's something that the player owns, etc. Each subclass of Space will have its own set of rules, as you described in option 1.
I think I need to use the String[] overloaded method for exec
Exactly! Change your command to be a String array. The array must contain the command and its arguments:
String[] command = {"cmd","/c", "concat2.vbs", arg1, arg2};
Process p = Runtime.getRuntime().exec(command);
concat2.vbs should be on Window's execution path (same directory, or configured in the PATH environment variable)
Check out the documentation for the Runtime class.
You need to:
String out = result.getConsoleOutput().replaceAll("\n", "<br/>");
transOut.getElement().setInnerHTML(out);
Note the setInnerHTML() instead of setInnerText()
See my answer here: http://stackoverflow.com/questions/2413722/gwt-processbuilder/2413770#2413770 Other answers in the same question provide useful advice as well.
It's not exactly about HSQLDB and GWT, but the cause of the error is the same: Google App Engine doesn't support all Java EE classes. Check the Will it play in GAE? page to know if your particular feature/library is available for GAE.
Yes, it's possible with ant. A jar file is basically a zip with a special manifest file. So to unjar, we need to unzip the jars. Ant includes an unzip task.
To unzip/unjar all the jar files in your project:
<target name="unjar_dependencies" depends="clean">
<unzip dest="${build.dir}">
<fileset dir="${lib.dir}">
<include name="**/*.jar" />
</fileset>
</unzip>
</target>
Obviously you need to declare ${build.dir} and ${lib.dir} first. The line <include name="**/*.jar" /> tells ant to include all files that end up with the jar extension, you can tweak that include to suit your needs.
To pack everything into a jar, you use the jar task:
<target name="make_jar" depends="compile, unjar_dependencies">
<jar basedir="${build.dir}"
destfile="${dist.dir}/${project_name}.jar">
<manifest>
<attribute name="Main-Class" value="${mainclass}" />
</manifest>
<fileset dir="${build.dir}">
<include name="**/*.class" />
</fileset>
<fileset dir="${src.dir}">
<include name="applicationContext.xml" />
<include name="log4j.properties" />
</fileset>
</jar>
</target>
In this example, we include different filesets. In one fileset we are including all compiled classes. In another fileset we include two config files that this particular project depends upon.
Initial request is the request that the browser does in order to display the page with the ${customer.name} tag. Postback happens when the browser posts some or all page values and then the same page that was posted in the first place is returned to the client. This might happen for example as a result of a validation error.
Knowing if the current view being rendered is a result of a postback is useful. For example you might want to display a message as a result of a postback, but not every time the page is refreshed.
There may be some performance overhead of calling the getAge() method many many times, but I suggest you consider The Sad Tragedy of Micro-Optimization Theater.
I would ask how they are approaching the problem, and in particular if they took current research results from vehicle wireless sensor networks, since that's an area I was researching into when in grad school.
Also some published papers on the actual implementation and experimentation results would be great.
Did you try subclassing DeckPanel and overriding onComplete()?
public MyDeckPanel extends DeckPanel{
@Override
protected void onComplete(){
super.onComplete();
//What you want to do once the animation completes
}
}
Call setVisible(false) on your main JFrame before capturing the screen. When the screen capturing process is finished, call setVisible(true) to get your GUI showing up again.
To capture the screen, you can use the Robot class. It contains a createScreenCapture method that receives rectangle coordinates which will be captured in a BufferedImage.
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.
I'm trying to get a simple layout working under GWT 2.0 using UiBinder. The layout I'm trying to get is one that mimic Java's BorderLayout in where you can specify different panels in the north, south, east, west and center directions; for that I'm using DockLayoutPanel. I would like to get a header and footer, both with fixed width. The remaining viewport space would be occupied by the widget assigned to the DockLayoutPanel center slot.
The current .ui.xml file I've got is:
<g:DockLayoutPanel unit='EM'>
<g:north size='2'>
<g:HTML>HEADER</g:HTML>
</g:north>
<g:south size='2'>
<g:HTML>FOOTER</g:HTML>
</g:south>
<g:center>
<g:HTML>
<div id='loginform'>Hello!</div>
</g:HTML>
</g:center>
</g:DockLayoutPanel>
The browser only renders HEADER at the top left corner. How can I achieve the layout I'm looking for? It seems that there's more CSS you've got to know before you can use GWT layout panels, but that kind of defeats the purpose of creating the UI with it.
I'm struggling to get association right on Grails. Let's say I have two domain classes:
class Engine {
String name
int numberOfCylinders = 4
static constraints = {
name(blank:false, nullable:false)
numberOfCylinders(range:4..8)
}
}
class Car {
int year
String brand
Engine engine = new Engine(name:"Default Engine")
static constraints = {
engine(nullable:false)
brand(blank:false, nullable:false)
year(nullable:false)
}
}
The idea is that users can create cars without creating an engine first, and those cars get a default engine. In the CarController I have:
def save = {
def car = new Car(params)
if(!car.hasErrors() && car.save()){
flash.message = "Car saved"
redirect(action:index)
}else{
render(view:'create', model:[car:car])
}
}
When trying to save, I get a null value exception on the Car.engine field, so obviously the default engine is not created and saved. I tried to manually create the engine:
def save = {
def car = new Car(params)
car.engine = new Engine(name: "Default Engine")
if(!car.hasErrors() && car.save()){
flash.message = "Car saved"
redirect(action:index)
}else{
render(view:'create', model:[car:car])
}
}
Didn't work either. Is Grails not able to save associated classes? How could I implement such feature?





