Apache Subversion - Apache Subversion

Apache Subversion
Apache Subversion logo.svg
Autor (es) original (es) CollabNet
Desarrollador (es) Fundación de software Apache
Versión inicial 20 de octubre de 2000 ; hace 20 años ( 20/10/2000 )
Liberaciones estables [±]
1.10.x 1.10.7 / 10 de febrero de 2021 ; hace 8 meses ( 10/02/2021 )
1.14.x 1.14.1 / 10 de febrero de 2021 ; hace 8 meses ( 10/02/2021 )
Vista previa de la (s) versión (es) [±]
Repositorio
Escrito en C
Sistema operativo Centos , Debian , Fedora , FreeBSD , HP-UX , NetBSD , OpenBSD , openSUSE , OpenVMS , macOS , Red Hat Linux , Solaris , SUSE Linux , Ubuntu , Windows
Escribe Control de revisión
Licencia Apache-2.0
Sitio web subversion .apache .org Edita esto en Wikidata

Apache Subversion (a menudo abreviado SVN , después de su nombre de comando svn ) es un sistema de control de versiones y control de versiones de software distribuido como código abierto bajo la Licencia Apache . Los desarrolladores de software usan Subversion para mantener versiones actuales e históricas de archivos como código fuente , páginas web y documentación. Su objetivo es ser un sucesor en su mayoría compatible con el Sistema de Versiones Concurrentes (CVS) ampliamente utilizado .

La comunidad de código abierto ha utilizado Subversion ampliamente: por ejemplo, en proyectos como Apache Software Foundation , Free Pascal , FreeBSD , SourceForge y de 2006 a 2019, GCC . CodePlex era anteriormente un host común para los repositorios de Subversion.

Subversion fue creado por CollabNet Inc. en 2000, y ahora es un proyecto Apache de alto nivel que está siendo construido y utilizado por una comunidad global de contribuyentes.

Historia

CollabNet fundó el proyecto Subversion en 2000 como un esfuerzo por escribir un sistema de control de versiones de código abierto que funcionara de manera muy similar a CVS, pero que solucionó los errores y proporcionó algunas características que faltaban en CVS. Para 2001, Subversion había avanzado lo suficiente para albergar su propio código fuente , y en febrero de 2004, se lanzó la versión 1.0. En noviembre de 2009, Subversion fue aceptado en Apache Incubator : esto marcó el comienzo del proceso para convertirse en un proyecto Apache estándar de alto nivel. Se convirtió en un proyecto Apache de nivel superior el 17 de febrero de 2010.

Versión Fecha de lanzamiento original Ultima versión Fecha de lanzamiento Estado
Versión antigua, ya no se mantiene: 1.0 2004-02-23 1.0.9 2004-10-13 Ya no es compatible
Versión antigua, ya no se mantiene: 1.1 2004-09-29 1.1.4 2005-04-01 Ya no es compatible
Versión antigua, ya no se mantiene: 1.2 2005-05-21 1.2.3 2005-08-19 Ya no es compatible
Versión antigua, ya no se mantiene: 1.3 2005-12-30 1.3.2 2006-05-23 Ya no es compatible
Versión antigua, ya no se mantiene: 1.4 2006-09-10 1.4.6 2007-12-21 Ya no es compatible
Versión antigua, ya no se mantiene: 1,5 2008-06-19 1.5.9 2010-12-06 Ya no es compatible
Versión antigua, ya no se mantiene: 1,6 2009-03-20 1.6.23 2013-05-30 Ya no es compatible
Versión antigua, ya no se mantiene: 1,7 2011-10-11 1.7.22 2015-08-12 Ya no es compatible
Versión antigua, ya no se mantiene: 1.8 2013-06-18 1.8.19 2017-08-10 Ya no es compatible
Versión antigua, ya no se mantiene: 1,9 2015-08-05 1.9.12 2019-07-24 Ya no es compatible
Versión anterior, pero aún se mantiene: 1,10 2018-04-13 1.10.7 2021-02-10 Parcialmente compatible, LTS
Versión antigua, ya no se mantiene: 1,11 2018-10-30 1.11.1 2019-01-11 Ya no es compatible
Versión antigua, ya no se mantiene: 1.12 2019-04-24 1.12.2 2019-07-24 Ya no es compatible
Versión antigua, ya no se mantiene: 1,13 2019-10-30 1.13.0 2019-10-30 Ya no es compatible
Versión estable actual: 1,14 27-05-2020 1.14.1 2021-02-10 Totalmente compatible, LTS
Leyenda:
Versión antigua
Versión anterior, aún mantenida
Ultima versión
Última versión de vista previa
Lanzamiento futuro

Las fechas de lanzamiento se extraen del CHANGESarchivo de Apache Subversion , que registra todo el historial de lanzamientos.

Características

  • Confirma como operaciones atómicas verdaderas ( las operaciones de confirmación interrumpidas en CVS causarían inconsistencia o corrupción del repositorio).
  • Los archivos renombrados / copiados / movidos / eliminados conservan el historial de revisión completo.
  • El sistema mantiene el control de versiones para directorios, cambios de nombre y metadatos de archivos (pero no para marcas de tiempo). Los usuarios pueden mover y / o copiar árboles de directorios completos muy rápidamente, mientras conservan el historial de revisión completo.
  • Versionado de enlaces simbólicos .
  • Soporte nativo para archivos binarios, con almacenamiento de diferencias binarias con uso eficiente del espacio.
  • Apache HTTP Server como servidor de red, WebDAV / Delta-V para protocolo . También hay un proceso de servidor independiente llamado svnserve que usa un protocolo personalizado sobre TCP / IP .
  • La bifurcación es una operación barata, independiente del tamaño del archivo (aunque Subversion en sí no distingue entre una bifurcación y un directorio).
  • De forma nativa cliente-servidor , en capas biblioteca de diseño.
  • El protocolo cliente / servidor envía diferencias en ambas direcciones.
  • Costos proporcionales al tamaño del cambio, no al tamaño de los datos.
  • Salida analizable , incluida la salida de registro XML .
  • Licencia de código abierto - Licencia Apache desde la versión 1.7; las versiones anteriores utilizan un derivado de la licencia de software Apache 1.1.
  • Mensajes de programas internacionalizados .
  • Bloqueo de archivos para archivos no fusionables ("pagos reservados").
  • Autorización basada en ruta.
  • Enlaces de lenguaje para C # , PHP , Python , Perl , Ruby y Java .
  • Compatibilidad total con MIME : los usuarios pueden ver o cambiar el tipo de MIME de cada archivo, y el software sabe qué tipos de MIME pueden mostrar sus diferencias con las versiones anteriores.
  • Seguimiento de fusiones: se realizará un seguimiento de las fusiones entre ramas, lo que permite la fusión automática entre ramas sin decirle a Subversion qué es necesario y qué no debe fusionarse.
  • Listas de cambios para organizar las confirmaciones en grupos de confirmaciones.

Tipos de repositorio

Subversion ofrece dos tipos de almacenamiento de repositorio.

Berkeley DB (obsoleto)

El desarrollo original de Subversion utilizó el paquete Berkeley DB . Subversion tiene algunas limitaciones con el uso de Berkeley DB cuando un programa que accede a la base de datos falla o se cierra por la fuerza. No se produce pérdida ni corrupción de datos, pero el repositorio permanece fuera de línea mientras Berkeley DB reproduce el diario y limpia los bloqueos pendientes. La forma más segura de usar Subversion con un repositorio de Berkeley DB implica un único proceso de servidor que se ejecuta como un usuario (en lugar de a través de un sistema de archivos compartido). El backend de Berkeley DB quedó obsoleto en la versión 1.8.

FSFS

En 2004, se desarrolló un nuevo subsistema de almacenamiento y se denominó FSFS. Funciona más rápido que el backend de Berkeley DB en directorios con una gran cantidad de archivos y ocupa menos espacio en disco, debido a un menor registro.

A partir de Subversion 1.2, FSFS se convirtió en el almacén de datos predeterminado para nuevos repositorios.

La etimología de "FSFS" se basa en el uso que hace Subversion del término "sistema de archivos" para su sistema de almacenamiento de repositorio. FSFS almacena su contenido directamente dentro del sistema de archivos del sistema operativo, en lugar de un sistema estructurado como Berkeley DB. Por lo tanto, es un "sistema de archivos [Subversion] encima del sistema de archivos".

FSX

Se está desarrollando un nuevo sistema de archivos, llamado FSX, para eliminar algunas limitaciones de FSFS. A partir de la Versión 1.9, no se consideró listo para producción.

Acceso al repositorio

El acceso a los repositorios de Subversion puede realizarse mediante:

  1. Sistema de archivos local o sistema de archivos de red, al que el cliente accede directamente. Este modo utiliza el esquema de acceso a la ruta file: /// .
  2. WebDAV / Delta-V (a través de http o https) usando el módulo mod_dav_svn para Apache 2 . Este modo usa el esquema de acceso http: // host / ruta o https: // host / ruta para conexiones seguras usando ssl.
  3. Protocolo personalizado "svn" ( puerto predeterminado 3690), usando texto plano o sobre TCP / IP . Este modo utiliza el esquema de acceso svn: // host / ruta para el transporte no cifrado o el esquema svn + ssh: // host / ruta para hacer un túnel sobre ssh.

Los tres medios pueden acceder a los repositorios FSFS y Berkeley DB.

Cualquier versión 1.x de un cliente puede funcionar con cualquier servidor 1.x. Los clientes y servidores más nuevos tienen características y capacidades de rendimiento adicionales, pero tienen soporte de respaldo para clientes / servidores más antiguos.

Capas

Internamente, un sistema Subversion comprende varias bibliotecas organizadas como capas. Cada uno realiza una tarea específica y permite a los desarrolladores crear sus propias herramientas en el nivel deseado de complejidad y especificidad.

Fs
El nivel más bajo; implementa el sistema de archivos versionado que almacena los datos del usuario.
Reposiciones
Preocupado por el repositorio creado alrededor del sistema de archivos. Tiene muchas funciones auxiliares y maneja los diversos "ganchos" que puede tener un repositorio, por ejemplo, scripts que se ejecutan cuando se realiza una acción. Juntos, Fs y Repos constituyen la "interfaz del sistema de archivos".
mod_dav_svn
Proporciona acceso WebDAV / Delta-V a través de Apache 2.
Real academia de bellas artes
Maneja el "acceso al repositorio", tanto local como remoto. A partir de este momento, se hace referencia a los repositorios mediante URL, p. Ej.
  • file: /// ruta / para acceso local,
  • http: // host / ruta / o https: // host / ruta / para acceso a WebDAV, o
  • svn: // host / ruta / o svn + ssh: // host / ruta / para el protocolo SVN.
Cliente, Wc
El nivel más alto. Abstrae el acceso al repositorio y proporciona tareas de cliente comunes, como autenticar usuarios o comparar versiones. Los clientes de Subversion usan la biblioteca Wc para administrar la copia de trabajo local.

Sistema de archivos

Svn 3D-tree.svg

Uno puede ver el sistema de archivos de Subversion como "bidimensional". Se utilizan dos coordenadas para abordar de forma inequívoca los elementos del sistema de archivos:

Cada revisión en un sistema de archivos de Subversion tiene su propia raíz , que se utiliza para acceder al contenido de esa revisión. Los archivos se almacenan como enlaces al cambio más reciente; por tanto, un repositorio de Subversion es bastante compacto. El sistema consume espacio de almacenamiento proporcional al número de cambios realizados, no al número de revisiones.

El sistema de archivos de Subversion usa transacciones para mantener los cambios atómicos . Una transacción opera en una revisión específica del sistema de archivos, no necesariamente la última. La transacción tiene su propia raíz , en la que se realizan cambios. A continuación, se confirma y se convierte en la última revisión, o se cancela. La transacción es en realidad un objeto de sistema de archivos de larga duración; un cliente no necesita confirmar o abortar una transacción por sí mismo, sino que también puede comenzar una transacción, salir y luego volver a abrir la transacción y continuar usándola. Potencialmente, varios clientes pueden acceder a la misma transacción y trabajar juntos en un cambio atómico, aunque ningún cliente existente expone esta capacidad.

Propiedades

Una característica importante del sistema de archivos de Subversion son las propiedades: pares de texto simple nombre = valor . La mayoría de las propiedades se encuentran en las entradas del sistema de archivos (es decir, archivos y directorios). Estos están versionados al igual que otros cambios en el sistema de archivos. El cliente de Subversion reserva el prefijo 'svn:' para las propiedades integradas, pero se pueden usar otros nombres para definir propiedades personalizadas.

svn: ejecutable
Hace que un archivo en copias de trabajo alojadas en Unix sea ​​ejecutable, cuando es compatible con el sistema de archivos.
svn: tipo-mimo
Almacena el tipo de medio de Internet ("tipo MIME") de un archivo. Afecta el manejo de diferencias y fusiones.
svn: ignorar
Una lista de patrones de nombre de archivo para ignorar en un directorio. De manera similar a CVS 's de .cvsignorearchivo.
svn: palabras clave
Una lista de palabras clave para sustituir en un archivo cuando se realizan cambios. El archivo en sí también debe hacer referencia a las palabras clave como $ palabra clave $ o $ palabra clave: ... $ . Se utiliza para mantener cierta información (por ejemplo, autor, fecha del último cambio, número de revisión) en un archivo sin intervención humana.
El mecanismo de sustitución de palabras clave se origina en RCS y CVS.
svn: estilo eol
Hace que el cliente convierta caracteres de final de línea en archivos de texto. Se utiliza cuando se necesita la copia de trabajo con un estilo EOL específico. "nativo" se usa comúnmente, de modo que las EOL coincidan con el estilo de EOL del sistema operativo del usuario. Los repositorios pueden requerir esta propiedad en todos los archivos para evitar finales de línea inconsistentes, lo que puede causar un problema en sí mismo.
svn: externos
Permite que partes de otros repositorios se desprotejan automáticamente en un subdirectorio.
svn: necesita-bloqueo
Especifica que se debe extraer un archivo con los permisos de archivo configurados como de solo lectura. Está diseñado para usarse con el mecanismo de bloqueo. El permiso de solo lectura recuerda que debe obtener un bloqueo antes de modificar el archivo: obtener un bloqueo hace que el archivo se pueda escribir, y liberar el bloqueo lo vuelve de solo lectura. Los bloqueos solo se aplican durante una operación de confirmación. Los bloqueos se pueden utilizar sin establecer esta propiedad. Sin embargo, eso no se recomienda, porque presenta el riesgo de que alguien modifique un archivo bloqueado; solo descubrirán que se ha bloqueado cuando su confirmación falle.
svn: especial
Esta propiedad no debe ser configurada o modificada directamente por los usuarios. A partir de 2010 solo se utiliza para tener enlaces simbólicos en el repositorio. Cuando se agrega un enlace simbólico al repositorio, se crea un archivo que contiene el destino del enlace con este conjunto de propiedades. Cuando un sistema similar a Unix comprueba este archivo, el cliente lo convierte en un enlace simbólico.
svn: mergeinfo
Se utiliza para realizar un seguimiento de los datos de combinación (números de revisión) en Subversion 1.5 (o posterior). Esta propiedad se mantiene automáticamente mediante el comando merge y no se recomienda cambiar su valor manualmente.

Subversion también usa propiedades en las propias revisiones. Al igual que las propiedades anteriores en las entradas del sistema de archivos, los nombres son completamente arbitrarios, y el cliente de Subversion usa ciertas propiedades con el prefijo 'svn:'. Sin embargo, estas propiedades no están versionadas y se pueden cambiar más adelante si lo permite un gancho de cambio previo a revprop.

svn: fecha
La marca de fecha y hora de una revisión.
svn: autor
El nombre del usuario que envió los cambios.
svn: registro
La descripción proporcionada por el usuario de los cambios.

Ramificación y etiquetado

Subversion usa el modelo de bifurcación entre archivos de Perforce para implementar bifurcaciones y etiquetado . Una rama es una línea de desarrollo separada. El etiquetado se refiere a etiquetar el repositorio en un momento determinado para que se pueda encontrar fácilmente en el futuro. En Subversion, la única diferencia entre las ramas y las etiquetas es cómo se usan.

Se configura una nueva rama o etiqueta mediante el comando " svn copy ", que debe usarse en lugar del mecanismo del sistema operativo nativo. El directorio copiado está vinculado al original en el repositorio para preservar su historial, y la copia ocupa muy poco espacio adicional en el repositorio.

Todas las versiones de cada rama mantienen el historial del archivo hasta el momento de la copia, además de los cambios realizados desde entonces. Se pueden "fusionar" los cambios en el tronco o entre las ramas.

texto alternativo
Visualización de un proyecto de Subversion simple

Limitaciones y problemas

Un problema conocido en Subversion afecta la implementación de la operación de cambio de nombre de archivos y directorios. A partir de 2014, Subversion implementa el cambio de nombre de archivos y directorios como una "copia" al nuevo nombre seguido de una "eliminación" del nombre anterior. Solo cambian los nombres, todos los datos relacionados con el historial de ediciones siguen siendo los mismos y Subversion seguirá usando el nombre antiguo en las revisiones anteriores del "árbol". Sin embargo, Subversion puede confundirse cuando un movimiento entra en conflicto con ediciones realizadas en otro lugar, tanto para confirmaciones regulares como cuando se fusionan ramas. La versión 1.5 de Subversion abordó algunos de estos escenarios, mientras que otros siguieron siendo problemáticos. La versión 1.8 de Subversion solucionó algunos de estos problemas haciendo que los movimientos sean una operación de primera clase en el cliente, pero aún se tratan como copiar + eliminar en el repositorio.

A partir de 2013, Subversion carece de algunas funciones de administración y gestión de repositorios. Por ejemplo, alguien puede querer editar el repositorio para eliminar permanentemente todos los registros históricos de ciertos datos. Subversion no tiene soporte incorporado para lograr esto simplemente.

Subversion almacena copias adicionales de datos en la máquina local, lo que puede convertirse en un problema con proyectos o archivos muy grandes, o si los desarrolladores trabajan en múltiples ramas simultáneamente. En las versiones anteriores a la 1.7, estos .svndirectorios del lado del cliente podían corromperse por una actividad del usuario desacertada, como las operaciones globales de búsqueda / reemplazo. A partir de la versión 1.7, Subversion usa una única carpeta .svn centralizada por área de trabajo.

Subversion no almacena las horas de modificación de los archivos. Como tal, un archivo extraído de un repositorio de Subversion tendrá la fecha 'actual' (en lugar de la hora de modificación en el repositorio), y un archivo registrado en el repositorio tendrá la fecha del registro (en lugar de la modificación hora en que se registró el archivo). Puede que esto no sea siempre lo que se desea. Para mitigar esto, existen herramientas de terceros que permiten preservar el tiempo de modificación y otros metadatos del sistema de archivos. Sin embargo, también es importante dar a los archivos extraídos una fecha actual; así es como herramientas como make (1) notarán un archivo cambiado para reconstruirlo.

Subversion usa un modelo de control de revisiones centralizado . Ben Collins-Sussman , uno de los diseñadores de Subversion, cree que un modelo centralizado ayudaría a evitar que los "programadores inseguros" oculten su trabajo a otros miembros del equipo. Algunos usuarios de sistemas de control de versiones ven el modelo centralizado como perjudicial; Es famoso que Linus Torvalds atacó el modelo de Subversion y sus desarrolladores.

Subversion a menudo no se ocupa bien de la normalización del nombre de archivo realizada por el sistema de archivos HFS + . Esto puede causar problemas cuando los archivos con caracteres acentuados en sus nombres se agregan al repositorio en un sistema de archivos que no es HFS + y luego el repositorio se usa con HFS +.

Etiquetas y ramas de subversión

Los números de revisión son difíciles de recordar en cualquier sistema de control de versiones. Por esta razón, la mayoría de los sistemas ofrecen etiquetas simbólicas como referencias fáciles de usar. Subversion no tiene tal característica y lo que su documentación recomienda usar en su lugar es de naturaleza muy diferente. En lugar de implementar etiquetas como referencias a puntos en el historial, Subversion recomienda hacer copias instantáneas en un subdirectorio conocido (" tags/") en el espacio del árbol del repositorio. Sólo unos pocos predefinidos referencias están disponibles: HEAD, BASE, PREVy COMMITTED.

Esta proyección de la historia al espacio tiene varios problemas:

  1. Cuando se toma una instantánea, el sistema no asigna ningún significado especial al nombre de la etiqueta / instantánea. Ésta es la diferencia entre una copia y una referencia . La revisión se registra y se puede acceder a la instantánea por URL. Esto hace que algunas operaciones sean menos convenientes y otras imposibles. Por ejemplo, un ingenuo svn diff -r tag1:tag2 myfileno funciona; Es un poco más complicado que el de lograr, lo que requiere que el usuario conozca y la URL de entrada / rutas de acceso a las instantáneas en lugar de sólo los nombres de: svn diff <URL-TO-TAG1>/myfile <URL-TO-TAG2>/myfile. Otras operaciones como, por ejemplo, svn log -r tag1:tag2 myfileson simplemente imposibles.
  2. Cuando dos tipos de objetos (idealmente independientes) viven en el árbol del repositorio, puede producirse una "lucha por la cima". En otras palabras, a menudo es difícil decidir en qué nivel crear el tags/subdirectorio:
    trunk/
         /componentfoo/
         /componentbar/
    tags/
        /1.1/
            /componentfoo/
            /componentbar/
    
     o 
    componentfoo/
                /trunk/
                /tags/
                     /1.1/
    componentbar/
                /trunk/
                /tags/
                     /1.1/
    
  3. Las etiquetas, según su definición convencional, son de solo lectura y ligeras, tanto en el repositorio como en el cliente. Las copias de Subversion no son de solo lectura y, si bien son livianas en el repositorio, son increíblemente pesadas para el cliente.

Para abordar estos problemas, los carteles en las listas de correo de Subversion han sugerido una nueva característica llamada "etiquetas" o "alias". Las etiquetas SVN se parecerían más a las "etiquetas" de otros sistemas como CVS o Git . El hecho de que Subversion tenga números de revisión globales abre el camino a una implementación etiqueta → revisión muy simple. Sin embargo, a partir de 2013, no se ha realizado ningún progreso y las etiquetas simbólicas no están en la lista de las características más buscadas.

Desarrollo e implementación

CollabNet ha continuado su participación con Subversion, pero el proyecto se ejecuta como una comunidad de código abierto independiente. En noviembre de 2009, el proyecto fue aceptado en Apache Incubator , con el objetivo de formar parte de los esfuerzos de Apache Software Foundation . Desde marzo de 2010, el proyecto se conoce formalmente como Apache Subversion, y forma parte de los proyectos de nivel superior de Apache.

En octubre de 2009, WANdisco anunció la contratación de los principales responsables de Subversion a medida que la empresa se movía para convertirse en uno de los principales patrocinadores corporativos del proyecto. Esto incluyó a Hyrum Wright, presidente de Subversion Corporation y gerente de lanzamiento del proyecto Subversion desde principios de 2008, quien se unió a la compañía para liderar su equipo de código abierto.

La comunidad de código abierto de Subversion no proporciona binarios, pero los usuarios potenciales pueden descargarlos de voluntarios. Si bien el proyecto Subversion no incluye una interfaz gráfica de usuario (GUI) oficial para usar con Subversion, terceros han desarrollado una serie de GUI diferentes, junto con una amplia variedad de software auxiliar adicional.

El trabajo anunciado en 2009 incluyó SubversionJ (una API de Java ) y la implementación del comando Obliterate, similar al proporcionado por Perforce . Ambas mejoras fueron patrocinadas por WANdisco.

Los confirmadores de Subversion normalmente tienen al menos una o dos características nuevas en desarrollo activo al mismo tiempo. La versión 1.7 de Subversion en octubre de 2011 incluyó un transporte HTTP optimizado para mejorar el rendimiento y una biblioteca de copia de trabajo reescrita.

En 2002, se llevó a cabo un concurso de diseño para seleccionar el logotipo de Subversion. Las entradas originales se pueden encontrar aquí , así como los votos para cada logotipo. El logo actual recibió la mayor cantidad de votos en el concurso.

Ver también

Notas

Referencias

Notas al pie

Fuentes

  • C. Michael Pilato, Ben Collins-Sussman, Brian W. Fitzpatrick; Control de versiones con Subversion ; O'Reilly; ISBN  0-596-00448-6 (1.a edición, tapa blanda, 2004, libro completo en línea , espejo )
  • Garrett Rooney; Subversión práctica ; Presione; ISBN  1-59059-290-5 (1.ª edición, tapa blanda, 2005)
  • Mike Mason; Control de versiones pragmático con Subversion ; Estantería pragmática; ISBN  0-9745140-6-3 (1.a edición, tapa blanda , 2005)
  • William Nagel; Control de versiones de Subversion: uso del sistema de control de versiones de Subversion en proyectos de desarrollo ; Prentice Hall; ISBN  0-13-185518-2 (1.a edición, tapa blanda , 2005)

Otras lecturas

enlaces externos