jueves, 19 de diciembre de 2013

Concerns, issues i problems

A la pàgina 21 del text de "Execució de projectes" de José Ramón Rodrígez ve una reflexió molt curiosa de les diferents accepcions que hi ha en anglès del que naltros anomenam "problemes":

concern: és una preocupació, una cosa que algun dia podria convertir-se en un issue.
issue: una cosa que requereix la nostra atenció i val la pena ocupar-se.
problem: cosa molt seriosa, només passa excepcionalment i supera el nostre control ("Houston, we have a problem...")

De manera que la gestió del issues és important per si de cas un dia es converteixen en un problema.

És tota una filosofia de vida: la gent en compres de pre-ocuparse, s'ocupa.

lunes, 16 de diciembre de 2013

Oracle log como SYSDBA sin ser del grupo dba

Para poder hacer este logeo, primero abrimos una sesión con sqlplus con la opción /nolog para que no escriba en el log del dba sin tener permisos. Luego logeamos como "as sysdba".

$sqlplus /nolog
SQL> connect sys/password as sysdba
Connected
SQL>

domingo, 15 de diciembre de 2013

Oracle formatear fecha incio sesión

CREATE OR REPLACE
TRIGGER set_formato_fecha
AFTER LOGON ON SCHEMA
BEGIN
  dbms_session.set_nls('nls_language','SPANISH');
  dbms_session.set_nls('nls_territory','SPAIN');
  dbms_session.set_nls('nls_date_format','''dd/mm/yyyy''');
END set_formato_fecha;

Mucho cuidado con el sqldeveloper: Formatea las fechas por su cuenta pasando de los nls.

Recordar que siempre podemos forzar con

select to_char(sysdate,'"día" dd "de" month "de" yyyy','nls_date_language=spanish')
from dual;

Oracle crear rol y asignárselo a usuario

-- http://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_9013.htm#i2077938
$sqlplus "/as sysdba"
create role programador;
GRANT CONNECT TO programador;
GRANT create session, alter session TO programador;
GRANT create procedure to programador;
GRANT execute any procedure to programador;
GRANT create table TO programador;
GRANT create sequence TO programador;
Grant create trigger to programador;
Grant create type to programador;
grant create view to programador;
grant create any index, create indextype to programador;
grant debug connect session to programador;
grant debug any procedure to programador;


-- CREATE USER username IDENTIFIED BY apassword;
-- GRANT role_name TO user_name;

-- en 11g la tablespace users ya viene hecha, si queremos podemos crear otra tablespace con
CREATE SMALLFILE TABLESPACE USERS DATAFILE 'u01/app/oracle/oradata/ORCL/espacio.dbf' SIZE 50g;

-- el size puede ser unlimited


ALTER DATABASE DEFAULT TABLESPACE USERS;
ALTER USER user_name QUOTA UNLIMITED ON USERS;


ORA-12528: TNS:listener: all approriate instances are blocking new connection

En un máquina con Windows XP SP3, me salia este error al intentar arrancar OracleXE 11g. Después de googlear un rato, realicé las siguientes acciones:

cd \oraclexe\app\oracle\product\11.2.0\server\bin
>lsnrctl
status
-- mirar si alguno de los servicios está BLOCKED
-- p.e. Instance "xe", status BLOCKED...
-- parar e iniciar el listener
stop
start
-- volver a comprobar el estado

Ahora, entrar como SYSDBA y hacer un startup

set ORACLE_SID=XE
sqlplus "/as sysdba"
-- opcional por si se había quedado con sesiones restringidas
alter system disable restricted session;
-- startup
startup

Volver a probar la conexión. Si el listener ya no está BLOCKED ya está todo bien.

Peeero..... En mi caso, lo que realmente estaba ocurriendo es que el registro de eventos de windows estaba lleno y por eso el listener no arrancaba. No he encontrado este error en Internet documentado de esta manera. Supongo que puede presentarse en multitud de escenarios, por ello conviene cercionarse de vez en cuando de cómo está el registro de eventos y vaciarlo.

El error en concreto lo vi cuando entraba en el sqlplus:






viernes, 6 de diciembre de 2013

Enviar ficheros al servidor que residen en la máquina cliente mediante http POST

Siguiendo con el último artículo, supongamos que lo que queremos es enviar al servidor una o varias imágenes que están en la máquina cliente. Este es un tema muy espinoso y lo más recomendable es instalar un servidor web en la máquina cliente y hacer que el servidor vaya a buscar esos ficheros.

También es cierto que por tema de "atomicidad" queda más bonito enviar imágenes y datos en un solo POST que sólo puede o tener éxito o fallar.

Si en concreto usamos chrome en el cliente, podemos hacer un sencillo "work arround" instalando una extensión de chrome que pida la lectura de unos ficheros en concreto y dándole permisos. Esto tiene la ventaja de que hacemos un solo POST con toda la información necesaria.

Para acceder a los ficheros en el cliente, primero creamos el manifiesto de la extensión de chrome con la lista de ficheros a los que queremos acceder, que deben estar todos en el mismo directorio. El manifiesto también lo guardamos en ese directorio.

manifest.json
{
  "name": "File holder",
  "manifest_version": 2,
  "version": "1.0",
  "web_accessible_resources": ["imagen1.jpg", "imagen2.jpg", "imagen3.jpg"]
}

Ahora, instalamos la extensión: Vamos a chrome->extensions, activamos developer mode y hacemos Load unpacked extension. A partir de este momento, podemos acceder las imágenes locales desde el navegador con
chrome-extension://[app-id]/[imagen]

donde [app-id] es el id de aplicación que nos sale cuando instalamos  la extensión. Ya podemos acceder a los ficheros locales con el protocolo chrome-extension, por ejemplo con

chrome-extension://debeanplnpndkfnlbalbmkikofkghfmk/imagen1.jpg

Podemos enviar la imagen al servidor mediante un POST, así:

    $("#bt_envia").on("click", function (e) {

        var x = new XMLHttpRequest();
        x.onload = function() {
            // Create a form
            var fd = new FormData();
            fd.append("upfile", x.response); 
            fd.append("csrfmiddlewaretoken", "{{ csrf_token }}");

            // Upload to your server
            var y = new XMLHttpRequest();
            y.onload = function() {
                alert('File uploaded!');
            };
            y.open('POST', '/gestion/prova/');
            y.send(fd);
        };
        x.responseType = 'blob';    
        x.open('GET', 'chrome-extension://debeanplnpndkfnlbalbmkikofkghfmk/foto.jpg');
        x.send();

    });


Fuente: varios en stackoverflow y
http://stackoverflow.com/questions/10611796/is-there-any-way-to-load-a-local-js-file-dynamically

Django hacer POST desde javascript con contenido binario

Si queremos hacer un POST con contenido binario como una imagen desde el navegador contra Django, tenemos que tener en cuenta que la llamada a ajax  codifica el stream en UTF-8.

Para desactivar este funcionamiento y hacer el envío "raw" tenemos que poner el responseType como 'blob', de esta forma:

    $("#bt_envia").on("click", function (e) {

        var x = new XMLHttpRequest();
        x.onload = function() {
            // Create a form
            var fd = new FormData();
            fd.append("upfile", x.response); // x.response is a Blob object
            fd.append("csrfmiddlewaretoken", "{{ csrf_token }}");

            // Upload to your server
            var y = new XMLHttpRequest();
            y.onload = function() {
                alert('Fichero subido!!');
            };
            y.open('POST', '/gestion/prova/');
            y.send(fd);
        };
        x.responseType = 'blob';   
        x.open('GET', 'http://planetary.s3.amazonaws.com/assets/images/spacecraft/2013/20131108_2013-3896_f537.jpg', true);
        x.send();

En la parte del servidor, los FILES nos vendrán directamente en el formato nativo, así que sólo tenemos que tratarlos directamente, por ejemplo grabando una imagen en un fichero.

def prova(request):
    #print str(request.body)
    # veure https://docs.djangoproject.com/en/dev/topics/http/file-uploads/
    print "Els files son ", str(request.FILES)
    f = request.FILES['upfile']    
    with open('c:/prova.jpg', 'wb+') as destination:
        for chunk in f.chunks():
            destination.write(chunk)

    return HttpResponse('Mu guay')


Fuente: varios en stackoverflow

lunes, 18 de noviembre de 2013

Naves espaciales: Masa de la nave y masa de los instrumentos

Es sabido que la física de un lanzamiento está impuesta, entre otras cosas, por la ecuación del cohete, por el tipo de trayectoria que se escoja para llegar al destino y por las características de la misión. Esto provoca situaciones como la de la MAVEN (extraido de planetary society), cito:

"The launch mass is 2,454 kilograms, of which 1,645 kg is fuel and only 809 is spacecraft. Of that, the instrument package weighs in at 65 kilograms, and there's an additional 6.5 kilograms devoted to the Electra instrument that allows relay from rovers and landers to Earth."

O sea, que para poner 65 Kg de instrumentos en Marte hay que usar una nave de 2.454 Kg. Es decir, que la verdadera "carga útil" de la nave es el 65/2454 = 2,6% del total. También es cierto que lleva mucho combustible por el tipo de misión.

De todas formas, para el lanzamiento se usará un Atlas V-401 cuya pinta es esta:


Pero es que este bichito tiene una masa de 546.700 Kg. por lo que realmente los 65Kg en Marte implican un 0.000118%, es decir, un uno por diez mil del lanzamiento. Curioso.

Imagen: NASA

sábado, 16 de noviembre de 2013

Uso del atributo data en html5

Html5 nos permite pasar datos arbitrarios en las etiquetas y que estas sigan siendo válidas sin tener que crear una dtd.

El único requerimiento es que el nombre del atributo de la etiqueta debe empezar por data-.

Así, esto es válido en html5:





E incluso podemos pasar datos en formato json:





Realmente útil y además valida.

Hey!, muy guay! ¿Pero qué hay acerca del tratamiento de estos atributos en la hoja de estilos?. Pues también mola porque podemos tratar los data- como cualquier otro atributo.

Vamos a saludar el santo a todos clientes que se llamen Pepe con CSS:

Rodrígez Pérez, José

Y la hoja de estilo:
div[data-nombre="Pepe"] { 
   background-color: red; 
}
div[data-nombre="Pepe"]:after { 
  content: attr(data-saludo); 
}




Para saber más:

htmldoctor
tutsplus

jueves, 17 de octubre de 2013

Jquery seleccionar todos los checkbox de una clase que están seleccionados

Este me ha costado un rato, para seleccionar todos los checkbox de una determinada clase que están seleccionados podemos usar los filtros en cascada $("[condicion1][condicion2]...") pero por alguna razón no he logrado que me funcione.

Sin embargo, usando filter es trivial:

var n = $(".clase").filter(":checked").length;

console.log("Se han seleccionado "+n);



lunes, 30 de septiembre de 2013

Decibelios: Mi primera entrada en ipython notebooks/ Decibels: My first ipython entry in ipython notebooks

Unos apuntes de decibelios tomados de varias fuentes y un ejemplo de sampling y graficado. Espero que os guste.

http://nbviewer.ipython.org/urls/raw.github.com/pvilas/ipython-notebooks/master/Decibelios.ipynb

A few notes about decibels taken from several sources and an example of sampling and plotting. Hope you enjoy.

sábado, 28 de septiembre de 2013

ipython notebooks: En la nube o en windows

En la nube

La empresa wakari ofrece notebooks ipython con todas las funcionalidades online!!

Por el momento es gratuito y permite guardar los cuadernos en la nube. La dirección es:

https://www.wakari.io

Para empezar

Una buena introducción a los módulos para ciencia y tecnología.

En windows

Si queremos usar los notebooks en windows la mejor opción es instalar el entorno (gratuito) de Canopy. Una vez instalado abrimos la "Canopy command prompt" que está configurada con el entorno completo para correr iphyton y abrimos una sesión con, por ejemplo,

ipython notebook --pylab inline

Si queremos editar en Latex directamente con la etiqueta %%latex tened en cuenta esto.


ipython: Shell python científica. Instalación.



Para los que estamos usando python en el día a día, es normal que si tenemos que hacer matemáticas, preparar gráficos vectoriales de calidad, documentar un proyecto o simplemente investigar una idea contemos también con nuestro lenguaje preferido en vez de irnos a un Mathematica, Matlab o similar.

Ojo, no estoy diciendo que uno sea mejor o peor que otro. Simplemente digo que si como yo usas python habitualmente, y no usas Mathematica cada día, tal vez te sea más cómodo usar ipython en tus proyectos científicos.

Una ventaja evidente es que tenemos a nuestra disposición la enorme y probada en situación real biblioteca de python para hacer cualquier cosa imaginable que pueda hacer una computadora. La desventaja es que tal vez tengas colegas que (aún) no saben python y no te venga bien si tienes que trabajar en grupo.

Básicamente ipython es una shell de python mejorada con código resaltado y gráficos.

Instalación

Web del proyecto:
http://ipython.org/index.html

Si queremos usar la consola gráfica necesitamos las Qt. Para instalar pyqt (escojer la combinación adecuada de versión de python y sistema operativo):
http://www.riverbankcomputing.co.uk/software/pyqt/download

Nota: Para saber qué versión de python tienes instalada haz python --version en la linea de comandos

Instalar librerías matemáticas y de plotting 

Scipy (recomiendo anaconda): http://www.scipy.org/install.html
Matplotlib: http://matplotlib.org/downloads.html
... Si faltan librería recordar que easy_install nombre-de-libreria es nuestro mejor aliado.
Para comprobar si matplotlib está bien instalado python -c "import matplotlib" no debe dar errores

Compartir notebooks

http://nbviewer.ipython.org/

Shortcuts

ipython Open IPython terminal console 
ipython qtconsole Open IPython qtconsole 
ipython notebook Open IPython Notebook (browser interface)
ipython notebook --pylab inline Open IPython Notebook with inline graphs
ipython notebook --pylab qt Open IPython Notebook with popup graphs
ipython3 Use the Python3 version of IPython
ipython --help-all Show all IPython start flags

martes, 24 de septiembre de 2013

Breaking Bad: Pequeño homenaje




¡Gracias a Vince Gilligan y a todo el equipo por los grandes momentos que nos han hecho pasar!
Fantastico ensayo en wired acerca de BB y la masculinidad.

Saul Goodman (Better Call Saul):
"If you're committed enough, you can make any story work. I once told a woman I was Kevin Costner, and it worked because I believed it"

Skyler:
"All I can do is wait . . . for the cancer to come back

Mike Ehrmantraut:
"Just because you shot Jesse James doesn't mean you are Jesse James."

Marie Schrader:
"They’re rocks"

Walter White, Jr.:
"He's a great father, a great teacher. He knows like everything there is to know about chemistry. He's patient with you, he's always there for you. He's just decent. And he always does the right thing and that's how he teaches me to be."

Gustavo Fring:
"I hide in plain sight, same as you"

Jesse Pinckman
"Yeah, bitch! Magnets!"

Hank Schrader:
"Heisenberg? Heisenberg! You two-faced sack of s--t! I will put you under the jail"

Vince Gilligan (Breaking Bad creator):
"You take Mr. Chips and turn him into Scarface."

Walter White:
"I am not in danger, Skyler. I am the danger! A guy opens his door and gets shot and you think that of me? No. I am the one who knocks!"




Source: The Telegraph
Picture: AMC

viernes, 30 de agosto de 2013

Django desde un template llamar a un procedimiento del primer objeto de un query

Puede usarse el with con esta sintaxis:

<img {% with im.inmuebleimagen_set.all|first as imagen %}
src="{{imagen.get_url}}"{%endwith%}
/>

martes, 27 de agosto de 2013

Django cambiar de lenguaje desde el view

Para cambiar el LANG en el servidor, asumiendo que tenemos todo el sistema de traducción correctamente configurado, llamamos via POST a la ficha setlang y le pasamos el campo language con la lengua seleccionada:

En settings definimos los lenguajes con los que trabajamos:

LANGUAGES = (
    ('es', ugettext(u'Español')),
    ('de', ugettext(u'German')),
    ('en', ugettext(u'English')),
);


En urls, incluimos las url de i18n:

(r'^i18n/', include('django.conf.urls.i18n')),


Y ya en el template podemos llamar a la ficha /i18n/setlang para setear el lenguaje:

<li class="gbt">
    <form name="setLangSpanish" action="/i18n/setlang/" method="POST">{% csrf_token %}
        <input name="next" type="hidden" value="/" />
        <input type="hidden" name="language" value="es" />
        <a href="#" class="language_off" onclick="document.setLangSpanish.submit();return false;">
            <span class="language_off sprachwahl">Español</span></a>
    </form>
</li>
<li class="gbt">
    <form name="setLangEnglish" action="/i18n/setlang/" method="POST">{% csrf_token %}
        <input name="next" type="hidden" value="/" />
        <input type="hidden" name="language" value="en" />
        <a href="#" class="language_off" onclick="document.setLangEnglish.submit();return false;">
            <span class="language_off sprachwahl">English</span></a>
    </form>
</li>
<li class="gbt">
    <form name="setLangDeusch" action="/i18n/setlang/" method="POST">{% csrf_token %}
        <input name="next" type="hidden" value="/" />
        <input type="hidden" name="language" value="de" />
        <a href="#" class="language_off" onclick="document.setLangDeusch.submit();return false;">
            <span class="language_off sprachwahl">Deusch</span></a>
    </form>                
</li>


Fuente: oscarcp http://blog.oscarcp.com/?p=163

miércoles, 24 de julio de 2013

Mysql borrado rápido filas duplicadas

En este sitio he encontrado una forma muy rápida de eliminar duplicados. Tan rápida que puede hacerse con una sola línea, se trata de crear ununique index con la palabra clave IGNORE. Tal que esto:

ALTER IGNORE TABLE dupTest ADD UNIQUE INDEX(a,b);


Guay eh?

martes, 23 de julio de 2013

Django filtro de query usando un string

Es común que queramos pasar directamente un string al filtro de una consulta, por ejemplo, desde una url. Dado que el parámetro de filter es un diccionario, lo podemos hacer mediante el operador de desempaquetado de diccionarios **.

Recordemos que para desempaquetar una lista usamos el operador * y para desempaquetar un diccionario el **:

Ejemplo de *


>>> pepe=(1,10,)
>>> range(pepe)
Traceback (most recent call last):
File "", line 1, in
TypeError: range() integer end argument expected, got tuple.
>>> range(*pepe)
[1, 2, 3, 4, 5, 6, 7, 8, 9]

Ejemplo de **



>>> pepe={ "venus" : "blanco", "tierra": "azul", "marte": "rojo" }
>>> '{tierra}'.format(pepe)
Traceback (most recent call last):
File "", line 1, in
KeyError: 'tierra'
>>> '{tierra}'.format(**pepe)
'azul'
>>>


En ambos ejemplos observamos que al usar * o ** pasamos con el tipo correcto. Pero ¿Cómo aprovecharlo para pasar directamente un filtro a la consulta?. Yo lo hago de la siguiente forma:


# un string
filtro="nacionalidad__exact@ESP"
# lo parseamos en clave-valor
f=filtro.split("@")
# pasamos como diccionario
p=Persona.objects.filter(**{f[0]:f[1]})
# el efecto es el mismo que hacer
p=Persona.objects.filter(nacionalidad__exact='ESP')

Y ahora veamos cómo implementarlo.

En la página web:

$('a.pais').click(function() {
   var pais=$(this).attr("pais");
   $('#{{entidad}}').load("?filtro="+escape('nacionalidad__exact@'+pais)+"&type=ajax");
});


Notemos que en la url pasamos,
  1. Un interrogante: Hará un get sobre la página actual.
  2. Un nombre de parámetro (filtro). Si queremos añadir más parámetros los separamos con &
  3. El valor del parametro poniendo un igual después del nombre, por ejemplo,  filtro=nacionalidad__exact@ESP 
En la parte del servidor lo que hacemos es procesar directamente el filtro pasando de string a diccionario así:


def get_filtro( self, request):
  """ aplica el filtro y devuelve el modelo filtrado """
   filtro=request.GET.get('filtro', False)
   if filtro:
  try:
     f=filtro.split('@')
     return Persona.objects.filter(**{f[0]:f[1]})
   except Exception, e:
    logger.error('desempaquetando filtro '+str(e))

   return Persona.objects.all()


La ventaja de este método es que es muy sencillo crear toda clase de filtros directamente en la página web teniendo un solo código que los gestiona en el servidor. 

Una última puntualización: Si no todos los usuarios pueden ver todo el modelo i.e. ver todas las personas Persona.objects.all() hay que ir con cuidado ya que es muy sencillo manipular a mano la url para que nos devuelva cualquier registro. Por ejemplo:

?filtro=moroso__exact@1

Nos devolvería todos los morosos ;-)



lunes, 22 de julio de 2013

Reproducir vídeos en la Nexus 10 por USB

De forma nativa no podemos conectar un disco externo o pen drive a la Nexus para reproducir vídeo. Para poderlo hacer precisamos dos cosas:

  1. Que la Nexus nos haga de "host" USB para que pueda leer desde dispositivos USB.
  2. Eventualmente, poder reproducir el formato AVI.

Conexión del dispositivo USB a la Nexus 10

Necesitamos un cable OTG (USB On-the-go) para poder conectar el dispositivo (hembra) en el micro-usb de la tablet. Son muy baratos y se encuentran en cualquier tienda de componentes o electrónica.






También necesitamos que el sistema operativo nos reconozca el dispositivo. Como android no lo hace, tenemos que instalar software. Una aplicación que funciona sin problemas (no es necesario entrar como root) es Nexus Media Importer. Basta con conectar el dispositivo y ya tendremos acceso al contenido del disco.



Reproducción de AVI

Hay muchos buenos programas que reproducen AVI y mantienen los códecs actualizados. Yo uso el MX Player Pro, al que podemos activar la decodificación por hardware (en la pestaña de Configuración-Decodificación)


lunes, 15 de julio de 2013

Django error "name field too short" generando permisos en el admin si verbose_name está presente

El verbose_name de un modelo sirve para dar una descripción extendida de él. Si está presente, es usada por el admin para describir el modelo, si no, se usa el nombre de la clase. Por ejemplo:

class Cliente(models.Model):
  ...
  ...
   verbose_name=u"Esta descripción saldrá en el admin, es un poco larga para mostrar el error"
   verbose_name_plural=u"Esta es la descripción que se usa en plural"


Para poder administrar el modelo, lo incluimos y registramos en admin.py:

class ClienteAdmin(admin.ModelAdmin):  
    list_display=('nombre','codigo',)
    ....
admin.site.register(Cliente, ClienteAdmin)  


En el primer runserver que hagamos, el admin intentará registrar el modelo y crear los permisos de add, change y delete. El problema es que la descripción del permiso es del estilo de "Can add "+verbose_name y se almacena en el campo name de la tabla auth_permission que está definido con 80 caracteres de largo. Por lo tanto, la creación de permisos fallará si se supera esa longuitud y nos encontraremos con el modelo registrado en el admin pero sin poderle asignar permisos.

Registré el bug y resulta que lo han cerrado como duplicado  de otro de hace cinco años!!!. Claro que es fácil quejarse y no currar en el proyecto....

De momento, para resolverlo basta con editar a mano la longitud del campo:

ALTER TABLE auth_permission MODIFY name VARCHAR(500);


Consola linux en utf8 (debian, ubuntu)

Un problema común cuando usamos la cónsola para pasar datos de una aplicación a otra o para pasar un dump de mysql a otro servidor es que la cónsola no acepta utf8 y nos corrompe los caracteres extendidos.

Para que podamos usar la cónsola en utf8 con es_ES, hemos de asegurarnos, en primer lugar, de que los locales están generados haciendo:

sudo locale-gen es_ES.UTF-8
sudo dpkg-reconfigure locales


y para que la sesión de bash use dicha configuración añadir en el .bashrc

export LANG=es_ES.UTF-8
export LANGUAGE=es_ES.UTF-8


Si no funciona y estamos iniciando la sesión desde otra máquina hemos de asegurarnos de que el cliente también tenga dicha configuración. Si estamos usando putty para una sesión ssh hay que ir a Preferences-Window-Translation y poner el remote character set en UTF-8 y guardar el perfil.

viernes, 12 de julio de 2013

Calidad de imagen en cámaras digitales: La aberración cromática

Voy a intentar explicar, desde mi perspectiva de fotógrafo aficionado, qué es la aberración cromática y cómo afecta a la calidad final de la fotografía digital. Empezaremos repasando unos conceptos.

Índice de refracción

La medida relativa de la velocidad de la luz en un medio respecto de la del vacío se llama índice de refracción.
n es índice de refracción del material.
C es la velocidad de la luz en el vacío
v es la velocidad de la luz en el material

n siempre será mayor o igual que 1 puesto que la máxima velocidad de la luz se da en el vacío.

Refracción de la luz

Cuando la luz cambia de medio se produce el fenómeno de la refracción. El fenómeno está relacionado con la distinta velocidad de propagación de la luz en diferentes medios materiales.

Observamos que cuando pasamos de un medio como el aire a otro más "denso" como el agua o el vidrio (mayor índice de refracción) la dirección de los rayos de luz cambian, acercándose a la normal.




El fenómeno es aprovechado por las lentes para enfocar rayos de luz en un punto y conseguir aparatos como la lupa, el microscopio, el telescopio o el objetivo de una cámara fotográfica.

Los ángulos del rayo incidente y el refractado están relacionados mediante la Ley de Snell:


Dispersión de la luz

Pero claro, decir que la onda "cambia la velocidad" tal vez sea un poco simplista. Vamos a ver, la velocidad es el cambio de posición respecto al tiempo, el "espacio partido por tiempo" de toda la vida. En el caso de las ondas este "espacio" se llama longitud de onda (la letra griega lambda)
es la distancia que separa dos máximos consecutivos y el "partido por tiempo" se llama frecuencia (la letra f), o sea:


O resumiendo,

Mientras la onda se propaga en otro medio, cambia su longitud de onda y la frecuencia se mantiene constante. Entonces, para que la igualdad se mantenga con f y v constantes, vemos que las ondas que tienen menor frecuencia cambiarán más su longitud de onda (lambda) que las que tienen mayor frecuencia. En una palabra, las ondas con frecuencias más altas se refractarán en ángulos más grandes que las ondas con con frecuencias más bajas. Este fenómeno genera la llamada "dispersión de la luz".

Sabemos que la luz que proviene del Sol está formada en realidad por la combinación de diferentes ondas con longitudes diferentes.

Podemos observarlo haciendo pasar un rayo de luz del sol (que vemos blanco) por un prisma.


Los colores que aparecen están ordenados por su longitud de onda. A mayor frecuencia, menor longitud de onda. El violeta tiene mayor frecuencia y menor longitud de onda que el rojo y por tanto se desvía más. Una luz que tiene un solo color (monocromática) sólo tiene una longitud de onda y por lo tanto no habría dispersión.

Aberración cromática

El problema de la aberración cromática viene entonces porque en el momento en que usamos una lente para enfocar una luz no monocromática en un punto, las diferentes longitudes de onda se enfocarán en puntos diferentes debido a que se refractan en ángulos diferentes.



Esto causa una merma en la calidad de las imágenes. El fenómeno es más acusado cuanta más curvatura y diámetro de la lente, o sea, en los objetivos gran angular. Veamos abajo cómo afecta la aberración cromática en función del diámetro efectivo de la lente. F1,4 es el doble de apertura que F1,7 y F2 el doble que F1,7. Se observa que así como vamos cerrando la lente (número F mayor) va disminuyendo la aberración y va mejorando la calidad.



Peeeero (siempre hay un pero) esto no es todo. Aparte de otro tipo de aberraciones ópticas, existe un factor adicional que afecta a la calidad de imagen digital; Está relacionado con la forma de capturar el color de la propia cámara

Cámaras digitales

El capturador de la cámara posee una matriz de elementos fotosensibles y es capaz  de contar la cantidad de fotones que inciden durante un determinado periodo de tiempo en cada uno de esos elementos. El proceso de conversión nos da una medida del "nivel" de luz que ha alcanzado cada elemento. En principio, esta medida no nos da información de color; Vendría a ser la imagen en blanco y negro. ¿Cómo pues obtiene la cámara la información de color?.

El filtro de Bayer

La información de color se obtiene disponiendo un filtro de colores sobre el sensor de esta forma:



Se observa que el patrón es RGB (Rojo, Verde, Azul) de 2x2. Se da más importancia al verde porque el ojo humano es más sensible en esa longitud de onda. Para cada cuatro elementos, tendremos la información de color de un pixel en la imagen final. La determinación del color de ese pixel se realiza a partir se la medida de las cuentas de rojo, verde y azul. La conversión de la información en crudo ("raw") a los valores de pixel se ha dado en llamar "revelado digital". El algoritmo de conversión se llama interpolación de Bayer.

El problema de la aberración cromática

Todo esto viene a cuento de que, como es evidente, el sensor es plano pero la aberración hace que los diferentes colores se enfoquen un poco "antes" o "después" de ese plano y por tanto confunden al algoritmo de interpolación. Esto causa una degradación adicional de la calidad de la imagen.


Soluciones

Las soluciones son de dos tipos:

  1. Ópticas: Se usan lentes de distintos tipos e índices de refracción para enfocar mejor los diferentes colores.
  2. Software: Que tiene en cuenta la aberración de cada objetivo y lo compensa en el momento del revelado.


Espero que esta entrada os haya ayudado a entender qué es la aberración cromática y cómo influye en la calidad final de la fotografía.

Un saludo a los estudiantes de Física II del Grado de Telecomunicación de la UOC.

Nota:
Cabe decir que cuando nos referimos a la "luz", queremos decir cualquier onda electromagnética.


Imagen refracción crédito: By Josell7 (Own work) [GFDL (http://www.gnu.org/copyleft/fdl.html) or CC-BY-SA-3.0-2.5-2.0-1.0 (http://creativecommons.org/licenses/by-sa/3.0)], via Wikimedia Commons

Imagen dispersión crédito: Wikimedia Commons

Imagen aberración cromática crédito: By Andreas 06 (Own work) [Public domain], via Wikimedia Commons

Imagen mosaico de Bayer: By en:User:Cburnett [GFDL (http://www.gnu.org/copyleft/fdl.html), CC-BY-SA-3.0 (http://creativecommons.org/licenses/by-sa/3.0/) or GPL (http://www.gnu.org/licenses/gpl.html)], via Wikimedia Commons

miércoles, 10 de julio de 2013

Django name field on auth_permission too short

If the verbose_name of the table is over 80 characters the syncdb command will silently fail.
The name field on auth_permissions table is too short to store if verbose_name are that long, so it doesn't update and you cannot assign permissions.
The obvious workaround is to manually change the field length on the table.
I have opened the ticket 20728

Thanks Victor!

lunes, 8 de julio de 2013

Guiado de un cohete

Los de Copenhagen Suborbitals están que no paran. Sus vídeos de cohetería amateur son una joya para cualquier afcionado; Resumen en pocos minutos los aspectos más complejos de la construcción y diseño de un cochete.

Un vídeo que me ha parecido especialmente interesante es el de guiado:




jueves, 20 de junio de 2013

Sondear (refrescar) a largo plazo con javascript jquery / jquery javascript long polling

Si queremos refrescar el contenido de una pagina web cada cierto tiempo hacemos

<meta http-equiv="refresh" content="5"/>

Pero si queremos refrescar sólo un div y queremos estar seguros de que el refresco se realice incluso después de que falle alguna de las peticiones, podemos hacer:

$(document).ready(function(){
function doPoll() {
$.post('/pagina/').done(function(data) {
$('#contenedor').html(data);
}).always(function() { setTimeout(doPoll, 5000); });
}
doPoll();
});



Nótese el empleo de always que es una manera elegante de no tener que pelearnos con la posibilidad de que falle una de las peticiones y el div se quede sin refrescar.

miércoles, 19 de junio de 2013

Cançó de vesprada

Tres grans pins, vora el camí,
alcen llurs ombrivols fronts.
El vent, que no vol dormir,
els omple el cor de cançons.
Camp i camp. Es vessa al mig
una campana vespral...
Voler l'impossible ens cal,
i que no mori el desig.

S'ha despertat tot l'amor
sota la volta d'estels.
¿Déu no es mostra al nostre anyor
en el seu món, sense vels?
S'escolta com el trepig
d'una bellesa inmortal.
Voler l'impossible ens cal
i que no mori el desitg.

Marià Villangómez
Elegies i paissatges
1949

sábado, 11 de mayo de 2013

Recurso enseñanza de inglés. Marco Polo-R Propuesta europea para el retorno de muestras de un asteriode

Daniel Marín informa de la propuesta para el retorno de muestras de un asteroide dentro del programa Cosmic Vision de la Agencia Espacial Europea ESA.

Me ha hecho mucha gracia el cómic que acompaña al proyecto: Explica la misión, el diseño, fases, ciencia, etc. en un nivel perfectamente comprensible para alumnos de secundaria.

Como está en inglés he pensado que tal vez podría servir de recurso para dar clases de este idioma y de paso que los chavales aprendan algo de exploración espacial.

El cómic viene en jpgs de diferentes tamaños; los he juntado y he creado un pdf más fácil de manejar e imprimir aunque la resolución de las imágenes originales no es muy alta. Les he pedido una versión en alta resolución.

De momento sólo llega hasta la página 16, lo iré actualizando así como vayan apareciendo nuevos episodios.

Recurso enseñanza inglés: Descargar Marco Polo R el cómic.


Instalar Django en Windows

Una de las formas es esta:
  1. Bajar e instalar python (2.7 en este momento)
  2. Incluir C:\Python27;C:\Python27\Scripts en el path
  3. Copiar este script de instalación de distribute en un fichero (distribute_setup.py) y ejecutarlo python distribute_setup.py
  4. Bajar ultima versión de pip y copiar a directorio; instalar usando python setup.py install
  5. Instalar Django con pip install Django==1.5 (1.5 es la última versión en este momento)
  6. Probar python -c "import django" (no debe dar ningún error)
  7. Crear la última killer app ;-)



viernes, 10 de mayo de 2013

Buscar en inglés con google

Para realizar búsquedas en google con resultados en inglés

http://www.google.com/ncr

o bien

http://www.google.com/webhp?hl=en

Esta url también acepta otros idiomas codificados en ISO-639-1 de dos caracteres, por ejemplo, prueba en albanés o en kanuri (hablado en Nigeria).

lunes, 6 de mayo de 2013

Eivissa des de la ISS (Eivissa from the ISS)

L'expedició 35 de l'Estació Espacial Internacional va prendre aquesta imatge de la nostra estimada casa el 22/03/2013.



Font:
Nasa: International Space Station Imagery

lunes, 29 de abril de 2013

Apache httpd CentOS Certificate not verified: 'Server-Cert'

En CentOS, si de repente tenéis el servidor web caido y os sale este error en /var/log/nss_error_log es porque está instalado el módulo mod_nss y aunque el httpd no lo está cargando, detecta que el certificado de prueba que instala nss automáticamente está caducado.

La solución es desinstalar el módulo

yum remove mod_nss


Ejemplo de error:

[Mon Apr 29 13:37:24 2013] [error] Certificate not verified: 'Server-Cert'
[Mon Apr 29 13:37:24 2013] [error] SSL Library Error: -8181 Certificate has expired
[Mon Apr 29 13:37:24 2013] [error] Unable to verify certificate 'Server-Cert'. Add "NSSEnforceValidCerts off" to nss.conf so the server can start until the problem can be resolved.


Bug en RH:

https://bugzilla.redhat.com/show_bug.cgi?format=multiple&id=711085

miércoles, 6 de marzo de 2013

Backup de los procedimientos almacenados mysql

El mysqldump no copia los stored procedures por defecto pero si los triggers, es decir, los parámetros por defecto son:

--routines FALSE por defecto
--triggers TRUE por defecto

Para volcar sólo los procedimientos almacenados:

mysqldump --routines --no-create-info --no-data --no-create-db --skip-opt database > procedimientos.sql

Para importar los procedimientos a otra db:


mysql database < procedimientos.sql

Para hacer un backup de datos y triggers que también copie los procedimientos almacenados:


mysqldump --routines outputfile.sql


Fuente:
http://www.ducea.com/2007/07/25/dumping-mysql-stored-procedures-functions-and-triggers/

jueves, 28 de febrero de 2013

Depurar procedimientos almacenados mysql

Depurar procedimientos de bases de datos suele ser una tarea ingrata a no ser que tengamos alguna herramienta de desarrollo. Pero aún estas herramientas suelen modificar internamente el procedimiento para efectuar el depurado además de crear multitud de tablas intermedias para guardar el estado de las variables en cualquier punto de la ejecución.

Si no te interesa este enfoque y sólo necesitas ir haciendo un log de lo que ocurre propongo el siguiente sistema que he ido mejorando a partir de diversas fuentes y experiencias.

La idea se basa en la creación de una tabla temporal donde vamos realizando el log mediante una llamada al procedimiento doLog(msg).

Primero creamos una tabla de configuración:

CREATE TABLE `internal_config` (
`debug` tinyint(4) NOT NULL DEFAULT '1'
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

insert into internal_config(debug) values(0);

Que nos servirá para activar/desactivar el debug con:

update internal_config set debug=true;

El procedimiento que crea la tabla temporal es:

CREATE PROCEDURE `setupTmpLog`()
BEGIN
 CREATE TEMPORARY TABLE IF NOT EXISTS tmplog(
   lin integer NOT NULL AUTO_INCREMENT primary key,
   msg VARCHAR(512)
 ) ENGINE = MEMORY;
END

y el que escribe el log:

CREATE PROCEDURE `doLog`(IN logMsg VARCHAR(512))
BEGIN
 declare do_debug bool default false;
 DECLARE CONTINUE HANDLER FOR NOT FOUND SET do_debug=false;
 DECLARE CONTINUE HANDLER FOR 1146 -- Table not found
  BEGIN
    CALL setupTmpLog();
    INSERT INTO tmplog(msg) VALUES ('resetup tmp table');
    INSERT INTO tmplog(msg) VALUES (logMsg);
  END;

 select debug from internal_config limit 1 into do_debug;

 -- escribimos en el log solo si debug esta activado
 if (do_debug) then
   INSERT INTO tmplog(msg) VALUES (logMsg);
 end if;
END

y finalmente, un procedimiento que nos muestra el log (con el último mensaje primero) y después borra la tabla:

CREATE PROCEDURE `view_log`()
BEGIN
  DECLARE CONTINUE HANDLER FOR 1146 -- Table not found
   BEGIN
    CALL setupTmpLog();
   end;

   select msg from tmplog order by lin desc;

   drop table tmplog;
END

Ya lo tenemos todo, para ir logeando en nuestros procedimientos sólo tenemos que llamar a doLog así:

call doLog(concat("Hola", " que ", " tal " ));

Y cuando queramos ver (y limpiar) el log hacemos:

call view_log();

Espero que os sirva. Good Luck ;-)


Fuentes:
http://www.drdobbs.com/database/debugging-mysql-stored-procedures/218100564?pgno=1

jueves, 21 de febrero de 2013

entender los joins sql gráficamente

Este gráfico puede servirnos para recordar qué partes se incluyen o se excluyen en los diferentes tipos de joins:


  1. INNER JOIN
  2. LEFT JOIN
  3. RIGHT JOIN
  4. OUTER JOIN
  5. LEFT JOIN EXCLUDING INNER JOIN
  6. RIGHT JOIN EXCLUDING INNER JOIN
  7. OUTER JOIN EXCLUDING INNER JOIN





Fuente:
Visual representation of SQL joins