;; Model: http://quadium.net/random/resume.html
(unless (find-package :html)
(asdf:operate 'asdf:load-op :com.informatimago.common-lisp)
(use-package :com.informatimago.common-lisp.utility))
(defparameter pascal-bourguignon
(quote
(:resume
(:person
(:name "Pascal BOURGUIGNON")
(:nationality (:text (:en "(French)") (:fr "(Français)") (:es "(Frances)")))
(:birth-date 2005 3 15)
(:birth-place "Hayange, France")
(:address "Apartado de correo 69 "
"30380 La Manga del Mar Menor "
"España")
(:mail "pjb@informatimago.com")
(:web "www.informatimago.com")
(:phone "+34 968 140 492"))
(:summary
(:text (:en "Common Lisp Application Development "
"& Web application development (UncommonWeb).")
(:fr "Développement d'applications en Common Lisp "
"& applications Web (UncommonWeb).")
(:es "Desarrollo de aplicaciones Common Lisp "
"y aplicaciones Web (UncommonWeb)."))
(:text (:en "OpenStep (MacOSX or GNUstep) & WebObject (GNUstepWeb) "
"Application Development")
(:fr "Développement d'applications OpenStep (MacOSX ou GNUstep) "
"& WebObject (GNUstepWeb)")
(:es "Desarrollo de aplicaciones OpenStep (MacOSX o GNUstep) "
"y WebObject (GNUstepWeb)."))
(:text (:en "UNIX System & Application Development.")
(:fr "Développement d'applications & développement système UNIX.")
(:es "Desarrollo de aplicaciones y sistema UNIX."))
(:text (:en "Internet UNIX Server Administration.")
(:fr "Administration de serveurs Internet UNIX.")
(:es "Administración de servidores Internet UNIX.")))
(:skills
(:category
(:text (:en "Compilers; "
"Operating Systems; "
"Object-Oriented Development.")
(:fr "Compilateurs; "
"Systèmes d'exploitation; "
"Développement orienté-objet.")
(:es "Desarrollo de compiladores; "
"Desarrollo Orientado a Objetos; "
"Sistemas Operativos.")))
(:category (:text (:en "Operating systems: ")
(:fr "Systèmes d'exploitation : ")
(:es "Sistemas operativos : "))
(:list
"UNIX (Linux, BSD, MacOSX, Solaris) "
"MacOS "
(:text (:en "Programming (system & applications);")
(:fr "Programmation (système & applications); ")
(:es "Programación (Sistema & applicaciones); "))
(:text (:en "Unix system administration.")
(:fr "Administration de systèmes Unix.")
(:es "Administración de sistemas Unix."))))
(:category (:text (:en "Internet:") (:fr "Internet :") (:es "Internet :"))
(:flow
"SMTP"
"POP3"
"IMAP"
"HTTP/HTML/CGI"
"FTP"
"DNS"
"NFS" "..."))
(:category (:text (:en "Programming Languages: ")
(:fr "Langages de programmation : ")
(:es "Lenguajes de programación : "))
(:flow
"Common-Lisp"
"emacs-lisp"
"Smalltalk"
"Java"
"C/C++"
(:text (:en "& other OO, procedural & scripting languages.")
(:fr "& autres langages OO ou procéduraux.")
(:es "& otros lenguajes OO, procedural y de script."))))
(:category (:text (:en "Development environment: ")
(:fr "Environnement de développement : ")
(:es "Entornos de desarrollo : "))
(:list
(:text (:en "UNIX: emacs, MacOSX/GNUstep development tools, "
"Standard UNIX & GNU development tools.")
(:fr "UNIX: emacs, outils de développement MacOSX "
"(Xcode) & GNUstep (Gorm); "
"Outils de développement standard UNIX & GNU.")
(:es "UNIX: emacs, Herramientas de desarrolo MacOSX "
"(Xcode) y GNUstep (Gorm); "
"Herramientas de desarrolo UNIX & GNU."))
(:text (:en "MacOS: CodeWarrior, MPW."))))
(:category (:text (:en "CASE Tools: ")
(:fr "Ateliers de génie logiciel : ")
(:es "Heramientas CASE : "))
(:list
(:text (:en "Objecteering UML (from Softeam SA); ")
(:fr "Objecteering UML (de Softeam SA); ")
(:es "Objecteering UML (de Softeam SA); "))
(:text (:en "ObjectTeam (from Cayenne Inc.); ")
(:fr "ObjectTeam (de Cayenne Inc.); ")
(:es "ObjectTeam (de Cayenne Inc.); "))
(:text (:en "OMTool (from Martin Marietta, Inc.). ")
(:fr "OMTool (de Martin Marietta, Inc.). ")
(:es "OMTool (de Martin Marietta, Inc.). "))))
(:category (:text (:en "Methodologies: ")
(:fr "Méthodologies : ")
(:es "Metodologias : "))
(:flow "UML" "OMT" "Booch"))
(:category (:text (:en "Databases: ")
(:fr "Bases de données : ")
(:es "Bases de datos : "))
(:flow "PostgreSQL" "MySQL" "Oracle" "Sybase")))
(:emp (:date 1998 "Autumn 1997 - Spring 1998")
(:desc
(:text (:en "A module of the AELEC application which purpose "
"is to generate labels for double-blind clinical "
"tests (for X & Lan SA).")
(:fr "Un module de l'application AELEC "
"(génération d'étiquettes pour des tests cliniques "
"en double-aveugle) (X & Lan SA).")
(:es "Un modulo de la aplicación AELEC: generación de "
"etiquetas para los testos clinicos en doble "
"ciego (para X & Lan SA). "))
(:skill "NeXTSTEP""Objective-C")))
(:emp (:date 1996 "1994 - 1996")
(:desc
(:text (:en "Employed by ORME Informatique SARL: "
"Worked as consultant at "
"Abeille/Vie (Commecial Union), Secteur Méthodes:")
(:fr "Employé chez ORME Informatique SARL : "
"Consultant chez Abeille/Vie (Commecial Union), "
"Secteur Méthodes :")
(:es "Empleado por ORME Informatique SARL: "
"Trabajé de consultor en la compañia de "
"seguros Abeille/Vie (Commecial Union), "
"Sector Metodologia:"))
(:list
((:text (:en "Managed a team of 3 persons responsible "
"of the printing applications.")
(:fr "mise en place de la cellule composition "
"(3 personnes) responsable des applications "
"d'impression des courriers clients.")
(:es "Dirigé un equipo de tres personas "
"responsable de las aplicaciones de impresion "
"de los correos de seguro."))
(:skill "SGML" "Xerox 4090 printer" "PCL printer"))
((:text (:en "Technical support to UNIX developpers. ")
(:fr "Support technique aux développeurs UNIX. ")
(:es "Soporte Tecnico a los desarroladores UNIX. "))
(:skill "makefile" "RCS" "CVS" "development tools"))
((:text (:en "Object-Oriented technologies consulting. ")
(:Fr "Conseils technologies orientées-objet. ")
(:es "Consultor sobre las tecnologias Orientado "
"a Objetos.")))
((:text (:en "Planed and launched the development of a "
"time tracking & user requests management "
"software.")
(:fr "Planification et mise en route du "
"développement d'un logiciel de gestion "
"des temps et des requêtes utilisateur.")
(:es "Planifiqué y arranqué el desarrolo de una "
"aplicación de seguimiento de tiempos de "
"trabajo y gerencia de las peticiones de "
"usuarios."))))))
(:emp (:date 1989 "1988 - 1989")
(:desc
(:text (:en "Employed by CEDISECO SA: Technical Support "
"for a LAN of 20 Macintosh.")
(:fr "Employé par CEDISECO SA : Support Technique "
"pour un réseau local de 20 Macintosh.")
(:es " Empleado por CEDISECO SA: Soporte tecnico "
"de una red local de 20 Macintosh."))))
(:emp (:date 1982 "1982 - 1988")
(:desc
(:text (:en "Employed by the Armée de l'Air (French Air Force):")
(:fr "Engagé dans Armée de l'Air :")
(:es "Empleado por el Ejército del Aire Francés :"))
(:list
(:text (:en "Maintainance of a COBOL & Assembler application.")
(:fr "Maintainance d'une application de gestion "
"COBOL & Assembleur.")
(:es "Mantenimiento de una aplicación de gestion "
"en COBOL & Asemblador."))
(:text (:en "Development of BASIC & DBASE IV applications.")
(:fr "Développement d'applications de gestion "
"(BASIC & DBASE IV).")
(:es "Desarrolo de aplicaciones en BASIC & DBASE IV.")))))
(:emp (:date :current "1996 - today")
(:desc
(:list
((:text (:en "Installation & remote administration of a "
"4-CPU Linux cluster server including:")
(:fr "Configuration et télémaintenance d'un serveur "
"Linux cluster de 4 CPU comprenant entre autres :")
(:es "Instalación y Administración a distancia de "
"un servidor Linux cluster de 4 CPU incluyendo:"))
(:list
((:text (:en "a domain name server (DNS),")
(:fr "serveur nom de domaine (DNS),")
(:es "servidor de dominio (DNS),")))
((:text (:en "a mail server "
"(postfix MTA, POP, IMAP, ClamAV, "
"SpamAssassin, WebMail),")
(:fr "serveur de messagerie "
"(postfix MTA, POP, IMAP, ClamAV, "
"SpamAssassin, WebMail),")
(:es "servidor de mensajeria "
"(postfix MTA, POP, IMAP, ClamAV, "
"SpamAssassin, WebMail),")))
((:text (:en "Web & FTP server with virtual hosting,")
(:fr "serveur Web et FTP avec hébergement virtuel,")
(:es "Servidor Web y FTP con virtual hosting,")))
((:text (:en "MySQL database server,")
(:fr "Serveur de base de donnée MySQL,")
(:es "Servidor de base de datos MySQL,")))
((:text (:en "mail list server,")
(:fr "serveur de listes de diffusion,")
(:es "Servidor de listas de difusion,")))
((:text (:en "2nd level phone support,")
(:fr "Support technique téléphonique de 2e niveau,")
(:es "Soporte telefonico de nivel 2 a los usuarios,")))
((:text (:en "a few on-site travels for hardware upgrades,")
(:fr "Visite sur site pour mises à jour du matériel,")
(:es "Algunos viajes en sitio para poner al dia el "
"material,")))
((:text (:en "Development of various utilities in Common-Lisp:")
(:fr "Développment de divers utiltiaires en Common-Lisp :")
(:es "Desarrollo de diversas utilidades en Common Lisp :"))
(:list
((:text (:en "Web application to let the users manage "
"their .vacation file,")
(:fr "Application Web permettant aux utilisateurs "
"la gestion de leur fichier .vacation")
(:es "Aplicacion Web de gestion de los usuarios "
"(selección del tipo de accesso de correo "
"(POP o IMAP), cambio de contraseña, "
"gestion del programa vacation, etc).")))
((:text (:en "Generation of named configuration & zone files.")
(:fr "Génération des fichiers de configuration et "
"zones de named.")
(:es "Generación de los archivos de configuración "
"y zonas DNS.")))
((:text (:en "Generation of postfix 'virtual' file.")
(:fr "Génération du fichier 'virtual' de postfix.")
(:es "Generación de los archivos 'virtual' "
"de postfix."))))))
(:link "http://janus.afaa.asso.fr/")
(:skill "Linux""Apache""postfix""Common-Lisp""UncommonWeb"))
((:text (:en "Installation & administration of a web & email "
"server, and small MacOSX LAN with 1st level "
"phone support to the users.")
(:fr "Installation et administration d'un serveur "
"web & email, et d'un réseau local MacOSX, "
"avec support téléphonique 1e niveau aux utilisateurs.")
(:es "Instalación y administración de servidor "
"web y mensajeria, y red local MacOSX, "
"con Soporte telefonico de nivel 1 a los usuarios. "))
(:link "http://www.intergruas.com/" "Intergruas 2000 S.L.")
(:skill "MacOSX""Linux""Apache""postfix"))
((:text (:en "In development: a web agent to collect "
"addresses from web phone directories, ")
(:fr "Développement: un agent web collectant des adresses "
"postales de répertoires téléphoniques sur le web.")
(:es "Desarrollo de un agente web para colectar "
"dirrecciones de las páginas amarillas. "))
(:skill "Common-Lisp""HTTP""HTML parsing""pattern matching "
"CSV""database")))))
(:emp (:date 2003 "December 2000 - June 2003")
(:desc
(:text (:en "Maintenance of AvMailGate, email antivirus filter, "
"for H+BEDV GmbH (all but the antivirus part per se "
"which is done in house by H+BEDV). "
"Development of test case scripts in emacs-lisp. ")
(:fr "Développement & Maintenance du logiciel AvMailGate, "
"filtre antivirus de messagerie, de H+BEDV GmbH, "
"(hormis la partie antivirus proprement dite).")
(:es "Mantenimiento y desarrollo de nuevas funciones "
"de AvMailGate, filtro de correo antivirus, "
"para H+BEDV GmbH (Todo, salvo la parte antivirus "
"que esta hecha por H+BEDV). "
"Desarrollo de scripts de test en emacs-lisp. "))
(:link "http://www.hbedv.com/")
(:mode (:text (:en "Remote work")
(:fr "Télétravail")
(:es "Trabajo a distancia")))
(:skill "Unix""C""SMTP""emacs-lisp")))
(:emp (:date 2001 "Summer 2001")
(:desc
(:text (:en "Development of a fast geographical indexing "
"module in C++, based on memory mapped quad-trees files, "
"for an interactive map application (for Mappy SA). "
"Testbed developed on NeXTSTEP.")
(:fr "Développement en C++ d'un module d'indexation "
"géographique à base d'arbres quaternaires pour "
"une application de cartographie interactive "
"(Mappy SA). "
"Application de test développée sur NeXTSTEP.")
(:es "Desarrollo de un modulo de indexación geográfica "
"rapida in C++, basado en archivos quad-arboles "
"mapeados en memoria, por una aplicación de mapas "
"interactivas (para Mappy SA). "
"Aplicación de test desarrollado sobre NeXTSTEP."))
(:link "http://www.mappy.com/")
(:mode (:text (:en "Remote work")
(:fr "Télétravail")
(:es "Trabajo a distancia")))
(:skill "Unix""C++""OpenStep""Objective-C")))
(:emp (:date 1999 "Summer 1999")
(:desc
(:text (:en "Development of an Oracle7/Oracle8 adaptor for GNUstep/db "
"(compatible with Apple's Enterprise Object Framework)")
(:fr "Développement d'un adapteur Oracle7/Oracle8 pour "
"GNUstep/db (compatible EOF-1). ")
(:es "Desarrollo de un adaptador Oracle7/Oracle8 para "
"GNUstep/db (compatible con EOF-1)."))
(:link "http://www.informatimago.com/develop/gnustep/#OracleAdaptor")
(:link "http://www.gnustep.org")
(:mode (:text (:en "Remote work, free software funded by: ")
(:fr "Télétravail, logiciel libre financé par : ")
(:es "Trabajo a distancia, "
"software libre financiado por : "))
(:link "http://www.orange-concept.com/" "Orange Concept"))
(:skill "GNUstep""Objective-C""Oracle")))
(:emp (:date 1998 "Autumn 1998")
(:desc
(:text (:en "Installation & configuration of a Cisco 1600 "
"router between the Saturn B satellite "
"transmitter (Inmarsat) & the LAN of the "
"'Fleur de Lampaul'.")
(:fr "Installation & configuration d'un routeur "
"Cisco 1600 entre le transmetteur Inmarsat "
"Saturn B et le réseau local du 'Fleur de Lampaul'.")
(:es "Installación & configuración de un enrutador "
"Cisco 1600 entre un transmisor Saturn B de "
"satelito (Inmarsat) y la red local del barco "
"'Fleur de Lampaul'."))
(:link "http://www.fleurdelampaul.com/")
(:skill "cisco IOS" "router")))
(:emp (:date 1998 "Summer 1998")
(:desc
(:text (:en "NeXTSTEP User Interface for Squeak Smalltalk.")
(:fr "Interface utilisateur NeXTSTEP pour Smalltalk Squeak.")
(:es "Interfaz usuario grafico NeXTSTEP para el "
"Smalltalk Squeak."))
(:link "http://www.informatimago.com/develop/squeak/")
(:skill "NeXTSTEP""Objective-C""Smalltalk")))
(:emp (:date 1997 "Autumn 1996 - Summer 1997")
(:desc
(:text (:en "Porting the EuroFile Transfer ETS 300 375 protocol "
"stack from PC to Macintosh (for the GrandCentral "
"application of Hermstedt GmbH).")
(:fr "Port du protocole EuroFile Transfer ETS 300 375 de "
"PC à Macintosh (pour l'application GrandCentral "
"de Hermstedt GmbH)."))
(:link "http://www.hermstedt.de/")
(:text (:en "(Developed partial C++ parser in Common Lisp "
"to aid in the analysis of the original C++ code).")
(:fr "(Développé un parseur partiel C++ en Common Lisp "
"pour faciliter l'analyse du code C++ original.")
(:es "(Desarrollé un analizador partial de C++ en "
"Common Lisp para ayudar en la análisis del "
"codigo original en C++). "))
(:mode (:text (:en "Remote work, with a final travel at Hermstedt's.")
(:fr "Télétravail, "
"avec un séjour final chez Hermstedt.")
(:es "Trabajo a distancia, con un viaje final. "
"en Alemania")))
(:skill "EFT""Macintosh""C++""NeXTSTEP""Common-Lisp")))
(:emp (:date 1996 "Summer 1996")
(:desc
(:text (:en "Installation, configuration & remote administration "
"of a NeXTSTEP intranet/Internet server (for AFAA).")
(:fr "Installation, configuration & télé-administration "
"d'un serveur Intranet/Internet (AFAA).")
(:es "Installación, configuración & administración a "
"distancia de un servidor Internet y intranet "
"NeXTSTEP (para AFAA)."))
(:link "http://janus.afaa.asso.fr")
(:skill "NeXTSTEP" "sendmail" "POP-3")))
(:emp (:date 1996 "Spring 1996")
(:desc
(:text (:en "Development of a NeXTSTEP CL-GD754x Screen "
"Device Driver.")
(:fr "Développement d'un pilote vidéo CL-GD754x "
"pour NeXTSTEP.")
(:es "Desarrollo de un piloto de pantalla CL-GD754x "
"para NeXTSTEP."))
(:link "http://www.informatimago.com/develop/cirrus/")
(:skill "NeXTSTEP""Objective-C")))
(:emp (:date 1993 "Autumn 1993 - Spring 1994")
(:desc
(:text (:en "Development of NeXTSTEP Minitel 1B Videotex "
"Terminal Emulator.")
(:fr "Développement d'un émulateur Minitel 1B.")
(:es "Desarrollo de un emulador de terminal Videotex "
"Minitel 1B para NeXTSTEP."))
(:link "http://www.informatimago.com/develop/mtel/")
(:skill "NeXTSTEP""C++""Videotex")))
(:emp (:date 1993 "Spring 1993")
(:desc
(:text (:en "Installation & configuration of routers on a WAN "
"(for SECUR.NET).")
(:fr "Installation et configuration de routeurs WAN "
"(SECUR.NET).")
(:es "Installación y configuración de enrutadores WAN "
"(para SECUR.NET)"))
(:skill "router""internet""DNS""sendmail""X25""X400")))
(:emp (:date 1992 "Winter 1992")
(:desc
(:text (:en "NeXTSTEP port of the Abalone game.")
(:fr "Port d'un ludiciel Abalone de Macintosh à "
"NeXTSTEP.")
(:es "Translación de un juego Abalone de Macintosh "
"a NeXTSTEP."))
(:link "http://www.informatimago.com/develop/abalone/")
(:skill "NeXTSTEP""Objective-C")))
(:emp (:date 1991 "Spring 1991")
(:desc
(:text (:en "NeXTSTEP prototype of user interface for the ProDoc "
"application (for DiaInformatica SARL).")
(:fr "Prototype d'interface utilisateur d'une application "
"sur NeXTSTEP (DiaInformatica SARL).")
(:es "Prototipo de interfaz usuario NeXTSTEP por la "
"applicación ProDoc (para DiaInformatica SARL)."))
(:skill "NeXTSTEP""Objective-C")))
(:emp (:date 1991 "Winter 1991")
(:desc
(:text (:en "Macintosh software to control remotely video "
"cameras (for OSII Rémy R&D).")
(:fr "Logiciel de commande à distance de caméra vidéo "
"pour Macintosh (OSII Rémy R&D).")
(:es "Un programa de mando a distancia para camaras "
"video sobre Macintosh (para OSII Rémy R&D). "))
(:skill "Macintosh""Modula-2")))
(:emp (:date 1990 "Summer 1989 - Spring 1990")
(:desc
(:text (:en "Macintosh ISDN Card Driver (for SCSI SA).")
(:fr "Pilote de carte RNIS pour Macintosh (SCSI SA).")
(:es "Piloto para una tajeta de interfaz RDSI por "
"Macintosh (para SCSI SA)."))
(:skill "Macintosh""C")))
(:emp (:date 1989 "Spring 1989")
(:desc
(:text (:en "Minitel Mail Server (for CEDISECO SA).")
(:fr "Serveur de messagerie Minitel (CEDISECO SA).")
(:es "Desarrollo de un servidor de mensajeria Minitel "
"(para CEDISECO SA)."))
(:skill "Macintosh""Modula-2""Videotex")))
(:emp (:date 1988 "Winter 1988")
(:desc
(:text (:en "Macintosh C.Itoh 600+ Line Printer Driver, "
"(for CEDISECO SA)")
(:fr "Pilote d'imprimante C.Itoh 600+ pour Macintosh "
"(CEDISECO SA).")
(:es "Piloto de impresora C.Itoh 600+ por Macintosh, "
"(para CEDISECO SA)."))
(:skill "Macintosh""Modula-2")))
(:emp (:date 1987 "Autumn 1987")
(:desc
(:text (:en "Macintosh SE External Screen Driver, "
"(for iOware SARL)")
(:fr "Pilote vidéo écran externe pour Macintosh SE "
"(iOware SARL).")
(:es "Piloto de pantalla external por Macintosh SE, "
"(para iOware SARL)."))
(:skill "Macintosh""68000 Assembler")))
(:emp (:date 1987 "Summer 1987")
(:desc
(:text (:en "A Macintosh IDE for a small tutorial parallel "
"programming language.")
(:fr "Un éditeur/compilateur/débogueur pour un "
"langage de programmation parallèle didactique "
"sur Macintosh.")
(:es "Desarrollo de un IDE (entorno de desarrollo "
"integrado) por un pequeño lenguaje de programación "
"paralelo didactico por Macintosh."))
(:skill "Macintosh""LightSpeed Pascal")))
(:emp (:date 1986 "December 1986")
(:desc
(:text (:en "Macintosh Biorythm application "
"(published by PsyDen Inc).")
(:fr "Application Macintosh Biorythm "
"(éditée par PsyDen Inc).")
(:es "Una aplicación de Bioritmos por Macintosh "
"(publicado por PsyDen Inc)."))
(:skill "Macintosh""LightSpeed Pascal")))
(:stu (:date 1995 "July 1995")
(:desc
(:text (:en "Softeam Classe-Relation OO Methodology & "
"Objecteering CASE Course.")
(:fr "Stage Softeam: Méthodologie Classe-Relation, "
"AGL Objecteering.")
(:es "Cursillo sobre la metodologia OO Clase-Relación "
"de Softeam & Objecteering CASE."))))
(:stu (:date 1995 "June 1995")
(:desc
(:text (:en "NeXT Developer Training Course Programming "
"with Enterprise Object Framework.")
(:fr "Stage NeXT: Programmation Enterprise Object Framework.")
(:es "Cursillo 'NeXT Developer Training Course Programming "
"with Enterprise Object Framework'."))))
(:stu (:date 1992 "February 1992")
(:desc
(:text (:en "NeXT Developer Training Course Programming "
"the NeXT Computer.")
(:fr "Stage NeXT: Programmation NeXTSTEP.")
(:es "Cursillo 'NeXT Developer Training Course Programming "
"the NeXT Computer.'"))))
(:stu (:date 1992 "1991 - 1992")
(:desc
(:text (:en "Maitrise d'Informatique at Université Pierre & "
"Marie Curie - Paris 6")
(:fr "Maitrise d'Informatique; "
"Université Pierre et Marie Curie - Paris 6.")
(:es "Maitrise d'Informatique en la Universidad Pierre "
"y Marie Curie - Paris 6."))
(:list (:text (:en "AI: Knowledge Representation (Lisp);")
(:fr "IA: Représentation des connaissance (Lisp);")
(:es "IA: Representación del conocimiento (Lisp);"))
(:text (:en "Algorithms: Parallel Algorithms, Compilation;")
(:fr "Algorithmes: Algorithmes parallèles, "
"Compilation;")
(:es "Algoritmos: Algoritmos paralelos, "
"Compilación;"))
(:text (:en "Operating systems: System Design, "
"Distributed Systems, Unix Architecture, "
"Network.")
(:fr "Systèmes d'exploitation: "
"Conception des systèmes; "
"Systèmes distribués; " "Architecture Unix; "
"Réseaux.")
(:es "Sistemas: Concepción de los sistemas, "
"Sistemas distribuidos, "
"Architectura Unix, Redes.")))))
(:stu (:date 1991 "1989 - 1991")
(:desc
(:text (:en "Licence d'Informatique at Université Pierre & "
"Marie Curie - Paris 6")
(:fr "Licence d'Informatique; "
"Université Pierre et Marie Curie - Paris 6.")
(:es "Licence d'Informatique en la Universidad Pierre "
"y Marie Curie - Paris 6."))))
(:stu (:date 1989 "1986 - 1989")
(:desc
(:text (:en "Diplôme d'Etudes Universitaires Générales 'A' "
"Science et Structure de la Matière at Université "
"Pierre & Marie Curie - Paris 6")
(:fr "Diplôme d'Etudes Universitaires Générales 'A' "
"Science et Structure de la Matière; "
"Université Pierre et Marie Curie - Paris 6.")
(:es "Diploma de Estudios Universitarios Generales 'A' "
"Ciencia y Structura de la Matera en la "
"Universidad Pierre y Marie Curie - Paris 6."))))
(:stu (:date 1987 "1983 - 1987")
(:desc
(:text (:en "Premier Cycle Technique en Informatique at "
"Conservatoire National des Arts et Métiers (Paris).")
(:fr "Premier Cycle Technique en Informatique "
"Conservatoire National des Arts et Metiers (Paris).")
(:es "Primiero Ciclo Tecnico en Informática "
"en el Conservatoire National des Arts et Métiers "
"(Paris)."))))
(:stu (:date 1993 "1993")
(:desc
(:text (:en "Degree of Programmer/Operator in the Armée de l'Air "
"(French Air Force)")
(:fr "Diplôme de Programmeur/Pupitreur de l'Armée de l'Air. "
"(équivalent Baccalauréat 'H').")
(:es "Diploma de Programador/Operator en el "
"Ejército del Aire Francés."))))
(:stu (:date 1982 "1982")
(:desc
(:text (:en "Baccalauréat Mathématiques")
(:fr "Baccalauréat 'C' Mathématiques.")
(:es "Baccalauréat Mathématiques"))))
(:language
(:text (:en "French: native")
(:fr "Français : langue maternelle")
(:es "Frances"))
(:text (:en "English: fluent")
(:fr "Anglais : courant")
(:es "Inglés"))
(:text (:en "Spanish: fluent")
(:fr "Espagnol : courant")
(:es "Castillano")))
(:leisure
(:text (:en "Programming")
(:fr "Informatique")
(:es "Informatica"))
(:text (:en "Flight simulators")
(:fr "Simulateurs de vol")
(:es "Simulatores de vuelo"))
(:text (:en "Science-Fiction")
(:fr "Science-Fiction")
(:es "Ciencia-Ficción"))
(:text (:en "Sailing ships")
(:fr "Voile")
(:es "Vela"))))))
;;----------------------------------------------------------------------
;; GENERATOR
;;----------------------------------------------------------------------
(defclass generator ()
())
(defgeneric gen-document (generator genbody &key file-path title))
(defgeneric gen-text (generator text))
(defgeneric gen-section (generator genbody &key name title)
(:documentation "The section name is used to generate anchors and links."))
(defgeneric gen-list (generator genbody &key type))
(defgeneric gen-list-item (generator genbody &key name))
(defgeneric gen-definition (generator term genbody &key name))
(defgeneric gen-link (generator genbody &key url))
(defvar *language* :en)
(defvar *generator* nil "The current generator")
(defvar *section* 0 "Used by gen-section methods to track the section level.")
(defmacro document ((&key (generator '*generator*) (file-path "document")
(title nil)) &body body)
(with-gensyms (vgen)
`(let ((,vgen ,generator))
(gen-document ,vgen (lambda () ,@body) :file-path ,file-path :title ,title))))
(defmacro section ((&key (generator '*generator*) (name nil) (title "Section"))
&body body)
(with-gensyms (vgen)
`(let ((,vgen ,generator))
(gen-section ,generator (lambda () ,@body) :name ,name :title ,title))))
(defmacro bullet-list (&body body)
`(gen-list *generator* (lambda () ,@body)))
(defmacro ordered-list (&body body)
`(gen-list *generator* (lambda () ,@body) :type :ordered))
(defmacro definition-list (&body body)
`(gen-list *generator* (lambda () ,@body) :type :definition))
(defmacro list-item (&body body)
`(gen-list-item *generator* (lambda () ,@body)))
;; (gen-text *generator* (language *language* item)))))
(defmacro definition (term &body description)
(let ((vterm (gensym)))
`(let ((,vterm ,term))
(gen-definition *generator*
(if ,vterm (language *language* ,vterm) "")
(lambda () ,@description)))))
(defun bullet-list-items (items)
(bullet-list (mapc (lambda (item) (list-item (generate-items (list item)))) items)))
(defmacro link (url text)
`(gen-link *generator*
(lambda () (gen-text *generator* (language *language* ,text)))
:url ,url))
;;----------------------------------------------------------------------
;; HTML-GENERATOR
;;----------------------------------------------------------------------
;; This class genrates HTML documents.
;;
(defclass html-generator (generator)
())
(defun rfc-822-date ()
(multiple-value-bind (se mi ho da mo ye day-of-week)
(decode-universal-time (get-universal-time) 0)
(format nil "~[Mon~;Tue~;Wed~;Thi~;Fri~;Sat~;Sun~], ~2@A ~
~[~;Jan~;Feb~;Mar~;Apr~;May~;Jun~;Jul~;Aug~;Sep~;Oct~;Nov~;Dec~] ~
~4,'0D ~2,'0D:~2,'0D:~2,'0D GMT "
day-of-week da mo ye ho mi se)))
(defmethod gen-style-header ((generator html-generator))
(html:META (:http-equiv "Expires" :content (rfc-822-date)))
(html:link (:href "/default.css" :rel "stylesheet" :type "text/css")))
(defmethod gen-document ((generator html-generator) genbody
&key (file-path #P"document") (title nil))
(html:initialize)
(html:DOCTYPE :TRANSITIONAL
(html:html ()
(html:head ()
(when title
(html:title ()
(gen-text generator title)))
(gen-style-header generator))
(html:body ()
(funcall genbody))))
(let ((path (make-pathname :type "html" :defaults file-path)))
(with-open-file (html path
:direction :output
:if-does-not-exist :create
:if-exists :supersede)
(html:finalize html))
path))
(defmethod gen-text ((generator html-generator) text)
(unless text (invoke-debugger (make-instance 'error)))
(html:insert-pcdata "~A" text))
(defmethod gen-section ((generator html-generator) genbody
&key (name nil) (title "Section"))
(let ((*section* (1+ *section*)))
(flet ((title () (if name
(html:a (:name name) (gen-text generator title))
(gen-text generator title))))
(case *section*
((1) (html:h1 () (title)))
((2) (html:h2 () (title)))
((3) (html:h3 () (title)))
((4) (html:h4 () (title)))
((5) (html:h5 () (title)))
(otherwise (html:h6 () (title)))))
(funcall genbody)))
(defmethod gen-list ((generator html-generator) genbody &key (type :bullet))
(case type
((:ordered) (html:ol () (funcall genbody)))
((:definition) (html:dl () (funcall genbody)))
(otherwise (html:ul () (funcall genbody)))))
(defmethod gen-list-item ((generator html-generator) genbody &key (name nil))
(if name
(html:li (:class name :id name) (funcall genbody))
(html:li () (funcall genbody))))
(defmethod gen-definition ((generator html-generator) term genbody &key name)
(if name
(progn (html:dt (:class name :id name) (gen-text generator term))
(html:dd (:class name :id name) (funcall genbody)))
(progn (html:dt () (gen-text generator term))
(html:dd () (funcall genbody)))))
(defmethod gen-link ((generator html-generator) genbody &key url)
(html:a (:href url) (funcall genbody)))
;;----------------------------------------------------------------------
(defmacro group (&body body) `(html:dl () ,@body))
(defun flow-items (language items)
(loop
:initially (html:insert-pcdata (language language (first items)))
:for line :in (rest items)
:do (progn (html:insert-pcdata ", ")
(html:insert-pcdata (language language line)))))
(defun field (title value &key strong link)
(definition title
(labels ((insert-value (value)
(assert value)
(if (consp value)
(loop
:initially (gen-text *generator* (first value))
:for line :in (rest value)
:do (html:br) (gen-text *generator* line))
(gen-text *generator* value)))
(opt-strong (value)
(if strong
(html:strong () (insert-value value))
(insert-value value))))
(if link
(link value value)
(opt-strong value)))))
(defun link-field (title value) (field title value :link t))
(defun item-kind (item)
(cond
((consp item)
(if (member (first item) '(:text :list :link :mode :skill :break))
(first item)
:sequence))
((stringp item) :text)
(t (error "Invalid item ~S" item))))
(defun generate-items (items)
(let ((groups
(loop
:named :groups
:with result = '()
:with group-kind = nil
:with group = '()
:for item :in items
:for item-kind = (item-kind item)
:do (if (eq group-kind item-kind)
(push item group)
(progn
(when group (push (nreverse group) result))
(unless (and (eq :text group-kind)
(eq :list item-kind))
;;(push '((:break)) result)
)
(setf group (list item)
group-kind item-kind)))
:finally (progn (when group (push (nreverse group) result))
(return-from :groups (nreverse result))))))
(loop
:for (group next-group) :on groups
:do
;; (print `(group = ,group))
;; (print `(next-group = ,next-group))
(ecase (item-kind (first group))
(:text
(dolist (item group)
(html:insert-pcdata "~A " (language *language* item))))
(:list
(dolist (item group)
(bullet-list-items (rest item))))
(:link
(let ((do-break nil))
(dolist (item group)
(if do-break
(html:br)
(setf do-break t))
(link (second item) (or (third item) (second item))))))
(:sequence
(dolist (item group) (generate-items item)))
(:mode
(html:i () (dolist (item group) (generate-items (rest item)))))
(:skill
(dolist (item group)
(html:code () (flow-items *language* (rest item))))))
(when (and next-group
(not (eq :list (item-kind (first group))))
(not (eq :list (item-kind (first next-group)))))
(html:br)))))
;;----------------------------------------------------------------------
;; GENERATE-CV
;;----------------------------------------------------------------------
(defun pget (l k) (cdr (assoc k (cdr l))))
(declaim (inline pget))
(defun language (language item)
(etypecase item
(string item)
(cons (apply (function concatenate) 'string
(if (eq :text (first item))
(cdr (or (assoc language (rest item)) (second item)))
item)))))
(defun vowelp (ch)
(position
ch "AEIOUYaeiouyÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÒÓÔÕÖØÙÚÛÜÝàáâãäåæèéêëìíîïòóôõöøùúûüýÿ"))
(defun cv-file-path (language full)
(format nil "cv-~(~A-~A~)" language (case full
((nil) "short")
((t) "full")
(otherwise full))))
(defgeneric generate-cv (generator cv &key full language toc))
(defmethod generate-cv ((*generator* generator) cv
&key (language *language*) full toc)
(let ((*language* language)
(person (find :person (cdr cv) :key (function first)))
(summary (find :summary (cdr cv) :key (function first)))
(skills (find :skills (cdr cv) :key (function first)))
(languages (find :language (cdr cv) :key (function first)))
(leisures (find :leisure (cdr cv) :key (function first)))
(employments
(let ((employments (remove :emp (cdr cv) :key (function first)
:test (complement (function eq)))))
(flet ((year (employment) (first (pget employment :date))))
(sort (if (not (or (numberp full) (null full)))
employments
(remove-if
(multiple-value-bind (s m h d o year)
(decode-universal-time (get-universal-time) 0)
(declare (ignore s m h d o))
(setf year (- year (if (numberp full) full 10)))
(lambda (emp-year) (and (not (eq :current emp-year))
(< emp-year year))))
employments :key (function year)))
(lambda (a b) (or (eq a :current)
(and (not (eq b :current)) (>= a b))))
:key (function year)))))
(studies (remove :stu (cdr cv) :key (function first)
:test (complement (function eq))))
(table
(quote ((:document "resume"
(:text (:en "Resume")
(:fr "Curriculum Vitae")
(:es "Curriculum Vitae")))
(:toc "toc"
(:text (:en "Contents")
(:fr "Table")
(:es "Contenido")))
(:skills "skills"
(:text (:en "COMPUTER SCIENCE KNOWLEDGE")
(:fr "CONNAISSANCES INFORMATIQUE")
(:es "CONOCIMIENTOS DE INFORMÁTICA")))
(:emp "employments"
(:text (:en "FREE-LANCE DEVELOPMENT AND MISSIONS")
(:fr "MISSIONS ET DÉVELOPPEMENTS")
(:es "TRABAJOS")))
(:full "full"
(:text (:en "Full Resume")
(:fr "CV complet")
(:es "CV completo")))
(:stu "studies"
(:text (:en "STUDIES")
(:fr "ÉTUDES")
(:es "ESTUDIOS")))
(:languages "languages"
(:text (:en "LANGUAGES")
(:fr "LANGUES")
(:es "IDIOMAS")))
(:leisures "leisures"
(:text (:en "LEISURES")
(:fr "LOISIRS")
(:es "OCIO")))))))
(flet ((entry-key (entry) (first entry))
(toc-name (key) (language language (second (assoc key table))))
(toc-title (key) (language language (third (assoc key table))))
(employment-item (employment)
(let ((date (pget employment :date))
(desc (pget employment :desc)))
(definition (second date) (generate-items desc)))))
(document (:file-path (cv-file-path language full)
:title (let ((name (first (pget person :name))))
(format nil (ecase language
(:en "~*~A's Resume")
(:fr "Curriculum Vitae d~:[e ~;~]~A")
(:es "Curriculum Vitae de ~*~A"))
(vowelp (aref name 0)) name)))
(section (:name (toc-name :document) :title (toc-title :document))
;; Name & Address:
(group
(field nil (first (pget person :name)) :strong t)
(field nil (language language
(first (pget person :nationality))))
(field nil (pget person :address))
(link-field nil (format nil "mailto:~A" (first (pget person :mail))))
(link-field nil (format nil "http://~A" (first (pget person :web))))
(field nil (first (pget person :phone))))
;; Summary:
(bullet-list-items (rest summary))
(when toc
(section (:name (toc-name :toc) :title (toc-title :toc))
(bullet-list
(dolist (item (remove-if
(lambda (x) (member x '(:toc :full :document)))
table :key (function entry-key)))
(gen-list-item
*generator*
(lambda () (link (format nil "#~A" (second item))
(third item)))))))))
(section (:name (toc-name :skills) :title (toc-title :skills))
(group
(dolist (cat (rest skills))
(definition-list
(definition (second cat)
(dolist (dot-point (cddr cat))
(ecase (first dot-point)
(:flow (flow-items language (rest dot-point)))
(:list (bullet-list-items (rest dot-point))))
(html:br)))))))
(section (:name (toc-name :emp) :title (toc-title :emp))
(definition-list
(mapc (function employment-item) employments))
(unless (eq full t)
(link (cv-file-path language t) (toc-title :full))))
(section (:name (toc-name :stu) :title (toc-title :stu))
(definition-list
(mapc (function employment-item) studies)))
(section (:name (toc-name :languages) :title (toc-title :languages))
(bullet-list-items (rest languages)))
(section (:name (toc-name :leisures) :title (toc-title :leisures))
(bullet-list-items (rest leisures)))))))
#+emacs
(defun put-in-text (start end)
(interactive "r")
(let ((en (buffer-substring start end)))
(delete-region start end)
(insert "(:text (:en " en ")\n(:fr \"\")\n(:es \"\"))")))
#+emacs
(local-set-key (kbd "s-p") (function put-in-text))
#||
(print (generate-cv (make-instance 'html-generator) pascal-bourguignon :full t :toc t))
||#
(dolist (full '(nil t))
(dolist (lang '(:en :fr :es))
(print (generate-cv (make-instance 'html-generator) pascal-bourguignon
:full full :toc t :language lang))))
;; Local Variables:
;; eval: (batch-cl-indent (((&whole 4 1 1 1 1 1 1 1 ) &body) document section))
;; End: