la W3C es obsoleta

Despues del papelón de Ian Hickson diciendo que hay que esperar hasta 2022 para tener una especificacion de html5 completa me encuentro con esto revisando element input[type=number]:

autocomplete = “on” or “off”
Specifies whether the element represents an input control for which a UA is meant to store the value entered by the user (so that the UA can prefill the form later).

autofocus = “autofocus” or “” (empty string) or empty
Specifies that the element represents a control to which a UA is meant to give focus as soon as the document is loaded.

¿Qué nos hace pensar que la w3c va a poder hacerlo bien en esta oportunidad? ni siquiera pueden ponerse de acuerdo en como representar un valor booleano en dos atributos que estan adyacentes en la especificacion. Despues es facil hecharle la culpa a los fabricantes de navegadores… Como bien dice el dicho: Un camello es un caballo diseñado por un comité

SourceMonitor

SourceMonitor es una aplicación freeware que examina el codigo fuente de nuestros proyectos y calcula distintas metricas acerca la complejidad que encuentra. Una caracteristica muy interesante es la posibilidad de tomar ’snapshots’ de los valores arrojados por las metricas para poder compararlos a lo largo de tiempo . Soporta Java, C, C++ y unos cuantos lenguajes más

Muy util para saber en que momento hay que empezar a refactorear.

Contadores Atómicos

Cuanto tiempo sin escribir… en fin. Siempre me llamo la atención que en Java muchas de las operaciones sobre primitivos no son atómicas. El statement c++; por ejemplo no es atómico y puede traernos muchos dolores de cabeza en entornos de multithreading. Vale recordar, consideramos una instrucción como “atómica” si no puede ser interrumpida para darle paso a otro thread. En el siguiente ejemplo se presentan el caso de dos threads que consumen concurrentemente un contador. Si ejecutan el código podrán ver que no se obtiene el resultado esperado.

public class Main {

public static void main(String[] args) {
Contador c = new Contador();
new Corredor(c).start();
new Corredor(c).start();
}
}

class Corredor extends Thread {

private Contador contador;

@Override
public void run() {

for (int i = 0; i < 20; i++) {
try {
System.out.println(contador.incrementAndGet());
Thread.sleep(500);
} catch(Exception e) {
}
}

}

public Corredor(Contador contador) {
this.contador = contador;
}
}

class Contador {

private int value = 0;

public int incrementAndGet() {
return ++value;
}
}

En la pantalla terminamos con algo parecido a

1 2 2 3 3 4 4 5 6 6 7 7 8 8 9 9 10 10 11 ……

De alguna forma estamos forzando un poco esa situacion poniendo a dormir el Thread luego de llamar al metodo incrementAndGet() pero es una situacion que perfectamente se puede dar cuando hay muchos threads en ejecución. Podriamos corregir esta situación synchronizando el metodo incrementAndGet() pero produciría una sobrecarga que quizá no estemos dispuestos a pagar.

java.util.concurrent.atomic.AtomicInteger es la clase que vamos a usar para solucionar este problema. AtomicInteger se comporta como un Integer comun y corriente pero es mutable a traves de metodos atómicos. Lo mejor es que los metodos no son sincronizados de forma tradicional sino por otras oscuras tecnicas que en su momento trataré. Esta clase posee metodos tales como addAndGet(int delta) que incrementa en un delta de forma atomica, decrementAndGet(), getAndAdd(), getAndIncrement() y muchos otros que hacen más o menos lo que indican los nombres pero siempre siempre de forma atómica.

Más información en http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/atomic/AtomicInteger.html

Manejando XML con XStream

Existen muchas librerias que permiten manejar archivos XML dentro de Java. Tenemos desde Apache Commons Digester hasta StAX incorporado en la JRE6 pasando por incontables alternativas con menos fama. Si a estas alturas hay algun desprevenido que no sabe que es XML le recomiendo este articulo. Si bien hay muchas alternativas algunas son algo complicadas y otras presentan una sobreingenieria extrema para algo que parece tan trivial como el mapeo de un documento xml a un grafo de objetos.

XStream es una de esas librerias que hacen fáciles las cosas simples. Con XStream no hay que armar grandes descriptores para hacer funcionar el mapeo sino que todo apela a la vieja y querida API Reflection, además XStream mantiene al minimo las dependencias con otros proyectos (exactamente lo opuesto que ocurre con Digester que requiere casi todo el apache commons para funcionar). La forma de usar XStream es muy sencilla. Veremos como hacer para pasar de Objetos a XML y de XML a Objetos. Supongamos que tenemos una clase Persona y una Telefono.

public class Persona {
private String nombre;
private long id;
private String fechaNacimiento;
private float sueldo;
private Telefono[] telefonos = new Telefono[10];

//setters y getters.....

}

public class Telefono {
private String codigoPais;
private String codigoArea;
private String numero;
private String interno;
//getters y setters....

}

Más POJO imposible, ni siquiera hay que hacer a la clase Serializable o algo así. Para hacer mas claros estos ejemplos y no bombardear la pantalla con código inutil ;) voy a apoyarme en una clase Generator a partir de la cual obtengo un objeto Persona o un String con la definicion XML. La definicion XML estará en un archivo, o en internet o en cualquier lado, como sea, la operatoria es la misma.

Ejemplo XML -> Objeto

import com.thoughtworks.xstream.XStream;

public class TestRead {
public static void main(String[] args) {
XStream xs = new XStream();
xs.alias("persona",Persona.class);
xs.alias("telefono",Telefono.class);
Persona p = (Persona)xs.fromXML(Generator.getXML());
//listo! en 3 lineas hace la conversion de XML a un Objeto de clase Persona.
System.out.println(p.getId());
System.out.println(p.getNombre());
System.out.println(p.getSueldo());
for(Telefono t:p.getTelefonos())
System.out.println(t.getNumero());
}
}

Ejemplo Objeto -> XML

public class TestWrite {
public static void main(String[] args) {

Persona p = Generator.getPersona();
XStream xs = new XStream();
xs.alias("persona", Persona.class);
xs.alias("telefono",Telefono.class);
String xml = xs.toXML(p);

// toXML() devuelve un string con la definicion xml para el objeto p. Todo en 3 lineas!
System.out.println(xml);
}
}

Rentas, Patentes y RegExp

Introducción

Esto es una historia real que me ocurrio hace unos instantes. No sabia si postearlo acá pero como es mi blog hago lo que quiero. Hace un rato queria ver cuanto debía del impuesto de patente de mi auto. Por motivos que no es prudente comentar acá hacia tiempo que no me llegaban las boletas y no reclamaba asi que quise ver si internet me daba una solución. Vaya si me dio una solución… Por prudencia no voy a poner la dirección donde pueden encontrar las páginas que destriparé en los párrafos siguientes, confio en que sabrán googlear ;)

Prolegómenos

Sin problemas encontré que en la página web de rentas de la ciudad autónoma de buenos aires es posible consultar el estado de la deuda con tan solo poner el número de patente. Sin embargo es necesario ingresar un “digito verificador” por motivos que, estimo, tienen que ver con salvaguardar la información del deudor. Dicho digito se encuentra impreso en la boleta pero como comente mas arriba, hace tiempo que no la tengo.

La página presentaba dos cuadros de texto donde introducir la patente y el digito verificador (se llama digito verificador a pesar de estar formado por Dos digitos). Puse la patente de mi auto y tire algunos digitos al azar. Naturalmente, no acerte con el digito verificador pero me llamó poderosamente la atención de que la validación se hacia instantaneamente y un hermoso alert() se encargaba de avisarnos de nuestro error. Algo olía a Javascript.

En pleno siglo XXI cuesta creer que alguien use javascript para realizar este tipo de validación, sin embargo las tecnicas de ofuscación de codigo a veces confunden a ciertas personas. Digo las confunde porque a veces se olvidan de ofuscar su código… asi que, firebug mediante, pude hacerme con el código de validación que comparto en este link.

Años atras, cuando el tiempo libre era algo que me sobraba, curioseando por ahí habia podido comprobar en incontables veces lo patético que son los emprendimientos informaticos del estado, sobretodo en lo referente a seguridad, desde el servicio meteorológico de las fuerzas aereas hasta el ministerio de educacion. Más cerca en el tiempo habia sufrido con las aplicaciones de rentas y los tramites via web de la afip. Sabía de las limitaciones del estado. Pero no sabia que se habian vuelto a superar…

Tratamiento

Todo empieza con una curiosa función titulada ValidarDigitoPatente() la cual, increiblemente, valida nuestra patente y el digito verificador. Efectivamente la lógica que hace la validación esta del lado del cliente y el codigo no esta ofuscado… bueno… no a la manera tradicional porque se las ingeniaron para que cueste entenderlo :)

Lo primero que hace esta función es validar que la patente ingresada sea valida (para los hermanos latinoamericanos en argentina las patentes, ó matriculas, de los autos tienen 3 letras seguidas de 3 digitos. ABC 123, DFG 167 y UIO 654 son ejemplos de patentes validas. Antiguamente se usaba una codificación formada por una letra y 7 numeros). El codigo que se encarga de hacer esto, contengan las risas, es el siguiente:

if (EsLetra(n.charAt(0))) {
if (n.length == 8 &&
isDigit(n.charAt(1)) &&
isDigit(n.charAt(2)) &&
isDigit(n.charAt(3)) &&
isDigit(n.charAt(4)) &&
isDigit(n.charAt(5)) &&
isDigit(n.charAt(6)) && isDigit(n.charAt(7))) {

Javascript posee una de las implementaciones mas lindas de expresiones regulares que existen. Los estatales argentinos, sin embargo, no saben usarlas. Esa maraña de código para chequear la validez de una patente se puede reducir a:

if(n.match('[a-zA-z]{3}[0-9]{3}')) {

Esta bien, no seria taaaaan grave que no dominen el arte oscuro de las expresiones regulares. Sucede que hay patentes de otro tipo de vehiculos, e incluso las patentes que se usaban antiguamente, que tienen otro formato. ¿Como hacen para evaluar los otros formatos? Facil, seguimos enmarañando el código.

if (isDigit(n.charAt(0))) {
if (n.length > 1 && isDigit(n.charAt(1))) {
if (n.length > 2 && isDigit(n.charAt(2))) {
if (n.length == 6 &&
EsLetra(n.charAt(3)) &&
EsLetra(n.charAt(4)) && EsLetra(n.charAt(5))) {

Más alla de esto lo que nos importa es poder averiguar el bendigo digito, que son dos, verificador. Para eso se valen de una enigmatica funcion Codigo(). Esta función recibe una letra y devuelve un número de dos cifras aparentemente asignados al azar, no soy un criptoanalista ni mire muy detenidamente la serie, pero esos numeros me parecen familiares. Bueno, con un array asociativo devolvemos como value dos digitos a partir de una letra que usamos como clave y listo. No necesariamente…

function Codigo(letra) {
if (letra == "a" || letra == "A") {
return "14";
} else if (letra == "b" || letra == "B") {
return "01";
} else if (letra == "c" || letra == "C") {
return "00";
//asi hasta el infinito y mas allá...

Detalles… detalles… ¿Pero como funciona la funcion validadora? Para seguir con la tradicion de los digitos del CUIT vamos a hacer un par de cuentitas con los valores que devuelve esta funcion y a otra cosa. En el caso de la patente de mi auto, con tres letras y tres digitos, el codigo verificador se evalua de esta forma:

//la patente esta en n
var a = new String(Codigo(n.charAt(0)) + Codigo(n.charAt(1)) + Codigo(n.charAt(2)) + n.charAt(3) + n.charAt(4) + n.charAt(5));
//quedaria a como un string de 9 digitos ya que cada letra se cambia por dos numeros y los ultimos 3 numeros quedan igual.
document.frmLogin.chapa_patente_copia.value = n;
//se copia la patente original (WTF?)
var digitos_impares = new String(a.charAt(0) * 1 + a.charAt(2) * 1 + a.charAt(4) * 1 + a.charAt(6) * 1 + a.charAt(8) * 1);
//aca empieza lo bueno: se castean los digitos en las posiciones pares de a y se suman entre ellos.
var digitos_pares = new String(a.charAt(1) * 1 + a.charAt(3) * 1 + a.charAt(5) * 1 + a.charAt(7) * 1);
//se hace lo mismo pero para las posiciones impares del string a
if (digitos_impares.length == 2) {
digitos_impares = new String(digitos_impares.charAt(0) * 1 + digitos_impares.charAt(1) * 1);
}
if (digitos_pares.length == 2) {
digitos_pares = new String(digitos_pares.charAt(0) * 1 + digitos_pares.charAt(1) * 1);
}
if (digitos_impares.length == 2) {
//aca es donde el agua nos empieza a tapar...
digitos_impares = new String(digitos_impares.charAt(0) * 1 + digitos_impares.charAt(1) * 1);
}
if (digitos_pares.length == 2) {
digitos_pares = new String(digitos_pares.charAt(0) * 1 + digitos_pares.charAt(1) * 1);
}
//aca es donde nos tapo el agua.
var digito_verificador = new String(digitos_impares + digitos_pares);

Con el agua al cuello puede darse la ¿casualidad? de que los benditos digitos_pares una vez sumados den una cifra de dos digitos, como 39, por lo que volvemos a sumarlos para obtener uno solo… aunque 3+9 da 11… deberiamos repetir el procedimiento y llegariamos como resultado a 2. No comprobe como se comportan los digitos que devuelve la funcion Codigo() para ver si podria darse el caso de llegar a situaciones que requieran volver a sumar los digitos del resultado hasta alcanzar un valor final de un solo digito. Los personajes de rentas aparentemente ya agotaron estas arduas cuestiones metafisicas y parece que con dos sumas siempre se llega a un resultado de un digito ¿maravilloso verdad? Para hacer esto no usaremos recursion, ni closures, ni un miserable ciclo while. Hacemos copy&paste del codigo y le prendemos una vela a los santos agradecidos por haber inventado el hardcoding.

Conclusión

Uno se encuentra con cosas raras en las operaciones informáticas de la administración pública. No puedo evitar reflexionar sobre estas cuestiones cada vez que tengo que hacer una declaracion jurada via internet en la pagina de la afip, o llenar un formulario de arba. Creo que la información de las personas es uno de los bienes más sensibles y deben ser manejados de la mejor forma por nuestras autoridades.

Lo importante resulto ser que el “digito verificador” de mi patente es el 43, uno más que el sentido de la vida, el universo y todo lo demás. Finalmente si alguien quiere saber cuanto debo de patentes esta es la respuesta que obtuve en el sitio de rentas:

ERROR DE COMUNICACION: INTENTE MAS TARDE.

Para todos los que llegan buscando como sacar su numerito de la suerte les dejo algo para que lo usen con fines beneficos solamente. Escriban la patente en el cuadro presionen en el boton, crucen los dedos y quiza se hagan con el numerito

Entradas y comentarios feeds. 14 queries. 0.260 seconds.

60921 pages viewed, 16 today
29270 visits, 11 today
FireStats icon Powered by FireStats