El sistema de clasificación COPA

Luis Meléndez - luism@uco.es - Dic. 2007

COPA [1] es un sistema desarrollado por RedIRIS [2] que permite establecer clasificaciones (introducir estructuras, típicamente jerárquicas) en sistemas de información allí donde la disposición lógica de los items no las reflejan, o donde se puede establecer en ellos distintas jerarquías según diferentes conceptos (en este documento usaremos los términos clasificación, jerarquía, vista y árbol de forma más o menos equivalente, aunque una clasificación puede tener un sólo nivel). También se puede usar COPA para mantener y gestionar grupos, expresar ontologías, etc.

Aunque COPA puede aplicarse en distintos ámbitos, nos centramos en este documento en su aplicación a LDAP, para lo cual se ha definido un esquema específico. La versión de COPA que vamos a explicar es la 2.1.0. LDAP es un ámbito de aplicación muy adecuado para COPA debido a que actualmente se acepta que la estructura del DIT debe ser lo más plana posible, y COPA nos permite expresar jerarquías en un contexto plano.

La documentación de COPA en su página Web está muy centrada en la utilización de interfaces de navegación por las distintas vistas que se definan. En este documento el énfasis se hace más en su utilización desde aplicaciones que necesiten la funcionalidad que permite.

Conceptos

La esencia de COPA es que se asigne a cada entrada del directorio que deba pertenecer a alguna clasificación o jerarquía un código alfanumérico que está construido de tal forma que refleja en sí mismo su posición dentro de dicha clasificación. Dicho código va precedido de un prefijo que indica la clasificación a la que pertenece, para el caso de que haya varias. El resultado final es un URN que se aconseja que tenga el siguiente formato:
urn:mace:rediris.es:<id-institucion>:classif:<id-clasificacion>:<version>:codigo
Por ejemplo:
urn:mace:rediris.es:uco.es:classif:por_relacion:1.0:a1b2
donde todo lo que precede a codigo es lo que llamamos prefijo.

Ése es el valor que se asignará a cada entrada en un atributo que típicamente será irisClassifCode.

Pero lo importante es el código en sí, que como hemos dicho refleja la estructura que se quiere reflejar. Los códigos de los que hablamos están compuestos de secuencias de conjuntos de una letra y uno o más dígitos, e incorporan en sí mismas información sobre la jerarquía. Así a1, a2, a3, ... son las etiquetas de los nodos (Áreas) del primer nivel. a1b1, a1b2, a1b3... son las de los hijos de a1. El nivel se expresa con la letra (a, b, c, ...) y los distintos nodos dentro del mismo nivel, con números tras la letra. Así a2b1c3 es el tercer elemento de los hijos del primer elemento de los hijos del segundo elemento del primer nivel.

              a1     a2    a3
                     |
                +----+------+
              a2b1   a2b2   a2b3
                |
        +-------+-------+
      a2b1c1   a2b1c2  a2b1c3
Estos códigos no incluyen por tanto el nombre de los nodos. Si el uso de COPA es para aprovechar su funcionalidad desde aplicaciones ad-hoc, éstas incluirán el conocimiento sobre los mismos. Si queremos usar algún interfaz de navegación (como navega 2.0 [7] ) debemos declarar en una rama del DIT sus nombres, así como otros datos (ver el apartado dedicado a la navegación). Incluso en el caso de aplicaciones propias puede ser interesante declarar estos nombres.

Veamos un ejemplo que refleja la estructura de una Universidad, originado en la Universidad de León [5]:

a1 Centros
a1b1 Aulario
a1b2 Escuela Superior y Técnica de Ingeniería Agraria
...
a2 Departamentos
a2b1 Biología Animal
a2b2 Biología Celular y Anatomía
...
a3 Fundaciones
a3b1 Fundación Perico de los Palotes
...
a4 Gerencia
a4b1 Area de Recursos Humanos
a4b2 Biblioteca Universitaria y Archivo
...
a5 Organos, Comisiones y Representaciones
a5b1 Defensor de la Comunidad Universitaria
a5b2 Programa Institucional de Calidad
...
a6 Rectorado
a6b1 Secretaría General
a6b2 Vicerrectorado Del Campus XXX
...
a7 Institutos
...
a8 Consejo Social
...
Hay otras clasificaciones en [6]. La idea es tan simple como potente: Como ejemplo del último punto, una búsqueda de todos los integrantes de un departamento es trivial, por ejemplo usando el filtro:
(irisClassifCode=*id-clasificacion*:a2b2)
Y podemos obtener la lista de todos los que pertenecen a algún departamento con:
(irisClassifCode=*id-clasificacion*:a2*)

Navegación

Una aplicación muy importante de COPA es la implementación de interfaces Web que permitan navegar y/o buscar según las distintas vistas. La mayor parte de esquema COPA está destinada a ser usado de forma que estos interfaces puedan obtener por sí mismos la información necesaria para su correcto funcionamiento: las vistas que hay definidas y para cada una de ellas dónde están los nombres de los nodos, qué atributos se usan en las entradas de personas para almacenar los códigos COPA de las clasificaciones a las que pertenecen, el prefijo que se usa, etc.

Implantar COPA

Los elementos de una implementación típica de COPA con soporte para interfaces de navegación son:

Si no deseamos navegación, nos basta con el último punto.

Clases de objetos y atributos

El esquema COPA es relativamente difícil de entender a primera vista, quizá porque gran parte de él está orientado a facilitar el desarrollo de herramientas gráficas o basadas en Web que permitan la navegación por las distintas vistas o jerarquías, y para que éstas encuentren toda la información que necesitan de forma automática en el directorio y no tengan que ser configuradas. Si obviamos este uso y sólo vamos a usar COPA desde aplicaciones propias todo es bastante más sencillo, pues en este caso realmente no habría que usar el esquema COPA en absoluto, simplemente incluir en cada entrada del DIT que deba formar parte de una clasificación un código COPA en el atributo irisClassifCode (esquema Iris, clase irisObject) o copaCode (esquema COPA, clase copaResource).

Las clases de objeto y sus atributos son:

copaVirtualViewSpec

Es una clase estructural, la idea es que se defina un objeto que sólo pertenece a esta clase. Es semejante a un fichero de configuración: los atributos que incluye declaran información sobre la vista, principalmente para su uso por parte de las aplicaciones de navegación por vistas, como navega [7] . Existirá un objeto de este tipo para cada vista.

copaClassifBase1 El DN de la base del subárbol del DIT que contiene los objetos del tipo copaArea que definen la jerarquía.
copaPrefix1 El prefijo del URN que se incluye en cada entrada del DIT y cuya última parte es el código COPA. En el apartado Conceptos hemos explicado su formato. Se usa entre otras cosas para distinguir a qué clasificación se refiere.
copaName1 Nombre de la clasificación (típicamente para mostrarlo en las aplicaciones de navegación).
copaCodeAttr1 Nombre del atributo de los objetos bajo copaClassifBase (que definen los nodos del árbol) donde se especifica su código COPA, sin el prefijo. Típicamente será copaAreaCode si esos objetos son del tipo copaArea.
copaPrintAttr1 Nombre del atributo de los objetos bajo copaClassifBase (que definen los nodos del árbol) donde se especifica el nombre del Área o nodo. Típicamente será copaName si esos objetos son del tipo copaArea.
copaAreaObjectClassName1+ Clase/s de los objetos bajo copaClassifBase. Típicamente copaArea.
copaCodeResourceAttr1 Nombre del atributo que habrá en cada entrada del DIT y donde se indica su código COPA, con el prefijo. Típicamente será irisClassifCode (esquema Iris, clase irisObject) o copaCode (esquema COPA, clase copaResource).
copaRelatedAttr1 ???
description1+ Pues eso...

copaVirtualViewNav

Es una clase auxiliar que típicamente se incluye en la raíz del DIT y simplemente sirve para declarar los DNs de los objetos de tipo copaVirtualViewSpec. Así las aplicaciones de navegación pueden encontrarlos de forma automática.

copaDefVvNav? Contiene el DN del objeto copaClassifBase que contiene la vista por defecto.
copaVvNav0+ Contiene los DNs del resto de objetos copaClassifBase que contienen otras vistas.

copaArea

En la nomenclatura COPA, un Área es cada uno de los nodos de una jerarquía. Cada uno de estos debe definirse en un objeto dentro del DIT, que pertenecerá a esta clase. Todos estos objetos que definen una jerarquía irán en una rama específica.

copaAreaCode1 El código COPA de un área o nodo del árbol, sin prefijo.
copaName1 El nombre de un área o nodo del árbol.
description1+ Descripción
copaCode0+ Permite asignar al nodo códigos COPA de otras jerarquías.

copaResource

Pensado para incluirlo en cada entrada del DIT correspondiente a un item (personas, etc.) que puede pertenecer a una clasificación. En su lugar se puede usar la clase irisObject y su atributo irisClassifCode.

copaCode1+ El código COPA (URN con prefijo) que asociamos a cada entrada del DIT. Alternativa a irisClassifCode.

copaLinkageIdentifier

???
copaExternalCode0+ ???

Donde ? indica 0 ó 1 ocurrencia, 0+ indica 0 o n, 1+ uno o más y 1 exactamente una ocurrencia, obligatoria.

Ejemplo: relación de cada persona con la Universidad y organización de ésta

En este ejemplo vamos a incluir en el objeto LDAP que representa a cada persona información sobre su relación con la Universidad. El concepto de relación en este contexto no es muy preciso, pues dependiendo de para qué uso concreto se necesite en un momento dado esa información puede bastar con saber si es PAS, PDI o alumno o puede ser necesario una información más específica, como si es becario/a y de qué tipo.

En primer lugar vamos a desarrollar una clasificación COPA que simplemente refleja la pertenencia de la persona a uno de esos tres estamentos (pueden ser más de uno). Para este caso no es necesario COPA, existen atributos bien establecidos, como eduPersonAffiliation, que sirven perfectamente para eso.

Posteriormente ampliaremos el ejemplo para contemplar una estructura jerárquica de posibles relaciones con la Universidad. De esta forma con un simple atributo en la entrada de cada persona se podrá hacer búsquedas más o menos específicas (todos los PAS, dentro de estos los laborales, o los funcionarios interinos, etc.), algo difícil de conseguir sin COPA.

Fase 1

Puesto que ya se han explicado los conceptos y el esquema de COPA y para no ser farragosos, mostramos simplemente el fragmento de fichero LDIF que contiene toda la información necesaria. Se necesitan los esquemas Iris [3] (para los atributos idnc y irisClassifCode) y COPA [4]:

     1	#####################################################################
     2	### Raiz y ramas
     3	#####################################################################
     4	
     5	dn: dc=uco,dc=es
     6	objectClass: top
     7	objectClass: dcObject
     8	objectClass: organization
     9	objectClass: copaVirtualViewNav
    10	o: uco.es
    11	dc: uco
    12	copaDefVvNav: idnc=por_relacion,ou=copa,dc=uco,dc=es
    13	
    14	dn: ou=copa,dc=uco,dc=es
    15	objectClass: top
    16	objectClass: organizationalUnit
    17	ou: copa
    18	
    19	dn: ou=areas,ou=copa,dc=uco,dc=es
    20	objectClass: top
    21	objectClass: organizationalUnit
    22	ou: areas
    23	
    24	dn: ou=People,dc=uco,dc=es
    25	objectClass: top
    26	objectClass: organizationalUnit
    27	ou: People
    28	
    29	
    30	#####################################################################
    31	### Configuracion de la jerarquia
    32	#####################################################################
    33	
    34	dn: idnc=por_relacion,ou=copa,dc=uco,dc=es
    35	objectclass: copaVirtualViewSpec
    36	objectclass: irisObject
    37	idnc: por_relacion
    38	copaClassifBase: ou=por_relacion,ou=areas,ou=copa,dc=uco,dc=es
    39	copaPrefix: urn:mace:rediris.es:uco.es:classif:por_relacion:v1
    40	copaName: Por relacion
    41	copaCodeAttr: copaAreaCode
    42	copaPrintAttr: copaName
    43	copaAreaObjectClassName: copaArea
    44	copaCodeResourceAttr: irisClassifCode
    45	description: Tipo de relacion con la Universidad
    46	
    47	
    48	#####################################################################
    49	### Rama especifica para las areas de esta jerarquia
    50	#####################################################################
    51	
    52	dn: ou=por_relacion,ou=areas,ou=copa,dc=uco,dc=es
    53	objectClass: top
    54	objectClass: organizationalUnit
    55	ou: por_relacion
    56	
    57	
    58	#####################################################################
    59	### Un objeto para cada area/nodo
    60	#####################################################################
    61	
    62	dn: copaAreaCode=a1,ou=por_relacion,ou=areas,ou=copa,dc=uco,dc=es
    63	objectclass: copaArea
    64	copaAreaCode: a1
    65	copaName: PAS
    66	description: Personal de Administracion y Servicios
    67	
    68	dn: copaAreaCode=a2,ou=por_relacion,ou=areas,ou=copa,dc=uco,dc=es
    69	objectclass: copaArea
    70	copaAreaCode: a2
    71	copaName: PDI
    72	description: Personal Docente e Investigador
    73	
    74	dn: copaAreaCode=a3,ou=por_relacion,ou=areas,ou=copa,dc=uco,dc=es
    75	objectclass: copaArea
    76	copaAreaCode: a3
    77	copaName: Alumnos
    78	description: Alumnos, becarios, etc.
    79	
    80	
    81	#####################################################################
    82	### Lo mas importante: las personas...
    83	#####################################################################
    84	
    85	dn: uid=rgomez,ou=People,dc=uco,dc=es
    86	uid: rgomez
    87	cn: Rafael Gomez
    88	sn: Gomez
    89	objectClass: inetorgperson
    90	objectClass: irisObject
    91	objectClass: top
    92	irisClassifCode: urn:mace:rediris.es:uco.es:classif:por_relacion:v1:a1
    93	
    94	dn: uid=aperez,ou=People,dc=uco,dc=es
    95	uid: aperez
    96	cn: Antonia Perez
    97	sn: Perez
    98	objectClass: inetorgperson
    99	objectClass: irisObject
   100	objectClass: top
   101	irisClassifCode: urn:mace:rediris.es:uco.es:classif:por_relacion:v1:a1
   102	irisClassifCode: urn:mace:rediris.es:uco.es:classif:por_relacion:v1:a2

En este caso concreto hemos creado un subárbol específico (ou=copa) para toda la información relativa a COPA (con la obvia excepción de los atributos que hay que incluir en la entrada de cada usuario mediante irisClassifCode y el atributo copaDefVvNav de la raíz).

Bajo esa rama creamos un objeto para la configuración de cada clasificación o vista (en este caso en la línea 34) y un subárbol (ou=areas) bajo el cual se crea otro para los objetos que definen los nodos de las clasificaciones (en este caso ver la línea 52 y siguientes). Esta es una posible organización, se puede optar por cualquier otra.

En la línea 12 vemos la vista por defecto, si hubiera otras se declararían mediante el atributo copaVvNav. Esto no es realmente necesario, pero sí muy conveniente para que el software de navegación por vistas pueda localizar automáticamente la información que necesita.

Vemos también que hay una persona que pertenece a PAS y PDI, por lo que en el caso de una navegación por vistas aparecerá en dos puntos distintos del árbol. Si tuviéramos definida otra vista (por cargos, por servicios, etc.) no habría conflicto al añadir más atributos irisClassifCode porque el prefijo de su valor sirve para distinguir entre ellas.

Localizar a todo el PAS es tan sencillo como:

ldapsearch -x -b "dc=uco,dc=es" "(irisClassifCode=*por_relacion*:a1)"
Para buscar los que pertenecen tanto al PAS como al PDI:

(&(irisClassifCode=*por_relacion*:a1)(irisClassifCode=*por_relacion*:a2))
Por supuesto se podría usar un atributo distinto para cada vista, simplificando un poco el filtro de búsqueda, pero no creo que merezca la pena pues complica el esquema.

Fase 2

Ahora vamos a establecer una jerarquía de relaciones con la Universidad e introducir otra vista, basada en la organización (en ambos casos muy sencillas al tratarse sólo de ejemplos).
     1	
     2	##########################################################################
     3	### Las ramas basicas
     4	##########################################################################
     5	
     6	dn: dc=uco,dc=es
     7	objectClass: top
     8	objectClass: dcObject
     9	objectClass: organization
    10	objectClass: copaVirtualViewNav
    11	o: uco.es
    12	dc: uco
    13	copaDefVvNav: idnc=por_relacion,ou=copa,dc=uco,dc=es
    14	copaVvNav: idnc=por_organizacion,ou=copa,dc=uco,dc=es
    15	
    16	dn: ou=copa,dc=uco,dc=es
    17	objectClass: top
    18	objectClass: organizationalUnit
    19	ou: copa
    20	
    21	dn: ou=People,dc=uco,dc=es
    22	objectClass: top
    23	objectClass: organizationalUnit
    24	ou: People
    25	
    26	dn: ou=areas,ou=copa,dc=uco,dc=es
    27	objectClass: top
    28	objectClass: organizationalUnit
    29	ou: areas
    30	
    31	
    32	##########################################################################
    33	### Los objetos que definen las vistas
    34	##########################################################################
    35	
    36	dn: idnc=por_relacion,ou=copa,dc=uco,dc=es
    37	objectclass: copaVirtualViewSpec
    38	objectclass: irisObject
    39	idnc: por_relacion
    40	copaClassifBase: ou=por_relacion,ou=areas,ou=copa,dc=uco,dc=es
    41	copaPrefix: urn:mace:rediris.es:uco.es:virtualview:por_relacion:v1
    42	copaName: Por relacion
    43	copaCodeAttr: copaAreaCode
    44	copaPrintAttr: copaName
    45	copaAreaObjectClassName: copaArea
    46	copaCodeResourceAttr: irisClassifCode
    47	description: Tipo de relacion con la Universidad
    48	
    49	dn: idnc=por_organizacion,ou=copa,dc=uco,dc=es
    50	objectclass: copaVirtualViewSpec
    51	objectclass: irisObject
    52	idnc: por_organizacion
    53	copaClassifBase: ou=por_organizacion,ou=areas,ou=copa,dc=uco,dc=es
    54	copaPrefix: urn:mace:rediris.es:uco.es:virtualview:por_organizacion:v1
    55	copaName: Por organizacion
    56	copaCodeAttr: copaAreaCode
    57	copaPrintAttr: copaName
    58	copaAreaObjectClassName: copaArea
    59	copaCodeResourceAttr: irisClassifCode
    60	description: Organizacion dentro de la Universidad
    61	
    62	
    63	##########################################################################
    64	### La rama que define la vista por relacion con la Univ.
    65	##########################################################################
    66	
    67	dn: ou=por_relacion,ou=areas,ou=copa,dc=uco,dc=es
    68	objectClass: top
    69	objectClass: organizationalUnit
    70	ou: por_relacion
    71	
    72	dn: copaAreaCode=a1,ou=por_relacion,ou=areas,ou=copa,dc=uco,dc=es
    73	objectclass: copaArea
    74	copaAreaCode: a1
    75	copaName: PAS
    76	description: Personal de Administracion y Servicios
    77	
    78	dn: copaAreaCode=a1b1,ou=por_relacion,ou=areas,ou=copa,dc=uco,dc=es
    79	objectclass: copaArea
    80	copaAreaCode: a1b1
    81	copaName: Laboral
    82	description: Personal laboral
    83	
    84	dn: copaAreaCode=a1b2,ou=por_relacion,ou=areas,ou=copa,dc=uco,dc=es
    85	objectclass: copaArea
    86	copaAreaCode: a1b2
    87	copaName: Funcionario
    88	description: Personal funcionario
    89	
    90	dn: copaAreaCode=a1b2c1,ou=por_relacion,ou=areas,ou=copa,dc=uco,dc=es
    91	objectclass: copaArea
    92	copaAreaCode: a1b2c1
    93	copaName: Funcionario fijo
    94	description: Personal funcionario fijo
    95	
    96	# ...
    97	
    98	##########################################################################
    99	### La rama que define la vista por organizacion
   100	##########################################################################
   101	
   102	dn: ou=por_organizacion,ou=areas,ou=copa,dc=uco,dc=es
   103	objectClass: top
   104	objectClass: organizationalUnit
   105	ou: por_organizacion
   106	
   107	dn: copaAreaCode=a1,ou=por_organizacion,ou=areas,ou=copa,dc=uco,dc=es
   108	objectclass: copaArea
   109	copaAreaCode: a1
   110	copaName: Servicios
   111	description: Servicios universitarios
   112	
   113	dn: copaAreaCode=a1b1,ou=por_organizacion,ou=areas,ou=copa,dc=uco,dc=es
   114	objectclass: copaArea
   115	copaAreaCode: a1b1
   116	copaName: Informatica
   117	description: Servicio de Informatica
   118	
   119	dn: copaAreaCode=a1b2,ou=por_organizacion,ou=areas,ou=copa,dc=uco,dc=es
   120	objectclass: copaArea
   121	copaAreaCode: a1b2
   122	copaName: Personal
   123	description: Servicio de Personal
   124	
   125	# ...
   126	
   127	##########################################################################
   128	### Las personas...
   129	##########################################################################
   130	
   131	dn: uid=rgomez,ou=People,dc=uco,dc=es
   132	uid: rgomez
   133	cn: Rafael Gomez
   134	sn: Gomez
   135	objectClass: inetorgperson
   136	objectClass: irisObject
   137	objectClass: top
   138	irisClassifCode: urn:mace:rediris.es:uco.es:virtualview:por_relacion:v1:a1b2c2
   139	irisClassifCode: urn:mace:rediris.es:uco.es:virtualview:por_organizacion:v1:a1b1
   140	
   141	dn: uid=aperez,ou=People,dc=uco,dc=es
   142	uid: aperez
   143	cn: Antonia Perez
   144	sn: Perez
   145	objectClass: inetorgperson
   146	objectClass: irisObject
   147	objectClass: top
   148	irisClassifCode: urn:mace:rediris.es:uco.es:virtualview:por_relacion:v1:a1b2c1
   149	irisClassifCode: urn:mace:rediris.es:uco.es:virtualview:por_relacion:v1:a2b3
   150	irisClassifCode: urn:mace:rediris.es:uco.es:virtualview:por_organizacion:v1:a1b1
   151	irisClassifCode: urn:mace:rediris.es:uco.es:virtualview:por_organizacion:v1:a2b2
No incluimos el fichero completo por brevedad, pero se puede descargar aquí....... Las clasificaciones usadas son las siguientes:

Por relación:

a1 Personal de Administracion y Servicios
a1b1 Personal laboral
a1b2 Personal funcionario
a1b2c1 Personal funcionario fijo
a1b2c2 Personal funcionario interino

a2 Personal Docente e Investigador
a2b1 Catedratico
a2b2 Titular de Universidad
a2b3 Ayudante

a3 Alumnos, becarios, etc.
a3b1 Estudiante de ensenanzas regladas
a3b2 Estudiante de ensenanzas no regladas
a3b3 Becario
a3b3c1 Becario FPI
a3b3c2 Becario Erasmus

Por organización:

a1 Servicios universitarios
a1b1 Servicio de Informatica
a1b2 Servicio de Personal
a1b3 Servicio de Deportes

a2 Departamentos universitarios
a2b1 Departamento de Filosofia
a2b2 Departamento de Informatica

Saber si una persona es PAS, PDI o alumno se reduce a buscar en su entrada usando el filtro "(irisClassifCode=*por_relacion*)", obtener la parte tras el último ':' y de ahí la parte antes de la primera 'b'. Puede parecer farragoso, pero no cuesta mucho hacer unas pequeñas funciones para realizar esas tareas y usarlas en todas las aplicaciones.

Se puede obtener igualmente el nombre del colectivo al que pertenece una persona obteniendo su irisClassifCode, elimimando el prefijo y buscando lo que queda en copaAreaCode bajo ou=por_relacion,ou=areas,ou=copa,dc=uco,dc=es, por ejemplo. Igualmente se puede obtener el nombre de sus supercolectivos parseando fácilmente su código y separándolo en sus componentes.

Localizar los distintos tipos de alumnos, becarios, etc:

ldapsearch -x -b "ou=por_relacion,ou=areas,ou=copa,dc=uco,dc=es" '(&(copaAreaCode=*a3b*)(!(copaAreaCode=*a3b*c*)))'
Como ejemplo final, podemos localizar a un profesor de apellido Ventura del Dpto. de Informática:
ldapsearch -x -b "dc=uco,dc=es" '(&(cn=*ventura*)(irisClassifCode=*por_organizacion*a2b2))'

Referencias

[1] - http://www.rediris.es/ldap/copa
[2] - http://www.rediris.es
[3] - http://www.rediris.es/ldap/esquemas/iris.schema
[4] - http://www.rediris.es/ldap/schema/copa.schema
[5] - http://www.rediris.es/ldap/copa/clasif/copaUniv.txt
[6] - http://www.rediris.es/ldap/copa/clasif/
[7] - https://forja.rediris.es/projects/siledap/