;; 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: