viernes, 24 de octubre de 2014

Yosemite, Apache y MySQL

Al actualizar el sistema de OS X Mavericks a  Yosemite, me he encontrado con el pequeño inconveniente de que Apache y MySQL han dejado de funcionar.

Apache

El problema del servidor Apache es que la instalación de Yosemite machaca el archivo httpd.conf, con lo cual se pierde toda la configuración anterior. Afortunadamente esa información está guardada en httpd.conf~previous. De esta forma he editado httpd.conf, cambiado los parámetros necesarios. En mi caso, el directorio raíz de la web local, los usuarios, activación del módulo de PHP, apertura de los puertos de escucha, ya que tengo 5 webs independientes. Todo eso está en el directorio "/etc/apache2". Se hacen los cambios y reiniciamos el servidor web: sudo apachectl restart.

MySQL

MySQL no responde. Una vez pulsado el botón del pánico porque creía que había perdido mis bases de datos, compruebo que el servicio MySQL no estaba iniciado. Se arranca y todo va bien... bueno... casi bien... ¡MySQL no arranca automáticamente al iniciar el ordenador!

La solución es sencilla y se encuentra en esta dirección: https://stackoverflow.com/questions/26461173/autostart-mysql-server-on-mac-os-x-yosemite/26465743#26465743

miércoles, 2 de julio de 2014

Selección aleatoria con pesos

Tenemos el siguiente problema: Tenemos un conjunto y hemos de seleccionar aleatoriamente (función de probabilidad uniforme) un elemento de dicho conjunto, lo que ocurre es que cada elemento tiene un peso que lo hace más elegible es decir, tiene más papeletas.

La solución la tenemos en https://stackoverflow.com/questions/6737283/weighted-randomness-in-java

Item[] items = ...;

// Compute the total weight of all items together
double totalWeight = 0.0d;
for (Item i : items)
{
    totalWeight += i.getWeight();
}
// Now choose a random item
int randomIndex = -1;
double random = Math.random() * totalWeight;
for (int i = 0; i < items.length; ++i)
{
    random -= items[i].getWeight();
    if (random <= 0.0d)
    {
        randomIndex = i;
        break;
    }
}
Item myRandomItem = items[randomIndex];
Si vamos a usar reiteradamente Math.random(), es más eficiente usar el objeto Random y llamar a nextDouble(), pues Math.random() usa internamente Random.nextDouble();

Más sobre esto en:
http://www.aprenderaprogramar.es/...
https://stackoverflow.com/questions/738629/math-random-versus-random-nextintint

viernes, 20 de junio de 2014

hashcode

Cuando usamos interfaces tipo Set,  necesitamos que los objetos de la colección tengan el método hashcode() correctamente funcionando. Con los objetos clave del interface Map ocurre lo mismo. Esto es porque para localizar los objetos, o las claves, dentro de la colección se utiliza el hashcode en su optimizado algoritmo de búsqueda.

¿Qué es el hashcodehashcode es un entero más o menos único para cada objeto, y se suele obtener a partir de los campos del objeto.

http://www.ibm.com/developerworks/java/library/j-jtp05273/index.html

Por otro lado, ciertos entornos de desarrollo como Eclipse nos puede generar un hashcode si así se lo requerimos, eligiendo qué campos son los significativos.

Finalmente, hemos de comprobar siempre que equals() y hashcode() actúen en sintonía, como bien dice el artículo.

martes, 29 de abril de 2014

lunes, 14 de abril de 2014

ConcurrentModificationException

En Yoching me he tropezado con un problema de la implementación de Iterable<T>: mientras leo una lista otro hilo intenta modificarla y se produce una excepción de concurrencia.

Leyendo el estupendo artículo de Pankaj (http://www.javacodegeeks.com/2011/05/avoid-concurrentmodificationexception.html), la solución es fácil, pues si bien una parte del programa "lee" la lista para monitorizar el proceso, la otra está "modificando" los datos. Es decir, en la lectura sólo necesito la información para tomar una foto del momento, y la sincronización con la lista mutante no es crítica.

Me basta copiar los datos en un array, mostrar el array y destruirlo, mientras yoching sigue a lo suyo con la lista original.

Cabala, validar email y teléfono desde el cliente

Expresiones regulares: validación de entradas


Para validar textos en el lado del cliente, javascript tiene herramientas muy simples de usar. Sólo hace falta dedicarle unos minutos para entender su funcionamiento:

http://ismaelgsan.com/validar-un-email-con-javascript-de-forma-rapida-y-sencilla/

Extrapolando a un teléfono

Siguiendo el ejemplo el patrón para un teléfono con/sin prefijo de país, con/sin extensión

+349588777#555

/^([+])?([0-9])*(([#])?([0-9])*)*$/

Más información en
http://www.w3schools.com/jsref/jsref_obj_regexp.asp

jueves, 6 de marzo de 2014

Subidas y bajadas: plupload y uploadify

De vuelta a "Revelaciones" y tras varias vueltas, finalmente descarto el uso de uploadify y me quedo con plupload. Esta librería es más versátil en su utilización, es más fácil de integrar y ofrece soluciones alternativas, y opacas para el programador, según los distintos sistemas y navegadores, usando flash, html4, html5 o silverlight según sea necesario.

Respecto a la integración, puedo evitar el uso de un botón que esté siempre visible durante la subida, lo cual me permite hacer la web más fluida. Cuando uploadify, y cualquier elemento basado en flash, se oculta, por ejemplo haciendo un JQuery.hide(), el motor de adobe oculta y deshabilita el objeto, paralizando cualquier proceso que esté ejecutando en ese momento. Y si no queremos ocultar el objeto por estas razones, es prácticamente imposible engañar al sistema cambiando el tamaño del botón flash.

Quizás sea piquismiquis, pero es horroroso tener un control incontrolable. plupload entra en Revelaciones y sale uploadify.

sábado, 1 de marzo de 2014

Adaptando el JList

Para el Yoching me he encontrado con la necesidad de adaptar el sistema de selección de un JList. El comportamiento estándar de una lista es que si se clickea sobre un elemento, éste pasa a estar seleccionado, borrando la selección anterior a no ser que se mantengan pulsadas las teclas shift, control o command, haciendo entonces selecciones múltiples, continúas o discontinúas.

Lo que necesitaba era que la lista simulara el comportamiento de una sucesión de checkboxes, es decir, que si pulso sobre un elemento de la lista, este elemento permuta su estado de selección, manteniendo la selección del resto de la lista inalterada.

Hay varias soluciones para esto, cada cual que elija la suya. Se puede colocar una serie de JCheckBox en un JPanel con layout vertical. Se puede hacer un ListCellRenderer que herede de un JCheckBox e implementar un controlador de activaciones. En cambio, he atacado el problema manipulando el modelo de selección del JList: he creado mi propio ListSelectionModel adaptado la clase DefaultListSelectionModel.

Partiendo del código fuente de DefaultListSelectionModel, encuentro que hay varios métodos que necesito retocar para tener el modo de selección buscado. Por desgracia, para reescribirlos no puedo heredar mi clase de DefaultListSelectionModel, pues en sus tripas se hacen referencia a métodos y campos privados, y lo más fácil es reescribir la clase fuente.

Vamos al código

El primer método en cuestión es setSelectionInterval. Como su nombre indica, establece el intervalo de selección, reseteando el estado anterior. Lo que hay que hacer es que llame directamente a addSelectionInterval, es decir, que añada el nuevo intervalo a la selección existente:

public void setSelectionInterval(int index0, int index1) {
    addSelectionInterval(index0, index1);
}


En addSelectionInterval obviamos las opciones que no nos interesa, pues nuestro modo de edición es MULTIPLE_INTERVAL_SELECTION, y así llegamos al método privado changeSelection. Simplificamos mucho la función original, eliminando el parámetro booleano clearFirst e intercambiando el estado de los items de la nueva selección:

private void changeSelection(int clearMin, int clearMax, int setMin, int setMax) {
    for (int i = Math.min(setMin, clearMin); i <= Math.max(setMax, clearMax); i++) {
        flip(i);
    }
    fireValueChanged();
}

private void flip(int r) {
    if (value.get(r))
        clear(r);
    else
        set(r);
}


Y que no se nos olvide mantener el modo de selección fijo:

public void setSelectionMode(int selectionMode) {
    this.selectionMode = MULTIPLE_INTERVAL_SELECTION;
}


¡Ya sólo falta decirle al JList que queremos tener este modelo de selección!

JList list = new JList();
list.setSelectionModel(new AccumulativeSelectionModel());

La pelea incansable

Tras un día liado porque a veces funciona uploadify y otras no, he llegado a la siguiente conclusión: dejaba de funcionar porque ocultaba uploadify al empezar la subida. Así que lo he cambiado para que se oculte cuando acabe, es decir, cuando en el evento onUploadComplete o en onUploadError la cola tenga un tamaño 0.

viernes, 21 de febrero de 2014

La solución elegante

Tras la entrada anterior, probaré la solución elegante, uploadify. El motivo es que tiene una manera secuencial de subir archivos, evitando bloqueos en el servidor. La semana que viene adaptaré su código al mío.

jueves, 20 de febrero de 2014

Revelaciones

Para el proyecto bíblico Revelaciones vamos a centrarnos inicialmente en modificar las restricciones de subida de archivos intrínsecas al servidor PHP.

La documentación nos la encontramos en http://php.net/manual/es/ini.core.php#ini.sect.file-uploads:

Opciones de configuración de subida de ficheros
NombrePor defectoCambiable
file_uploads"1"PHP_INI_SYSTEM
upload_tmp_dirNULLPHP_INI_SYSTEM
max_input_nesting_level64PHP_INI_PERDIR
max_input_vars1000PHP_INI_PERDIR
upload_max_filesize"2M"PHP_INI_PERDIR
max_file_uploads20PHP_INI_SYSTEM
He aquí una breve explicación de las directivas de configuración.
file_uploads boolean
Si permitir o no la subida de ficheros mediante HTTP. Véanse también las directivas upload_max_filesize, upload_tmp_dir, y post_max_size.
upload_tmp_dir string
El directorio temporal usado para almacenar ficheros durante el proceso de subida. Es necesario tener permisos de escritura para el usuario que está ejecutando PHP. Si no está especificado, PHP usará el predeterminado del sistema.
Si el directorio especificado no tiene permisos de escritura, PHP recurrirá al directorio temporal predeterminado del sistema. Si la directiva open_basedir está activada, al directorio predeterminado del sistema se le ha de permitir la subida de ficheros para que funcione.
upload_max_filesize integer
El tamaño máximo de un fichero subido.
Cuando se usa un integer, el valor del mismo es medido en bytes. También se puede usar la notación reducida, tal como se describe en esta FAQ.
max_file_uploads integer
El número máximo de ficheros a subir permitidos de forma simultánea. A partir de PHP 5.3.4, los campos de subida de ficheros dejados en blanco en el momento del envío no cuentan en este límite.
También hay que modificar la directiva max_post_size, pues ésta limita el tamaño total de archivos de subida. max_post_size debe ser mayor o igual que upload_max_filesize, y memory_limit debe ser mayor o igual que max_post_size.

La directivas ini_get('upload_max_filesize') e ini_get('max_file_uploads') dan los valores por defecto, 2M y 20, así pues hemos de modificar estos parámetros, y solo se puede hacer desde el php.ini. Seguimos los pasos de http://bajolinux.com/upload_max_filesize-php-modificar-el-tamano-maximo-subida-archivo/, pero teniendo en cuenta que en el mac php.ini se debería encontrar en /private/etc/php.ini, y si no, copiamos php.ini.default en esa ubicación (stackoverflow.com):

sudo cp /private/etc/php.ini.default /private/etc/php.ini

Modificamos los parámetros y reiniciamos apache (cyberciti.biz):

sudo apachectl -k restart

Y ahora ya aparecen los valores correctos:

upload_max_filesize: 10M
max_file_uploads: 30

lunes, 17 de febrero de 2014

Mes dos

El sábado descubrí que la máquina había rebasado la capacidad de almacenaje, lo cual iba a ocurrir tarde o temprano, pero ha sucedido demasiado temprano. He tenido que hacer cálculos y previsiones, qué tedioso.

Haciendo un prorrateo sería necesario medio millón de años para terminar la producción, y no exagero. Es necesario tener otro enfoque: cambiar la tecnología y hacer un sistema totalmente no supervisado.

Lo primero es pasar el código JS a Java, una locura. Se pierde tiempo, pero gano en un programa mejor estructurado y, espero, más rápido. Mi pésima memoria ha de recordar la declaración de arrays y el System.arraycopy para clonarlos, la de cosas que se pueden olvidar.

Luego está la fabricación de workers y su ejecutor.

Hoy hemos retrocedido dos pasos para coger impulso mañana.