]> git.parisson.com Git - telemeta-data.git/commitdiff
adding trunk and tags directories, moving files into trunk
authorolivier <olivier@3bf09e05-f825-4182-b9bc-eedd7160adf0>
Tue, 17 Jun 2008 14:37:42 +0000 (14:37 +0000)
committerolivier <olivier@3bf09e05-f825-4182-b9bc-eedd7160adf0>
Tue, 17 Jun 2008 14:37:42 +0000 (14:37 +0000)
git-svn-id: http://svn.parisson.org/svn/crem@37 3bf09e05-f825-4182-b9bc-eedd7160adf0

48 files changed:
docref/crem.sql [deleted file]
docref/crem.zargo [deleted file]
docref/docref-0.1-prealpha.odt [deleted file]
docref/docref-0.2-prealpha.odt [deleted file]
docref/docref-0.3-alpha.odt [deleted file]
docref/docref-0.4-beta.odt [deleted file]
docref/docref.odt [deleted file]
docref/spec/build.sh [deleted file]
docref/spec/docref.txt [deleted file]
docref/spec/elements.py [deleted file]
docref/spec/parse.py [deleted file]
docref/spec/staticenum.py [deleted file]
docref/spec/tables.py [deleted file]
docref/spec/texttable.py [deleted file]
docref/tools/analyse_collection_ids.py [deleted file]
import/README [deleted file]
import/prototype/README [deleted file]
import/prototype/scripts/import.sql [deleted file]
import/prototype/scripts/prepare [deleted file]
import/prototype/src/2007-05-09/phono.txt.gz [deleted file]
import/prototype/src/2007-05-09/support.txt.gz [deleted file]
import/raw_conversion/README [deleted file]
import/raw_conversion/export.4d.txt [deleted file]
import/raw_conversion/import [deleted file]
trunk/docref/crem.sql [new file with mode: 0644]
trunk/docref/crem.zargo [new file with mode: 0644]
trunk/docref/docref-0.1-prealpha.odt [new file with mode: 0644]
trunk/docref/docref-0.2-prealpha.odt [new file with mode: 0644]
trunk/docref/docref-0.3-alpha.odt [new file with mode: 0644]
trunk/docref/docref-0.4-beta.odt [new file with mode: 0644]
trunk/docref/docref.odt [new file with mode: 0644]
trunk/docref/spec/build.sh [new file with mode: 0644]
trunk/docref/spec/docref.txt [new file with mode: 0644]
trunk/docref/spec/elements.py [new file with mode: 0644]
trunk/docref/spec/parse.py [new file with mode: 0644]
trunk/docref/spec/staticenum.py [new file with mode: 0644]
trunk/docref/spec/tables.py [new file with mode: 0644]
trunk/docref/spec/texttable.py [new file with mode: 0644]
trunk/docref/tools/analyse_collection_ids.py [new file with mode: 0644]
trunk/import/README [new file with mode: 0644]
trunk/import/prototype/README [new file with mode: 0644]
trunk/import/prototype/scripts/import.sql [new file with mode: 0644]
trunk/import/prototype/scripts/prepare [new file with mode: 0755]
trunk/import/prototype/src/2007-05-09/phono.txt.gz [new file with mode: 0755]
trunk/import/prototype/src/2007-05-09/support.txt.gz [new file with mode: 0755]
trunk/import/raw_conversion/README [new file with mode: 0644]
trunk/import/raw_conversion/export.4d.txt [new file with mode: 0755]
trunk/import/raw_conversion/import [new file with mode: 0755]

diff --git a/docref/crem.sql b/docref/crem.sql
deleted file mode 100644 (file)
index 4f60c51..0000000
+++ /dev/null
@@ -1,378 +0,0 @@
---
--- Copyright Samalyse SARL, 2008
--- Auteur: Olivier Guilyardi <olivier@samalyse.com>
--- 
--- Structure de la nouvelle base du CREM
--- 
--- Ce logiciel est régi par la licence CeCILL soumise au droit français et
--- respectant les principes de diffusion des logiciels libres. Vous pouvez
--- utiliser, modifier et/ou redistribuer ce programme sous les conditions
--- de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA 
--- sur le site "http://www.cecill.info".
--- 
--- En contrepartie de l'accessibilité au code source et des droits de copie,
--- de modification et de redistribution accordés par cette licence, il n'est
--- offert aux utilisateurs qu'une garantie limitée.  Pour les mêmes raisons,
--- seule une responsabilité restreinte pèse sur l'auteur du programme,  le
--- titulaire des droits patrimoniaux et les concédants successifs.
--- 
--- A cet égard  l'attention de l'utilisateur est attirée sur les risques
--- associés au chargement,  à l'utilisation,  à la modification et/ou au
--- développement et à la reproduction du logiciel par l'utilisateur étant 
--- donné sa spécificité de logiciel libre, qui peut le rendre complexe à 
--- manipuler et qui le réserve donc à des développeurs et des professionnels
--- avertis possédant  des  connaissances  informatiques approfondies.  Les
--- utilisateurs sont donc invités à charger  et  tester  l'adéquation  du
--- logiciel à leurs besoins dans des conditions permettant d'assurer la
--- sécurité de leurs systèmes et ou de leurs données et, plus généralement, 
--- à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. 
--- 
--- Le fait que vous puissiez accéder à cet en-tête signifie que vous avez 
--- pris connaissance de la licence CeCILL, et que vous en avez accepté les
--- termes.
---
--- SVN:$Id$
---
-
---
--- Enumérations simples
---
-
-CREATE TABLE physical_formats (
-    id      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
-    value   VARCHAR(250) NOT NULL
-);
-
-CREATE TABLE publishing_status (
-    id      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
-    value   VARCHAR(250) NOT NULL
-);
-
-CREATE TABLE acquisition_modes (
-    id      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
-    value   VARCHAR(250) NOT NULL
-);
-
-CREATE TABLE metadata_authors (
-    id      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
-    value   VARCHAR(250) NOT NULL
-);
-
-CREATE TABLE metadata_writers (
-    id      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
-    value   VARCHAR(250) NOT NULL
-);
-
-CREATE TABLE legal_rights (
-    id      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
-    value   VARCHAR(250) NOT NULL
-);
-
-CREATE TABLE recording_contexts (
-    id      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
-    value   VARCHAR(250) NOT NULL
-);
-
-CREATE TABLE ad_conversions (
-    id      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
-    value   VARCHAR(250) NOT NULL
-);
-
-CREATE TABLE vernacular_styles (
-    id      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
-    value   VARCHAR(250) NOT NULL
-);
-
-CREATE TABLE generic_styles (
-    id      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
-    value   VARCHAR(250) NOT NULL
-);
-
---
--- Editeurs et collections
---
-
-CREATE TABLE publishers (
-    id      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
-    value   VARCHAR(250) NOT NULL
-);
-
-CREATE TABLE publisher_collections (
-    id              INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
-    publisher_id    INTEGER NOT NULL,
-    value           VARCHAR(250) NOT NULL,
-
-    FOREIGN KEY(publisher_id) REFERENCES publishers (id)
-);
-
---
--- Thésaurus géographique
---
-
-CREATE TABLE location_types (
-    id              INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
-    type            VARCHAR(250) NOT NULL
-);    
-
-CREATE TABLE locations (
-    name                VARCHAR(250) NOT NULL PRIMARY KEY,
-    type                ENUM('country', 'continent', 'other'),
-    complete_type_id    INTEGER NOT NULL,
-    current_name        VARCHAR(250),
-    is_authoritative    BOOLEAN NOT NULL,
-
-    FOREIGN KEY(current_name) REFERENCES locations (name),
-    FOREIGN KEY(complete_type_id) REFERENCES location_types (id)
-);
-
-CREATE TABLE location_aliases (
-    location_name       VARCHAR(250) NOT NULL,
-    alias               VARCHAR(250) NOT NULL,
-    is_authoritative    BOOLEAN NOT NULL,
-
-    PRIMARY KEY(location_name, alias),
-    FOREIGN KEY(location_name) REFERENCES locations (name)
-);
-
-CREATE TABLE location_relations (
-    location_name           VARCHAR(250) NOT NULL,
-    parent_location_name    VARCHAR(250) NOT NULL,
-
-    PRIMARY KEY(location_name, parent_location_name),
-    FOREIGN KEY(location_name) REFERENCES locations (name),
-    FOREIGN KEY(parent_location_name) REFERENCES locations (name)
-);
-
---
--- Ethnies
---
-
-CREATE TABLE ethnic_groups (
-    id      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
-    name    VARCHAR(250) NOT NULL
-);
-
-CREATE TABLE ethnic_group_aliases (
-    ethnic_group_id INTEGER NOT NULL, 
-    name            VARCHAR(250) NOT NULL,
-
-    FOREIGN KEY(ethnic_group_id) REFERENCES ethnic_groups (id)
-);
-
---
--- Collections
---
-
-CREATE TABLE media_collections (
-    id                      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
-    reference               VARCHAR(250) NOT NULL UNIQUE,
-    physical_format_id      INTEGER NOT NULL,
-    old_code                VARCHAR(250) NOT NULL UNIQUE,
-    code                    VARCHAR(250) NOT NULL UNIQUE,
-    title                   VARCHAR(250) NOT NULL,
-    alt_title               VARCHAR(250) NOT NULL,
-    physical_items_num      INTEGER NOT NULL,
-    publishing_status_id    INTEGER NOT NULL,
-    creator                 VARCHAR(250) NOT NULL,
-    booklet_author          VARCHAR(250) NOT NULL,
-    booklet_description     TEXT NOT NULL,
-    collector               VARCHAR(250) NOT NULL,
-    collector_is_creator    BOOLEAN NOT NULL,
-    publisher_id            INTEGER NOT NULL,
-    year_published          INTEGER NOT NULL,
-    publisher_collection_id INTEGER NOT NULL,
-    publisher_serial        VARCHAR(250) NOT NULL,
-    external_references     TEXT NOT NULL,
-    acquisition_mode_id     INTEGER NOT NULL,
-    comment                 TEXT NOT NULL,
-    metadata_author_id      INTEGER NOT NULL,
-    metadata_writer_id      INTEGER NOT NULL,
-    legal_rights_id         INTEGER NOT NULL,
-    alt_ids                 VARCHAR(250) NOT NULL,
-    recorded_from_year      INTEGER NOT NULL,
-    recorded_to_year        INTEGER NOT NULL,
-    recording_context_id    INTEGER NOT NULL,
-    approx_duration         TIME NOT NULL,
-    doctype_code            INTEGER NOT NULL,
-    travail                 VARCHAR(250) NOT NULL,
-    state                   VARCHAR(250) NOT NULL,
-    cnrs_contributor        VARCHAR(250) NOT NULL,
-    items_done              VARCHAR(250) NOT NULL,
-    a_informer_07_03        VARCHAR(250) NOT NULL,
-    ad_conversion_id        INTEGER NOT NULL,
-    public_access           ENUM('none', 'metadata', 'full') NOT NULL,
-
-    FOREIGN KEY(ad_conversion_id)       REFERENCES ad_conversions (id),
-    FOREIGN KEY(publisher_collection_id) REFERENCES publisher_collections (id),
-    FOREIGN KEY(recording_context_id)   REFERENCES recording_contexts (id),
-    FOREIGN KEY(publisher_id)           REFERENCES publishers (id),
-    FOREIGN KEY(metadata_author_id)     REFERENCES metadata_authors (id),
-    FOREIGN KEY(physical_format_id)     REFERENCES physical_formats (id),
-    FOREIGN KEY(metadata_writer_id)     REFERENCES metadata_writers (id),
-    FOREIGN KEY(legal_rights_id)        REFERENCES legal_rights (id),
-    FOREIGN KEY(acquisition_mode_id)    REFERENCES acquisition_modes (id),
-    FOREIGN KEY(publishing_status_id)   REFERENCES publishing_status (id)
-);
-
---
--- Items
---
-
-CREATE TABLE media_items (
-    id                      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
-    collection_id           INTEGER NOT NULL,
-    track                   VARCHAR(250) NOT NULL,
-    code                    VARCHAR(250) NOT NULL,
-    approx_duration         TIME NOT NULL,
-    recorded_from_date      DATE NOT NULL,
-    recorded_to_date        DATE NOT NULL,
-    location_name           VARCHAR(250) NOT NULL,
-    location_comment        VARCHAR(250) NOT NULL,
-    ethnic_group_id         INTEGER NOT NULL,
-    title                   VARCHAR(250) NOT NULL,
-    alt_title               VARCHAR(250) NOT NULL,
-    author                  VARCHAR(250) NOT NULL,
-    vernacular_style_id     INTEGER NOT NULL,
-    context_comment         TEXT NOT NULL,
-    external_references     VARCHAR(250) NOT NULL,
-    moda_execut             VARCHAR(250) NOT NULL,
-    copied_from_item_id     INTEGER,
-    collector               VARCHAR(250) NOT NULL,
-    cultural_area           VARCHAR(250) NOT NULL,
-    generic_style_id        INTEGER NOT NULL,
-    collector_selection     VARCHAR(250) NOT NULL,
-    creator_reference       VARCHAR(250) NOT NULL,
-    filename                VARCHAR(250) NOT NULL,
-    public_access           ENUM('none', 'metadata', 'full') NOT NULL,
-
-    FOREIGN KEY(ethnic_group_id) REFERENCES ethnic_groups (id),
-    FOREIGN KEY(collection_id) REFERENCES media_collections (id),
-    FOREIGN KEY(vernacular_style_id) REFERENCES vernacular_styles (id),
-    FOREIGN KEY(location_name) REFERENCES locations (name),
-    FOREIGN KEY(copied_from_item_id) REFERENCES media_items (id),
-    FOREIGN KEY(generic_style_id) REFERENCES generic_styles (id)
-);
-
---
--- Parties d'item/marqueurs
---
-
-CREATE TABLE media_parts (
-    id                      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
-    item_id                 INTEGER NOT NULL,
-    title                   VARCHAR(250) NOT NULL,
-    start                   FLOAT NOT NULL,
-    end                     FLOAT NOT NULL,
-
-    FOREIGN KEY(item_id) REFERENCES media_items (id)
-);
-
---
--- Instruments et formations
---
-
-CREATE TABLE instruments (
-    id      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
-    name    VARCHAR(250) NOT NULL
-);
-
-CREATE TABLE instrument_relations (
-    instrument_id           INTEGER NOT NULL, 
-    parent_instrument_id    INTEGER NOT NULL,
-
-    FOREIGN KEY(instrument_id)          REFERENCES instruments (id),
-    FOREIGN KEY(parent_instrument_id)   REFERENCES instruments (id)
-);
-
-CREATE TABLE instrument_aliases (
-    id      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
-    name    VARCHAR(250) NOT NULL
-);
-
-CREATE TABLE instrument_alias_relations (
-    alias_id                INTEGER NOT NULL, 
-    instrument_id           INTEGER NOT NULL,
-
-    FOREIGN KEY(alias_id)       REFERENCES instrument_aliases (id),
-    FOREIGN KEY(instrument_id)  REFERENCES instruments (id)
-);
-
-CREATE TABLE media_item_performances (
-    media_item_id           INTEGER NOT NULL,
-    instrument_id           INTEGER NOT NULL,
-    alias_id                INTEGER NOT NULL, 
-    instruments_num         VARCHAR(250) NOT NULL,
-    musicians               VARCHAR(250) NOT NULL,
-
-    FOREIGN KEY(media_item_id)  REFERENCES media_items (id),
-    FOREIGN KEY(instrument_id)  REFERENCES instruments (id),
-    FOREIGN KEY(alias_id)       REFERENCES instrument_aliases (id)
-);
-
---
--- Contexte ethnographique
---
-
-CREATE TABLE context_keywords (
-    id      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
-    value   VARCHAR(250) NOT NULL
-);
-
-CREATE TABLE media_item_keywords (
-    item_id     INTEGER NOT NULL,
-    keyword_id  INTEGER NOT NULL,
-
-    PRIMARY KEY(item_id, keyword_id),
-    FOREIGN KEY(item_id) REFERENCES media_items (id),
-    FOREIGN KEY(keyword_id) REFERENCES context_keywords (id)
-);
-
---
--- Utilisateurs
---
-
-CREATE TABLE users (
-    username    VARCHAR(64) NOT NULL PRIMARY KEY,
-    level       ENUM ('user', 'maintainer', 'admin') NOT NULL,
-    first_name  VARCHAR(250) NOT NULL,
-    last_name   VARCHAR(250) NOT NULL,
-    phone       VARCHAR(250) NOT NULL,
-    email       VARCHAR(250) NOT NULL
-);
-
---
--- Séléctions
---
-
-CREATE TABLE playlists (
-    id              INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
-    owner_username  VARCHAR(250) NOT NULL,
-    name            VARCHAR(250) NOT NULL,
-
-    FOREIGN KEY(owner_username) REFERENCES users (username)
-);
-
-CREATE TABLE playlist_resources (
-    playlist_id     INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
-    resource_type   ENUM('item', 'collection') NOT NULL,
-    resource_id     INTEGER NOT NULL,
-
-    FOREIGN KEY(playlist_id) REFERENCES playlists (id)
-);
-
-
---
--- Historique des modifications
---
-
-CREATE TABLE revisions (
-    id              INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
-    element_type    VARCHAR(32) NOT NULL,
-    element_id      INTEGER NOT NULL,
-    change_type     ENUM('create', 'update', 'delete') NOT NULL,
-    time            DATETIME NOT NULL,
-    username        VARCHAR(64) NOT NULL,
-
-    FOREIGN KEY(username) REFERENCES users (username)
-);
-
diff --git a/docref/crem.zargo b/docref/crem.zargo
deleted file mode 100644 (file)
index 4f7b7e8..0000000
Binary files a/docref/crem.zargo and /dev/null differ
diff --git a/docref/docref-0.1-prealpha.odt b/docref/docref-0.1-prealpha.odt
deleted file mode 100644 (file)
index 4c8a8df..0000000
Binary files a/docref/docref-0.1-prealpha.odt and /dev/null differ
diff --git a/docref/docref-0.2-prealpha.odt b/docref/docref-0.2-prealpha.odt
deleted file mode 100644 (file)
index 79cba1f..0000000
Binary files a/docref/docref-0.2-prealpha.odt and /dev/null differ
diff --git a/docref/docref-0.3-alpha.odt b/docref/docref-0.3-alpha.odt
deleted file mode 100644 (file)
index 4295755..0000000
Binary files a/docref/docref-0.3-alpha.odt and /dev/null differ
diff --git a/docref/docref-0.4-beta.odt b/docref/docref-0.4-beta.odt
deleted file mode 100644 (file)
index f043e96..0000000
Binary files a/docref/docref-0.4-beta.odt and /dev/null differ
diff --git a/docref/docref.odt b/docref/docref.odt
deleted file mode 100644 (file)
index 5e96532..0000000
Binary files a/docref/docref.odt and /dev/null differ
diff --git a/docref/spec/build.sh b/docref/spec/build.sh
deleted file mode 100644 (file)
index 14af7e3..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/bash
-
-python parse.py
-cd build
-rst2html docref.txt docref.html && rst2latex docref.txt docref.tex && pdflatex docref.tex
-
diff --git a/docref/spec/docref.txt b/docref/spec/docref.txt
deleted file mode 100644 (file)
index 48bb608..0000000
+++ /dev/null
@@ -1,223 +0,0 @@
-
-
-===================================================================
-Recommandations pour la réorganisation de la base de donnée du CREM
-===================================================================
-------------------------------------
-Document de référence, version alpha
-------------------------------------
-
-
-I - Enjeux
-==========
-
-I.1 - Recherche d'informations
-------------------------------
-
-L'analyse de la structure de données et la rencontre des personnes concernées par son usage
-permettent de délimiter des enjeux majeurs. Il apparaît notamment que le fond documentaire
-que constitue cette base n'est actuellement pas mis à profit comme il pourrait l'être. Cette
-base est largement sous-utilisée, les chercheurs, pour certains, ne l'utilisent pas du tout.
-
-La raison principale de cette situation est le fait que l'environnement technique et la
-structure de la base ont été conçus pour s'inscrire dans un environnement documentaire
-traditionnel, qui implique généralement de prendre contact avec un documentaliste pour effectuer
-une recherche. Le documentaliste est un spécialiste de la base, il possède les connaissances
-techniques nécessaires à sa consultation.
-
-Mais à l'heure d'Internet, ce processus de recherche est trop lourd et inadapté, en un mot
-: obsolète. Les chercheurs lui préfèrent d'autres fonds documentaires accessibles en ligne,
-de façon immédiate, et équipés d'outils de recherche puissants et ergonomiques.
-
-L'enjeu principal de la réorganisation de la base du CREM consiste donc à : sous-tendre le
-développement d'un outil moderne de gestion et de consultation en ligne, avec des fonctions
-de recherche puissantes et intuitives déterminer et améliorer les données de la base qui
-sont prioritaires pour la recherche d'information
-
-En de-ça des-dits champs prioritaires, il existe un grand nombre d'information techniques de
-second ordre, qui soit ne sont utiles qu'aux documentalistes, soit ne présentent pas d'intérêt
-majeur pour la recherche d'information. Ces informations peuvent être conservées telles quelles,
-sans grand effort de réorganisation, et resteront ainsi disponibles lors de la consultation
-individuelle des fiches.
-
-En procédant de cette façon, c'est à dire en délimitant les-dîtes priorités, il semble
-possible de dégager une véritable plus-value, de rendre le fond documentaire du CREM plus vivant,
-sans pour autant engager des moyens démesurés dans la réorganisation de la base de donnée.
-
-I.2 - Gestion et mise à jour des données
-----------------------------------------
-
-Il est entendu qu'au delà de la consultation d'information, il s'agit également de faciliter
-la gestion des données, leur mise à jour. Cette question implique pour une large part des
-problématiques d'ordre ergonomique, liées au développement d'un outil logiciel autour de la
-base, ce qui n'entre pas dans le cadre de la réorganisation de la base de données.
-
-Cependant, au niveau de la base, certains choix sont structurant. Par exemple l'emploi d'une
-liste hiérarchisée de lieux telle que le Thesaurus of Geographical Names (TGN, recommandé par
-Dublin Core), permet, en choisissant une région, une sous-région ou un village, de renseigner
-automatiquement le pays (et les autres zones géographiques intermédiaires), ce qui diminue
-l'effort et prévient les erreurs de saisie.
-
-Pour un grand nombre de champs, l'emploi d'énumérations (liste de valeurs valides pour
-un champ donné) facilite et valide déjà la mise à jour des données. Cet aspect de la base
-devra être conservé.
-
-Cependant, il semble que l'enjeu majeur de la réorganisation, du point de vue de la gestion
-des données, est de permettre un travail collaboratif, entre chercheurs et documentalistes. C'est
-là, d'une manière générale, ce qui permet sur Internet de rendre un fond documentaire vivant.
-
-Dans le cadre du CREM, il serait ainsi idéal d'amener les chercheurs à alimenter la base de
-façon autonome, en sus des documentalistes dont c'est le métier. Ce serait là une véritable
-nouveauté, représentant un fort potentiel d'enrichissement des données.
-
-D'une façon générale, une application en ligne ("webifiée") bien conçue se prête
-très bien au travail collaboratif. Cependant, il semble que dans notre cas, les potentielles
-contributions des chercheurs se heurtent à une question importante de confidentialité et
-de propriété intellectuelle. Des cas ont en effet été rapportés d'usage détournés du
-fruit du travail du centre de recherche, et d'une manière générale, il semble qu'il faille
-observer une grande prudence pour la mise en commun d'enregistrement sonores et autres données,
-qui représentent une matière précieuse aux yeux des chercheurs.
-
-La sécurité informatique est pour une large part distinct de la base de donnée ; elle
-implique des efforts particuliers au niveau du développement applicatif, et de l'administration
-de l'infrastructure réseau.
-
-Cependant, au niveau de la base de donnée, il est possible de mettre l'accent sur la
-propriété des données. Chaque ressource (collection, item) peut en effet se voir attribuer
-un propriétaire. Le dit propriétaire devrait ensuite pouvoir choisir quel autre utilisateur
-et/ou groupe d'utilisateur est autorisé à consulter, écouter, et/ou modifier la ressource.
-
-En rassurant ainsi les chercheurs, il est envisageable que la base s'enrichisse notablement
-par leurs contributions, dont certaines d'abord privées, pourront, à leur guise, devenir
-petit à petit accessibles à un nombre grandissant d'utilisateurs et de groupes de travail.
-
-I.3 - Données prioritaires
-
-Après consultation des différents utilisateurs il apparaît que les meta-données principales
-pour chaque item sont :
-
-* l'identifiant unique de l'item
-* le titre de l'item
-* la zone géographique
-* le nom du collecteur, c'est à dire le chercheur qui a collecté cet enregistrement
-* les instruments de musique utilisés
-* l'année d'enregistrement
-* le contexte ethnographique
-* l'ethnie
-
-Il s'agit d'apporter une attention particulière à celles-ci, notamment en les normalisant,
-pour faciliter la recherche d'informations, mais aussi pour l'ajout et la gestion simplifiés
-d'items.
-
-Les autres données pourront être conservées telles quelles sans grand effort de normalisation.
-
-I.4 - Dublin Core
------------------
-
-...
-
-II - Modalités de conversion/réorganisation de la base
-======================================================
-
-II.1 - Enumérations simples
----------------------------
-
-dynamic:tables.describe_enums()
-
-II.2 - Collections
-------------------
-
-Ancien nom de table : support
-
-Nouveau nom de table : media_collections
-
-II.2.1 - Champs convertis
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-dynamic:tables.media_collections.describe_conversion()
-
-II.2.2 - Nouveaux champs
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-dynamic:tables.media_collections.describe_new_fields()
-
-II.2.3 - Champs supprimés
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-dynamic:tables.media_collections.describe_removed_fields()
-
-II.3 - Items 
-------------
-
-Ancien nom de table : phono
-
-Nouveau nom de table : media_items
-
-II.3.1 - Champs convertis
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-dynamic:tables.media_items.describe_conversion()
-
-II.3.2 - Nouveaux champs
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-dynamic:tables.media_items.describe_new_fields()
-
-II.3.3 - Champs supprimés
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-dynamic:tables.media_items.describe_removed_fields()
-
-II.4 - Sélections 
------------------
-
-II.4.1 - Liste
-~~~~~~~~~~~~~~
-
-Nom de table:
-dynamic:tables.media_playlists.name
-
-dynamic:tables.media_playlists.describe_new_fields()
-
-II.4.2 - Table de relation interne
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Nom de table:
-dynamic:tables.media_playlist_resources.name
-
-dynamic:tables.media_playlist_resources.describe_new_fields()
-
-II.5 - Thesaurus Géographique
------------------------------
-
-II.5.1 - Lieux
-~~~~~~~~~~~~~~
-
-Nom de table:
-dynamic:tables.locations.name
-
-dynamic:tables.locations.describe_new_fields()
-
-II.5.2 - Alias des lieux
-~~~~~~~~~~~~~~~~~~~~~~~~
-
-Nom de table:
-dynamic:tables.location_aliases.name
-
-dynamic:tables.location_aliases.describe_new_fields()
-
-II.5.3 - Relations hiérarchiques
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Nom de table:
-dynamic:tables.location_relations.name
-
-dynamic:tables.location_relations.describe_new_fields()
-
-II.6 - Utilisateurs
--------------------
-
-Nom de table: 
-dynamic:tables.users.name
-
-dynamic:tables.users.describe_new_fields()
diff --git a/docref/spec/elements.py b/docref/spec/elements.py
deleted file mode 100644 (file)
index e46b8d7..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-#coding: utf-8
-import sqlalchemy
-import texttable
-
-def make_table(rows, width=20):
-    return texttable.indent(rows, hasHeader = True, separateRows = True,
-        prefix=u'| ', postfix=u' |',
-        wrapfunc = lambda x: texttable.wrap_onspace(x, width=width))
-        
-def describe_enums(metadata):
-    rows = [['Nom interne', 'Ancien nom', 'Description']]
-    for enum in metadata.enums:
-        rows.append([enum.name, enum.old_name, enum.label])
-    return make_table(rows, 40)
-
-class Column(sqlalchemy.Column):
-    old_name = ''
-    label = ''
-    desc = ''
-    dc = ''
-    comment = ''
-    conversion = ''
-    enum = None
-
-    def __init__(self, name, type, *args, **kwargs):
-        parent_args = {}
-        for key, value in kwargs.items():
-            if key == 'old_name':
-                if isinstance(value, list):
-                    self.old_name = unicode(",\n".join(value), 'utf-8')
-                    #self.old_name = []
-                    #for item in value:
-                    #    self.old_name.append(unicode(item, 'utf-8'))
-                else:
-                    self.old_name = unicode(value, 'utf-8')
-            elif key == 'label':
-                self.label = unicode(value, 'utf-8')
-            elif key == 'desc':
-                self.desc = unicode(value, 'utf-8')
-            elif key == 'dc':
-                self.dc = value
-            elif key == 'comment':
-                self.comment = unicode(value, 'utf-8')
-            elif key == 'conversion':
-                self.conversion = unicode(value, 'utf-8')
-            else:
-                parent_args[key] = value
-        
-        if isinstance(type, Enumeration):
-            args = (sqlalchemy.ForeignKey(type.name + '.id'),) + args
-            self.enum = type
-            type = sqlalchemy.Integer
-
-        super(Column, self).__init__(name, type, *args, **parent_args)
-
-class RemovedColumn(object):
-    old_name = ''
-    comment = ''
-
-    def __init__(self, old_name, comment=''):
-        self.old_name = unicode(old_name, 'utf-8')
-        self.comment = unicode(comment, 'utf-8')
-
-class Table(sqlalchemy.Table):
-
-    def __init__(self, table_name, metadata, label, *args):
-        self.label = unicode(label, 'utf-8')
-        real_columns = []
-        self.removed_columns = []
-        for column in args:
-            if isinstance(column, RemovedColumn):
-                self.removed_columns.append(column)
-            else:
-                real_columns.append(column)
-        super(Table, self).__init__(table_name, metadata, *real_columns) 
-
-
-    def describe_new_fields(self):
-        rows = [['Nom', 'Nom interne', 'Dublin Core']]
-        for column in self.columns:
-            if not column.old_name:
-                rows.append([column.label, column.name, column.dc])
-        
-        return make_table(rows)
-
-    def describe_conversion(self):        
-        rows = [['Nouveau nom', 'Ancien nom', 'Nouveau nom interne', 'Dublin Core']]
-        for column in self.columns:
-            if column.old_name:
-                rows.append([column.label, column.old_name, column.name, column.dc])
-        
-        return make_table(rows)
-            
-    def describe_removed_fields(self):        
-        rows = [['Nom', 'Commentaire']]
-        for column in self.removed_columns:
-            rows.append([column.old_name, column.comment])
-        
-        return make_table(rows, 50)
-
-    def to_dot(self):
-        dot  = u'digraph g {\n'
-        dot += '  charset = "utf-8";\n'
-        dot += '  node [shape=record, charset="utf-8"];\n'
-        dot += '  rankdir = LR;\n'
-        dot += '  subgraph cluster_new_fields {\n'
-        dot += '    label = "Nouveaux champs";\n'
-        dot += '    color = black;\n'
-        old_fields = ''
-        conversion = ''
-        for column in self.columns:
-            dot += '    ' + column.name + '[label = "{' + column.label + ' | ' + column.name + '}"];\n'
-            if column.old_name:
-                old_fields += '    old_' + column.name + '[label = "' + column.old_name  + '"];\n'
-                conversion += '  old_' + column.name + ' -> ' + column.name + ';\n'
-        dot += '  }\n'            
-        dot += '  subgraph cluster_old_fields {\n'
-        dot += '    label = "Anciens champs";\n'
-        dot += '    color = black;\n'
-        dot += old_fields
-        dot += '  }\n'            
-        dot += conversion
-        dot += '}\n'            
-        return dot            
-
-class Enumeration(Table):
-
-    def __init__(self, name, metadata, label='', old_name=''):
-        self.old_name = unicode(old_name, 'utf-8')
-        if not hasattr(metadata, 'enums'):
-            metadata.enums = []
-        metadata.enums.append(self)
-        super(Enumeration, self).__init__(name, metadata, label,
-            Column('id', sqlalchemy.Integer, primary_key=True),
-            Column('value', sqlalchemy.String(250), unique=True)
-        )
diff --git a/docref/spec/parse.py b/docref/spec/parse.py
deleted file mode 100644 (file)
index 535832c..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-
-import tables
-import codecs
-input = codecs.open('docref.txt', 'r', "utf-8")
-output = codecs.open('build/docref.txt', 'w', "iso-8859-1")
-
-for line in input:
-    if line[0:8] == 'dynamic:':
-        output.write(eval(line[8:], globals(), locals()) + "\n")
-    else:
-        output.write(line)
-
-input.close()
-output.close()
-
-output = codecs.open('build/collections.dot', 'w', 'utf-8')
-output.write(tables.media_collections.to_dot())
-output.close()
diff --git a/docref/spec/staticenum.py b/docref/spec/staticenum.py
deleted file mode 100644 (file)
index d364f5b..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-#!python\r
-\r
-## The MIT License\r
-\r
-## Copyright (c) <year> <copyright holders>\r
-\r
-## Permission is hereby granted, free of charge, to any person obtaining a copy\r
-## of this software and associated documentation files (the "Software"), to deal\r
-## in the Software without restriction, including without limitation the rights\r
-## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
-## copies of the Software, and to permit persons to whom the Software is\r
-## furnished to do so, subject to the following conditions:\r
-\r
-## The above copyright notice and this permission notice shall be included in\r
-## all copies or substantial portions of the Software.\r
-\r
-## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
-## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
-## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
-## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
-## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
-## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r
-## THE SOFTWARE.\r
-\r
-\r
-from sqlalchemy import types, exceptions\r
-\r
-class StaticEnum(types.TypeDecorator):\r
-    impl = types.Unicode\r
-    \r
-    def __init__(self, values, empty_to_none=False, strict=False):\r
-        """Emulate an Enum type.\r
-\r
-        values:\r
-           A list of valid values for this column\r
-        empty_to_none:\r
-           Optional, treat the empty string '' as None\r
-        strict:\r
-           Also insist that columns read from the database are in the\r
-           list of valid values.  Note that, with strict=True, you won't\r
-           be able to clean out bad data from the database through your\r
-           code.\r
-        """\r
-\r
-        if values is None or len(values) is 0:\r
-            raise exceptions.AssertionError('StaticEnum requires a list of values')\r
-        self.empty_to_none = empty_to_none\r
-        self.strict = strict\r
-        self.values = values[:]\r
-\r
-        # The length of the string/unicode column should be the longest string\r
-        # in values\r
-        size = max([len(v) for v in values if v is not None])\r
-        super(StaticEnum, self).__init__(size)        \r
-        \r
-        \r
-    def convert_bind_param(self, value, engine):\r
-        if self.empty_to_none and value is '':\r
-            value = None\r
-        if value not in self.values:\r
-            raise exceptions.AssertionError('"%s" not in StaticEnum.values' % value)\r
-        return super(StaticEnum, self).convert_bind_param(value, engine)\r
-        \r
-        \r
-    def convert_result_value(self, value, engine):\r
-        if self.strict and value not in self.values:\r
-            raise exceptions.AssertionError('"%s" not in StaticEnum.values' % value)\r
-        return super(StaticEnum, self).convert_result_value(value, engine)\r
-\r
diff --git a/docref/spec/tables.py b/docref/spec/tables.py
deleted file mode 100644 (file)
index 41fd6d4..0000000
+++ /dev/null
@@ -1,331 +0,0 @@
-#coding: utf-8
-
-import sqlalchemy
-from sqlalchemy import String, Integer, ForeignKey, Time, Date, MetaData, Text, Boolean
-from elements import Column, RemovedColumn, Table, Enumeration
-import elements
-from staticenum import StaticEnum
-
-metadata = MetaData()
-def describe_enums():
-    return elements.describe_enums(metadata)
-
-# Users
-
-users = Table('users', metadata, 'Utilisateurs',
-    Column('username', String(250), primary_key=True, label='Nom d\'utilisateur'),
-    Column('level', StaticEnum('user,maintainer,administrator'), label='Niveau de permissions'),
-    Column('first_name', String(250), label='Prénom'),
-    Column('last_name', String(250), label='Nom'),
-    Column('phone', String(250), label='Téléphone'),
-    Column('email', String(250), label='E-Mail')
-)    
-
-# Playlists
-
-media_playlists = Table('playlists', metadata, 'Sélections personelles d\'items et de collections',
-    Column('id', Integer, primary_key='true', label='Identifiant'),
-    Column('owner_username', String(250), ForeignKey('users.username'), label='Propriétaire'),
-    Column('name', String(250), label='Intitulé'))
-
-media_playlist_resources = Table('playlist_resources', metadata, 'Ressources associées aux sélections personelles ',
-    Column('playlist_id', Integer, ForeignKey('playlists.id'), label='Identifiant de la sélection'),
-    Column('resource_type', StaticEnum('item', 'collection'), label='Type de ressource (item, collection)'),
-    Column('resource_id', String(250), label='Identifiant de la ressource')
-)
-
-# Simple enumerations
-
-physical_formats = Enumeration('physical_formats', metadata, 'Formats physiques', old_name='Format (e)')
-publishing_status = Enumeration('publishing_status', metadata, 'Status d\'édition/réédition', old_name='Réédition (e)')
-publishers = Enumeration('publishers', metadata, 'Editeurs', old_name='Editeur1 (e)')
-acquisition_modes = Enumeration('acquisition_modes', metadata, 'Modes d\'acquisition', old_name='Mode_Acqui (e)')
-metadata_authors = Enumeration('record_authors', metadata, 'Rédacteurs des fiches', old_name='Rédacteur_Fiche (e)')
-metadata_writers = Enumeration('metadata_writers', metadata, 'Opérateur de saisie des fiches', old_name='Saisie_Fiche (e)')
-legal_rights = Enumeration('legal_rights', metadata, 'Statuts juridiques', old_name='Droit_d\'Utiliser (e)')
-recording_contexts = Enumeration('recording_contexts', metadata, 'Contextes d\'enregistrement', old_name='Terrain_ou_Autre (e)')
-ad_conversions = Enumeration('ad_conversions', metadata, 'Statuts de numérisation', old_name='Numérisation (e)')
-ethnic_groups = Enumeration('ethnic_groups', metadata, 'Ethnies/Groupe social', old_name='Ethnie (t)')
-vernacular_styles = Enumeration('vernacular_styles', metadata, 'Forme / genre vernaculaire', old_name='Form (t)')
-generic_styles = Enumeration('generic_styles', metadata, 'Forme / genre générique', old_name='FormStyle générique (e)')
-context_keywords = Enumeration('context_keywords', metadata, 'Mots clés du contexte ethnographique', old_name='Mot_Clef (t)')
-publisher_collections = Enumeration('publisher_collections', metadata, 'Collections éditeur', old_name='Collection_Série (e)')
-
-# Geographic Thesaurus
-
-location_types = Enumeration('location_types', metadata, 'GeoEthno / Types de lieux')
-
-locations = Table('locations', metadata, 'GeoEthno / Lieux)',
-    Column('name', String(127), primary_key=True, label='Terme descripteur'),
-    Column('type', StaticEnum('country', 'continent', 'other')),
-    Column('complete_type', location_types),
-    Column('current_name', String(127), ForeignKey('locations.name'), label='Nom actuel'),
-    Column('is_authoritative', Boolean),
-)
-
-location_aliases = Table('location_aliases', metadata, 'GeoEthno / Alias des lieux',
-    Column('location_name', String(127), ForeignKey('locations.name'), primary_key=True),
-    Column('alias', String(127), primary_key=True),
-    Column('is_authoritative', Boolean))
-
-location_relations = Table('location_relations', metadata, 'GeoEthno / Relations hiérachiques',
-    Column('location_name', String(127), ForeignKey('locations.name'), primary_key=True),
-    Column('parent_location_name', String(127), ForeignKey('locations.name'), primary_key=True)
-)    
-
-# Media Collections
-
-media_collections = Table('media_collections', metadata, 'Collections',
-    Column('reference', 
-        String(250), unique=True, 
-        old_name='Réf', label='Référence'),
-    Column('physical_format_id', 
-        physical_formats,
-        old_name='Format', label='Format', 
-        desc="Format du 1er exemplaire archivé"),
-    Column('old_id', 
-        String(250), 
-        old_name='Cote', label='Ancienne cote'),
-    Column('id', 
-        String(250), primary_key=True, 
-        dc='identifier',
-        label='Cote', conversion='à préciser'),
-    Column('title', 
-        String(250), 
-        dc='title',
-        old_name='Titre', label='Titre'),
-    Column('native_title', 
-        String(250), 
-        dc='title',
-        old_name='Transcrip_Trad', label='Traduction du titre'),
-    Column('physical_items_num', 
-        Integer, 
-        old_name='Nb_de_pieces', label='Nombre de supports physiques'),
-    Column('publishing_status_id', 
-        publishing_status,
-        old_name='Réédition', label='Réédition'),
-    RemovedColumn(old_name='Original'),
-    RemovedColumn(old_name='Copie_TotPartie'),
-    RemovedColumn(old_name='Copié_de'),
-    Column('creator', 
-        String(250), 
-        dc='creator',
-        old_name='Auteur_Compil', label='Auteur / Cédant'),
-    Column('booklet_author', 
-        String(250),
-        dc='contributor',
-        old_name='Auteur_Notice', label='Auteur notice'),
-    Column('booklet_description', 
-        Text, 
-        old_name='Notice', label='Notice / Dossier technique'),
-    Column('collector',
-        Text, 
-        dc='contributor',
-        old_name='Collecteur', label='Collecteur'),
-    Column('publisher_id', 
-        publishers,
-        dc='publisher',
-        old_name='Editeur', label='Editeur', 
-        desc='Pour les documents ÉDITÉS:Nom et État de l\'Editeur. Pour les INÉDITS :voir champ "Type de document".'),
-    Column('year_published', 
-        Integer,
-        dc='date',
-        old_name='Année_parution', label='Année de parution',
-        desc='Ne concerne que les documents ÉDITÉS.',
-        conversion='à préciser, traiter les nombres négatifs ?'),
-    Column('publisher_collection', 
-        publisher_collections,
-        old_name='Collect_Série', label='Collection éditeur',
-        comment='faux: nom de la collection, suivi du n° dans la collection.'),
-    Column('publisher_serial',
-        String(250),
-        old_name='Num_Dans_Collec', label='Numéro de série',
-        desc='Numéro de série dans la collection éditeur', 
-        comment='à valider'),
-    Column('external_references', 
-        Text,
-        old_name='Réf_Biblio', label='Bibliographie', 
-        desc='Références biblio/disco/filmographiques, uniquement liées à ce support'),
-    Column('acquisition_mode_id',
-        acquisition_modes,
-        old_name='Mod_Acqui', label='Mode d\'acquisition'),
-    Column('comment',
-        Text,
-        old_name='Commentaire', label='Commentaire'),
-    Column('metadata_author_id', 
-        metadata_authors,
-        dc='contributor',
-        old_name='Rédacteur_Fiche', label='Rédacteur fiche',
-        desc='Responsable de l\'analyse documentaire'),
-    Column('metadata_writer_id',
-        metadata_writers,
-        old_name='Saisie_Fiche', label='Saisie fiches',
-        desc='Personne qui a saisi les fiches dans la base de données.'),
-    Column('legal_rights_id',
-        legal_rights,
-        dc='rights',
-        old_name='Droit_Utiliser', label='Statut juridique'),
-    Column('alt_ids', 
-        String(250),
-        old_name='Autres_Cotes', label='Autres exemplaires'),
-    Column('recorded_from_year',
-        Integer,
-        dc='date',
-        old_name='Année_Enreg', label='Années d\'enregistrement',
-        conversion="split"),
-    Column('recorded_to_year',
-        Integer,
-        dc='date',
-        old_name='Année_Enreg', label='Années d\'enregistrement',
-        conversion="split"),
-    Column('recording_context_id',
-        recording_contexts, 
-        old_name='Terrain_ou_Autr', label='Contexte d\'enregistrement'),
-    Column('approx_duration', 
-        Time(),
-        old_name='Durée_approx', label='Durée approximative'),
-    Column('doctype_code', 
-        Integer,
-        old_name='Tri_DiBm', label='Type de document'), 
-    Column('travail', 
-        String(250),
-        old_name='Travail', label='?'), 
-    Column('state',
-        String(250),
-        old_name='Compil_Face_Plage', label="Etat"),
-    Column('cnrs_contributor',
-        String(250),
-        old_name='Déposant_CNRS', label="Déposant CNRS",
-        desc='Pour les INÉDITS uniquement. Signale les collectes ayant bénéficées d\'une aide du CNRS.'), 
-    Column('items_done',
-        String(250),
-        old_name='Fiches', label='Fiches faîtes', 
-        desc="Signale que les fiches Item de ce support sont présentes dans la base."),
-    Column('a_informer_07_03',
-        String(250),
-        old_name='A informer_07-03', label='?'), 
-    Column('ad_conversion_id',
-        ad_conversions,
-        old_name='Numérisation', label="Historique de numérisation"),
-    RemovedColumn(old_name='Champ36'),
-)
-
-# Media Items
-
-media_item_context_keywords = Table('media_item_context_keywords', metadata, 
-    'Mots clés associés à un item',
-    Column('media_item_id', Integer, ForeignKey('media_items.id')),
-    Column('context_keyword_id', context_keywords))
-
-media_items = Table('media_items', metadata, 'Items',
-    RemovedColumn(old_name='Réf', comment='Calculé en temps réel à partir de la collection'),
-    Column('collection_id', 
-        String(250), ForeignKey('media_collections.id'), 
-        dc='relation/isPartOf',
-        label='Collection'),
-    RemovedColumn(old_name='Format', comment='Calculé en temps réel à partir de la collection'),
-    RemovedColumn(old_name='Cote_Support', comment='Calculé en temps réel à partir de la collection'),
-    Column('track',
-        String(250),
-        old_name="Face_Plage", label="N° de l'item"),
-    Column('id', 
-        String(250),
-        old_name='Cote_Phono', label="Cote item"),
-    Column('approx_duration', 
-        Time(),
-        old_name='Durée', label='Durée'),
-    Column('recorded_from_date',
-        Date(),
-        dc='date',
-        old_name='Date_enregistr', label='Date', desc='Date de l\'enregistrement'),
-    Column('recorded_to_date',
-        Date(),
-        dc='date',
-        old_name='Date_enregistr', label='Date'),
-    Column('location_name',
-        Integer, ForeignKey('locations.name'),
-        dc='coverage',
-        old_name=['Continent', 'Etat', 'Région_Village'], label='Lieu',
-        desc='(?) Lieu de provenance de la  musique. Si le lieu de l\'enregistrement est autre, l\'indiquer en "Remarques".'),
-    Column('location_comment',
-        String(250),
-        old_name='Région_Village', label='Commentaire lieu'),
-    Column('ethnic_group_id',
-        ethnic_groups,
-        old_name='Ethnie_GrSocial', label='Ethnie/Groupe social', comment='attention alias ethnies'),
-    RemovedColumn(old_name='Titre_Support', comment='Calculé en temps réel à partir de la collection'),
-    Column('title', 
-        String(250),
-        dc='title', 
-        old_name='Titre_pièce', label='Titre Item'),
-    Column('native_title', 
-        String(250),
-        dc='title', 
-        old_name='Transcrip_Trad', label='Traduction du titre', 
-        desc='Traduction des langues non communes, plus translittération des langues n\'utilisant pas l\'alphabet latin.'),
-    Column('author',
-        String(250),
-        dc='creator',
-        old_name='Auteur', label='Auteur',
-        desc='Le cas échéant, faire suivre le nom par une mention "-auteur /-compositeur / -arrangeur"'),
-    Column('vernacular_style_id',
-        vernacular_styles,
-        old_name='Form_Genr_Style', label='Forme / genre vernaculaire [nom à revoir]', 
-        desc='Nom local de la forme ou du genre'),
-    RemovedColumn(old_name='Struct_Modale'),        
-    RemovedColumn(old_name='Struct_Rythm'), 
-    RemovedColumn(old_name='Struct_Rythm'), 
-    RemovedColumn(old_name='Fonction_Usage', 
-        comment='Champ inutile, les mots clés sont associés via une table de relation externe'), 
-    Column('context_comment',
-        Text,
-        old_name='Comm_FonctUsage', label='Contexte ethnographique : commentaires'),
-    Column('external_references', 
-        String(250),
-        old_name='Documentation', label='Références', 
-        desc='Références directement liées à l\'item.'),
-    Column('moda_execut', 
-        String(250),
-        old_name='Moda_Execut', comment='à supprimer ?'),
-    Column('copied_from_item_id',
-        String(250), ForeignKey('media_items.id'),
-        dc='relation/isVersionOf',
-        old_name='Copie_de', label='Copie de'),
-    Column('collector',
-        String(250),
-        dc='contributor',
-        old_name='Enregistré_par', label='Collecteur'),
-    Column('cultural_area',
-        String(250),
-        old_name='Aire culturelle', label='Aire culturelle'),
-    RemovedColumn(old_name='Année_Enreg', 
-        comment='calculé en temps-réel à partir de la date d\'enregistrement'),
-    Column('generic_style',
-        generic_styles,
-        old_name='FormStyl généri', label='Forme / genre générique'),
-    Column('collector_selection',
-        String(250),
-        old_name='ChoixCollecteur', label='Choix du collecteur', 
-        desc='Permet au collecteur de repérer les items les plus intéressants'),
-    RemovedColumn(old_name='Repère_bande'),        
-    Column('creator_reference', 
-        String(250),
-        old_name='NroBandNroPièc', label='Référence du déposant'),    
-)                        
-                
-
-            
-            
-            
-            
-            
-
-            
-
-            
-    
-
-        
-
-
-
diff --git a/docref/spec/texttable.py b/docref/spec/texttable.py
deleted file mode 100644 (file)
index 3d07d25..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-#coding: utf-8
-import cStringIO,operator
-
-def indent(rows, hasHeader=False, headerChar=u'-', delim=u' | ', justify=u'left',
-           separateRows=False, prefix=u'', postfix=u'', wrapfunc=lambda x:x):
-    """Indents a table by column.
-       - rows: A sequence of sequences of items, one sequence per row.
-       - hasHeader: True if the first row consists of the columns' names.
-       - headerChar: Character to be used for the row separator line
-         (if hasHeader==True or separateRows==True).
-       - delim: The column delimiter.
-       - justify: Determines how are data justified in their column. 
-         Valid values are 'left','right' and 'center'.
-       - separateRows: True if rows are to be separated by a line
-         of 'headerChar's.
-       - prefix: A string prepended to each printed row.
-       - postfix: A string appended to each printed row.
-       - wrapfunc: A function f(text) for wrapping text; each element in
-         the table is first wrapped by this function."""
-    # closure for breaking logical rows to physical, using wrapfunc
-    def rowWrapper(row):
-        newRows = [wrapfunc(item).split('\n') for item in row]
-        return [[substr or '' for substr in item] for item in map(None,*newRows)]
-    # break each logical row into one or more physical ones
-    logicalRows = [rowWrapper(row) for row in rows]
-    # columns of physical rows
-    columns = map(None,*reduce(operator.add,logicalRows))
-    # get the maximum of each column by the string length of its items
-    maxWidths = [max([len(item) for item in column]) for column in columns]
-    rowSeparator = u"+" + u"+".join([u'-' * (width + len(delim) - 1) for width in maxWidths]) + u"+"
-    headerSep = u"+" + u"+".join([u'=' * (width + len(delim) - 1) for width in maxWidths]) + u"+"
-    #headerChar * (len(prefix) + len(postfix) + sum(maxWidths) + \
-    #                             len(delim)*(len(maxWidths)-1))
-    #headerSep = u"=" * (len(prefix) + len(postfix) + sum(maxWidths) + \
-    #                             len(delim)*(len(maxWidths)-1))                                
-    # select the appropriate justify method
-    #justify = {'center':str.center, 'right':str.rjust, 'left':str.ljust}[justify.lower()]
-    output=u''
-    if separateRows: 
-        output += rowSeparator + "\n"
-
-    for physicalRows in logicalRows:
-        for row in physicalRows:
-            output += \
-                prefix \
-                + delim.join([item.ljust(width) for (item,width) in zip(row,maxWidths)]) \
-                + postfix + "\n"
-        if hasHeader: output += headerSep + "\n"; hasHeader=False
-        elif separateRows: output += rowSeparator + "\n"
-    return output
-
-# written by Mike Brown
-# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/148061
-def wrap_onspace(text, width):
-    """
-    A word-wrap function that preserves existing line breaks
-    and most spaces in the text. Expects that existing line
-    breaks are posix newlines (\n).
-    """
-    return reduce(lambda line, word, width=width: '%s%s%s' %
-                  (line,
-                   ' \n'[(len(line[line.rfind('\n')+1:])
-                         + len(word.split('\n',1)[0]
-                              ) >= width)],
-                   word),
-                  text.split(' ')
-                 )
-
-import re
-def wrap_onspace_strict(text, width):
-    """Similar to wrap_onspace, but enforces the width constraint:
-       words longer than width are split."""
-    wordRegex = re.compile(r'\S{'+str(width)+r',}')
-    return wrap_onspace(wordRegex.sub(lambda m: wrap_always(m.group(),width),text),width)
-
-import math
-def wrap_always(text, width):
-    """A simple word-wrap function that wraps text on exactly width characters.
-       It doesn't split the text in words."""
-    return '\n'.join([ text[width*i:width*(i+1)] \
-                       for i in xrange(int(math.ceil(1.*len(text)/width))) ])
-    
-if __name__ == '__main__':
-    labels = ('First Name', 'Last Name', 'Age', 'Position')
-    data = \
-    '''John,Smith,24,Software Engineer
-       Mary,Brohowski,23,Sales Manager
-       Aristidis,Papageorgopoulos,28,Senior Reseacher'''
-    rows = [row.strip().split(',')  for row in data.splitlines()]
-
-    print 'Without wrapping function\n'
-    print indent([labels]+rows, hasHeader=True)
-    # test indent with different wrapping functions
-    width = 10
-    for wrapper in (wrap_always,wrap_onspace,wrap_onspace_strict):
-        print 'Wrapping function: %s(x,width=%d)\n' % (wrapper.__name__,width)
-        print indent([labels]+rows, hasHeader=True, separateRows=True,
-                     prefix='| ', postfix=' |',
-                     wrapfunc=lambda x: wrapper(x,width))
-    
-    # output:
-    #
-    #Without wrapping function
-    #
-    #First Name | Last Name        | Age | Position         
-    #-------------------------------------------------------
-    #John       | Smith            | 24  | Software Engineer
-    #Mary       | Brohowski        | 23  | Sales Manager    
-    #Aristidis  | Papageorgopoulos | 28  | Senior Reseacher 
-    #
-    #Wrapping function: wrap_always(x,width=10)
-    #
-    #----------------------------------------------
-    #| First Name | Last Name  | Age | Position   |
-    #----------------------------------------------
-    #| John       | Smith      | 24  | Software E |
-    #|            |            |     | ngineer    |
-    #----------------------------------------------
-    #| Mary       | Brohowski  | 23  | Sales Mana |
-    #|            |            |     | ger        |
-    #----------------------------------------------
-    #| Aristidis  | Papageorgo | 28  | Senior Res |
-    #|            | poulos     |     | eacher     |
-    #----------------------------------------------
-    #
-    #Wrapping function: wrap_onspace(x,width=10)
-    #
-    #---------------------------------------------------
-    #| First Name | Last Name        | Age | Position  |
-    #---------------------------------------------------
-    #| John       | Smith            | 24  | Software  |
-    #|            |                  |     | Engineer  |
-    #---------------------------------------------------
-    #| Mary       | Brohowski        | 23  | Sales     |
-    #|            |                  |     | Manager   |
-    #---------------------------------------------------
-    #| Aristidis  | Papageorgopoulos | 28  | Senior    |
-    #|            |                  |     | Reseacher |
-    #---------------------------------------------------
-    #
-    #Wrapping function: wrap_onspace_strict(x,width=10)
-    #
-    #---------------------------------------------
-    #| First Name | Last Name  | Age | Position  |
-    #---------------------------------------------
-    #| John       | Smith      | 24  | Software  |
-    #|            |            |     | Engineer  |
-    #---------------------------------------------
-    #| Mary       | Brohowski  | 23  | Sales     |
-    #|            |            |     | Manager   |
-    #---------------------------------------------
-    #| Aristidis  | Papageorgo | 28  | Senior    |
-    #|            | poulos     |     | Reseacher |
-    #---------------------------------------------
-
diff --git a/docref/tools/analyse_collection_ids.py b/docref/tools/analyse_collection_ids.py
deleted file mode 100644 (file)
index d180f55..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-import MySQLdb
-import _mysql_exceptions
-import re
-from sys import stdout
-
-"""
-CREATE TABLE `coll` (
-  `cote` varchar(255) default NULL,
-  `format` varchar(255) default NULL,
-  `regex` varchar(255) default NULL,
-  `new_id` varchar(64) default NULL,
-  `dup` BOOLEAN NOT NULL,
-  UNIQUE KEY `new_id` (`new_id`),
-  UNIQUE KEY `cote` (`cote`)
-)
-"""
-
-
-collection_patterns = [
-    { 'format': 'BM.aaa.nnn.mmm',           'regex': r'^(BM)\.([0-9]{3})\.([0-9]{3})\.([0-9]{3})$'}, 
-    { 'format': 'BM.aaaa.nnn.mmm/pp',       'regex': r'^(BM)\.([0-9]{4})\.([0-9]{3})\.([0-9]{3})/[0-9]{2}$'}, 
-    { 'format': 'BM.aaaa.nnn.mmm',          'regex': r'^(BM)\.([0-9]{4})\.([0-9]{3})\.([0-9]{3})$'}, 
-    { 'format': 'BM.aaaa.nnn.mmm/',         'regex': r'^(BM)\.([0-9]{4})\.([0-9]{3})\.([0-9]{3})/$'}, 
-    { 'format': 'BM.aaaa.nnn.mmm/ppp',      'regex': r'^(BM)\.([0-9]{4})\.([0-9]{3})\.([0-9]{3})/[0-9]{3}$'}, 
-    { 'format': 'BM.aaaa.nnn.mm/pp',        'regex': r'^(BM)\.([0-9]{4})\.([0-9]{3})\.([0-9]{2})/[0-9]{2}$'}, 
-    { 'format': 'BM.aaaa.nnn',              'regex': r'^(BM)\.([0-9]{4})\.([0-9]{3})$'}, 
-    { 'format': 'BM.aaa.nnn.mmm/pp',        'regex': r'^(BM)\.([0-9]{3})\.([0-9]{3})\.([0-9]{3})/[0-9]{2}$'}, 
-    { 'format': 'BM.aaa.nnn FANTOME',       'regex': r'^(BM)\.([0-9]{3})\.([0-9]{3}) FANTOME$'}, 
-    { 'format': 'BM.aaa.nnn',               'regex': r'^(BM)\.([0-9]{3})\.([0-9]{3})$'}, 
-    { 'format': 'BM.aaa.nnnBISoo/pp',       'regex': r'^(BM)\.([0-9]{3})\.([0-9]{3})BIS([0-9]{2})/[0-9]{2}$'}, 
-    { 'format': 'BM.aaa.nnn.mmm.ppp',       'regex': r'^(BM)\.([0-9]{3})\.([0-9]{3})\.([0-9]{3})\.[0-9]{3}$'}, 
-    { 'format': 'BM.aaa.nnn.mmm/ppp',       'regex': r'^(BM)\.([0-9]{3})\.([0-9]{3})\.([0-9]{3})/[0-9]{3}$'}, 
-    { 'format': 'BM.aaa.nnn/pp',            'regex': r'^(BM)\.([0-9]{3})\.([0-9]{3})/[0-9]{2}$'}, 
-    { 'format': 'BM.aaa.nnn-BIS.ooo/pp',    'regex': r'^(BM)\.([0-9]{3})\.([0-9]{3})-BIS\.([0-9]{3})/[0-9]{2}$'}, 
-    { 'format': 'BM.aaaa.nnn.mmm/NN',       'regex': r'^(BM)\.([0-9]{4})\.([0-9]{3})\.([0-9]{3})/NN$'}, 
-    { 'format': 'BM.aaa.nnn.mmm/pp-DEPOT',  'regex': r'^(BM)\.([0-9]{3})\.([0-9]{3})\.([0-9]{3})/[0-9]{2}-DEPOT$'}, 
-    { 'format': 'BM.aaa.nnn.mmm-o>p',       'regex': r'^(BM)\.([0-9]{3})\.([0-9]{3})\.([0-9]{3})-[0-9]>[0-9]$'}, 
-    { 'format': 'CY.aaaa.nnn',              'regex': r'^(CY)\.([0-9]{4})\.([0-9]{3})$'}, 
-    { 'format': 'DI.aaaa.nnn.mmm',          'regex': r'^(DI)\.([0-9]{4})\.([0-9]{3})\.([0-9]{3})$'}, 
-    { 'format': 'DI.aaaa.nnn.mmm/pp',       'regex': r'^(DI)\.([0-9]{4})\.([0-9]{3})\.([0-9]{3})/[0-9]{2}$'}, 
-    { 'format': 'DI.aaa.nnn.mmm',           'regex': r'^(DI)\.([0-9]{3})\.([0-9]{3})\.([0-9]{3})$'}, 
-    { 'format': 'DI.aaa.nnn.mmm/pp',        'regex': r'^(DI)\.([0-9]{3})\.([0-9]{3})\.([0-9]{3})/[0-9]{2}$'}, 
-    { 'format': 'DI.aaa.nnn.mmm-o/p',       'regex': r'^(DI)\.([0-9]{3})\.([0-9]{3})\.([0-9]{3})-[0-9]/[0-9]$'}, 
-    { 'format': 'FANTOME 2*',               'regex': r'FANTOME 2\*$'}, 
-]
-
-db = MySQLdb.connect(user='root', db='test');
-
-rcursor = db.cursor()
-wcursor = db.cursor()
-
-wcursor.execute("UPDATE coll SET format='', new_id = NULL, dup = 0")
-
-nrow = 0
-for pattern in collection_patterns:
-    stdout.write('* format: ' + pattern['format'] + '\n')
-    wcursor.execute("UPDATE coll SET format=%s WHERE cote REGEXP %s",
-        (pattern['format'], pattern['regex']))
-    rcursor.execute("SELECT COUNT(*) FROM coll")        
-    row = rcursor.fetchone()
-    count = row[0]
-    rcursor.execute("SELECT cote FROM coll WHERE cote REGEXP %s", (pattern['regex'],))    
-    row = rcursor.fetchone()
-    while row:
-        if nrow % 200 == 0:
-            stdout.write("  row " + str(nrow) + "/" + str(count) + '\n')
-        id = row[0]
-        match = re.match(pattern['regex'], id)
-
-        published = False
-        year = -1
-        serial = -1
-        physical = -1
-
-        if (match.lastindex >= 1):
-            published = (match.group(1) == 'DI')
-        if (match.lastindex >= 2):
-            year = int(match.group(2)) 
-        if (match.lastindex >= 3):
-            serial = int(match.group(3))
-        if (match.lastindex >= 4):
-            physical = int(match.group(4)) 
-        
-        if (year == -1 or serial == -1):
-            stdout.write('    missing year or serial: ' + id + '\n')
-        else:            
-            tokens = []
-            if published:
-                tokens.append('CNRSMH_E')
-            else:                
-                tokens.append('CNRSMH_I')
-            
-            if year < 1000:
-                if year < 100:
-                    year += 2000
-                else:
-                    year += 1000
-            tokens.append(str(year))
-                            
-            tokens.append(str(serial).rjust(3, '0'))
-
-            if published:
-                if physical != -1:
-                    tokens.append(str(physical).rjust(3, '0'))
-                else:
-                    tokens.append('001')
-            
-            new_id = '_'.join(tokens)
-
-            try:
-                wcursor.execute("UPDATE coll SET new_id = %s WHERE cote = %s", (new_id, id))           
-            except _mysql_exceptions.IntegrityError, (errno, errstr):
-                if errno == 1062:
-                    stdout.write('    duplicate entry: ' + id + ' -> ' + new_id + '\n')
-                    wcursor.execute("UPDATE coll SET dup = 1 WHERE cote = %s", (id,))           
-                else:
-                    raise
-
-        row = rcursor.fetchone()
-        nrow += 1      
-
-rcursor.execute("SELECT format, cote, COUNT(*), SUM(dup) FROM coll GROUP BY format");
-
-stdout.write("\nFORMAT STATS:\n")
-row = rcursor.fetchone()
-stdout.write("format\texample\tcount\tduplicates\n");
-while row:
-    stdout.write(row[0] + "\t" + row[1] + "\t" + str(row[2]) + "\t" + str(row[3]) + '\n')
-    row = rcursor.fetchone()
-
-rcursor.execute("SELECT cote FROM coll WHERE new_id IS NULL AND dup = 1")
-stdout.write("\nUNCONVERTED IDs (duplicates):\n")
-row = rcursor.fetchone()
-while row:
-    stdout.write(row[0] + '\n')
-    row = rcursor.fetchone()
-    
-rcursor.execute("SELECT cote FROM coll WHERE new_id IS NULL AND dup = 0")
-stdout.write("\nUNCONVERTED IDs (non duplicates):\n")
-row = rcursor.fetchone()
-while row:
-    stdout.write(row[0] + '\n')
-    row = rcursor.fetchone()
-    
-    
-
-    
-            
-
-    
diff --git a/import/README b/import/README
deleted file mode 100644 (file)
index 7b6f193..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-
-==========================================
-CREM data import instructions and programs
-==========================================
-
-* ``prototype`` : this directory contains scripts to perform an experimental
-  import of the CREM database into Telemeta 0.3.x. It is only meant as a
-  proof of concept.
-* ``raw_conversion`` : instructions and scripts to perform a full raw conversion 
-  of the CREM database from 4D to MySQL. The result has the same structure
-  as the original 4D database, and, as such, can't be used directly in 
-  Telemeta. 
-
diff --git a/import/prototype/README b/import/prototype/README
deleted file mode 100644 (file)
index 88c4a14..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-==================================================
-CREM data and how to import it into Telemeta 0.3.x
-==================================================
-
-Warning: the following instructions allow you to import the CREM's data
-into telemeta. However, it is currently a rather data destructive process,
-only meant for demonstration and testing purpose. Do not use this in a
-production environment.
-
-1.  Install Telemeta upon MySQL. Initialize the database using Telemeta's
-    Django models. Ensure that everything is running fine before going any 
-    further.
-
-2.  Run prepare on the source directory. The source directory must contain
-    text files as they were exported from the 4D database. These files are 
-    expected to be gzipped. 
-
-    Example::
-
-    $ scripts/prepare src/2007-05-09
-
-3.  Use the import.sql script to insert the data into your MySQL database.
-
-    Example::
-
-    $ mysql your_telemeta_database < scripts/import.sql
-
-4.  Copy the WAV test file of your choice, into <MEDIA_ROOT>/items/test.wav
-    This single file is associated with all media items, for testing purpose.
-
-That should be it. If you want to run Telemeta against SQLite instead of 
-MySQL, first follow the above instructions to import the data into MySQL.
-Then convert your data from MySQL to SQLite, this is a common task, google 
-about it.
-
-
-
diff --git a/import/prototype/scripts/import.sql b/import/prototype/scripts/import.sql
deleted file mode 100644 (file)
index 0bb05be..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-DELETE FROM telemeta_collection;
-LOAD DATA INFILE '/tmp/crem_import/support.txt' INTO TABLE telemeta_collection
-FIELDS TERMINATED BY '\t'
-LINES TERMINATED BY '\r\n';
-
-UPDATE telemeta_collection SET id=REPLACE(id, '/', '--');
-UPDATE telemeta_collection SET copied_from_id = NULL WHERE copied_from_id = '';
-
-DELETE FROM telemeta_item;
-LOAD DATA INFILE '/tmp/crem_import/phono.txt' INTO TABLE telemeta_item
-FIELDS TERMINATED BY '\t'
-LINES TERMINATED BY '\r\n';
-
-UPDATE telemeta_item SET id=REPLACE(id, ":", "__");
-UPDATE telemeta_item SET id=REPLACE(id, '/', '--');
-UPDATE telemeta_item SET id=REPLACE(id, '?', 'i');
-UPDATE telemeta_item SET collection_id=REPLACE(collection_id, '/', '--');
-UPDATE telemeta_item SET title='' WHERE title='N';
-UPDATE telemeta_item SET etat=REPLACE(etat, ')', '_');
-UPDATE telemeta_item SET etat=REPLACE(etat, '(', '_');
-UPDATE telemeta_item SET file="items/test.wav";
-
-DELETE FROM telemeta_physicalformat;
-INSERT INTO telemeta_physicalformat (value)
-    SELECT DISTINCT physical_format FROM telemeta_collection
-    WHERE physical_format <> '' AND physical_format IS NOT NULL;
-
-DELETE FROM telemeta_publishingstatus;
-INSERT INTO telemeta_publishingstatus (value)
-    SELECT DISTINCT publishing_status FROM telemeta_collection
-    WHERE publishing_status <> '' AND publishing_status IS NOT NULL;
diff --git a/import/prototype/scripts/prepare b/import/prototype/scripts/prepare
deleted file mode 100755 (executable)
index 92a7618..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/bin/bash
-
-if [ "$1" == "" ]
-then 
-    echo "Please provide the source directory"
-    exit 1
-fi
-
-src=$1
-tmpdir=crem_import
-required="support.txt.gz phono.txt.gz"
-
-for f in $required
-do
-    if ! [ -f $src/$f ]
-    then 
-        echo "Can't find $f in $src"
-        exit 1
-    fi
-done    
-
-if [ -d /tmp/$tmpdir ]
-then
-    rm /tmp/$tmpdir/*
-else
-    mkdir /tmp/$tmpdir
-fi    
-
-echo -n "Converting charset and cleaning text files.. "
-
-zcat $src/support.txt.gz | tail -n +2 \
-    | sed 's/^ *//' | sed 's/ *\t */\t/g'| sed 's/ *$//' \
-    | iconv -f WINDOWS-1252 -c -t latin1 \
-    > /tmp/$tmpdir/support.txt
-
-zcat $src/phono.txt.gz | tail -n +2 \
-    | sed 's/^ *//' | sed 's/ *\t */\t/g'| sed 's/ *$//' \
-    | iconv -f WINDOWS-1252 -c -t latin1 | sed '/^\t/d' \
-    > /tmp/$tmpdir/phono.txt
-
-echo "Done"
-
-
diff --git a/import/prototype/src/2007-05-09/phono.txt.gz b/import/prototype/src/2007-05-09/phono.txt.gz
deleted file mode 100755 (executable)
index fd0be4a..0000000
Binary files a/import/prototype/src/2007-05-09/phono.txt.gz and /dev/null differ
diff --git a/import/prototype/src/2007-05-09/support.txt.gz b/import/prototype/src/2007-05-09/support.txt.gz
deleted file mode 100755 (executable)
index a7ec8c6..0000000
Binary files a/import/prototype/src/2007-05-09/support.txt.gz and /dev/null differ
diff --git a/import/raw_conversion/README b/import/raw_conversion/README
deleted file mode 100644 (file)
index 17f2195..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-==========================================================
-Base de données du CREM : conversion brut de 4D vers MySQL
-==========================================================
-
-Le présent document décrit la procédure de conversion brut de la base de 
-données du CREM de 4D vers MySQL. La base MySQL obtenue a la même structure
-que la base originale 4D.
-
-Cette procédure doit être effectuée par un informaticien.
-
-Les instructions ci-dessous nécessitent l'emploi de la version 6.5.x de 4D pour 
-Windows.
-
-Avertissement: il est fortement recommandé de réaliser ces opérations sur une
-copie de la base 4D, et non sur la version de production.
-
-1.  Sur un poste Windows où se trouve la base du CREM, et équipé de 4D 6.5.x,
-    créer le répertoire C:\export_crem
-
-2.  Lancer 4D, ouvrir la base du CREM, créer une nouvelle méthode 4D avec 
-    le code source fourni dans le fichier ``export.4d.txt``, et lancer cette 
-    méthode de façon à exporter toute la base et les relations dans le 
-    répertoire C:\export_crem
-
-    Cette opération peut prendre plusieurs minutes. Une fenêtre "Export terminé"
-    s'affiche à la fin.
-
-    Remarque: si vous utilisez une version de démonstration de 4D, vous ne pouvez
-    pas créer de nouvelle méthode, mais vous pouvez remplacer une méthode existante.
-    
-3.  Placer le répertoire export_crem sur un poste linux, de façon à ce qu'il soit
-    accessible à l'import MySQL, par exemple dans /tmp/export_crem avec 777 pour
-    permissions
-
-4.  Créer une base MySQL, par exemple: crem
-
-5.  Importer la toutes les données dans la base MySQL avec la commande::
-
-        ./import /tmp/export_crem | mysql -vvv crem
-    
-    Vérifiez que chaque requête se termine par "Query OK" avec "Warnings: 0", 
-    pour vous assurer du bon déroulement de l'opération.
-
diff --git a/import/raw_conversion/export.4d.txt b/import/raw_conversion/export.4d.txt
deleted file mode 100755 (executable)
index bd30cd6..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-`Export de toutes les tables\r
-\r
-C_ALPHA(1;$fieldDelimiter;$recordDelimiter)\r
-C_ALPHA(32;$tableName;$fieldName)\r
-C_ENTIER LONG($numberOfTables;$tableNumber;$numberOfFields;$fieldNumber)\r
-C_ENTIER LONG($numberOfRecords;$fieldType)\r
-C_POINTEUR($tablePtr;$fieldPtr)\r
-C_TEXTE($fieldValue)\r
-C_HEURE($documentReference)\r
-C_REEL($Plateforme)\r
-PROPRIETES PLATE FORME($Plateforme)\r
-\r
-$fieldDelimiter:=Caractere(9)  \r
-$recordDelimiter:=Caractere(10)  \r
-\r
-$numberOfTables:=Nombre de tables  \r
-\r
-Boucle ($tableNumber;1;$numberOfTables)  \r
-  \r
-  $tablePtr:=Table($tableNumber)  \r
-  $tableName:=Nom de la table($tableNumber)  \r
-  \r
-  $documentReference:=Creer document("C:\export_crem\"+$tableName+".txt";"TEXT")  \r
-  \r
-  Si (OK=1)  \r
-    $numberOfFields:=Nombre de champs($tableNumber)  \r
-    \r
-    Boucle ($fieldNumber;1;$numberOfFields)  \r
-      $fieldName:=Nom du champ($tableNumber;$fieldNumber)  \r
-      Si ($fieldNumber#$numberOfFields)  \r
-        Si ($Plateforme=Windows )\r
-          ENVOYER PAQUET($documentReference;Mac vers Windows($fieldName)+$fieldDelimiter)\r
-            \r
-        Sinon \r
-          ENVOYER PAQUET($documentReference;$fieldName+$fieldDelimiter)\r
-            \r
-        Fin de si \r
-      Sinon \r
-        Si ($plateforme=Windows )\r
-          ENVOYER PAQUET($documentReference;Mac vers Windows($fieldName)+$recordDelimiter)\r
-            \r
-        Sinon \r
-          ENVOYER PAQUET($documentReference;$fieldName+$recordDelimiter)\r
-            \r
-        Fin de si \r
-      Fin de si \r
-    Fin de boucle \r
-    \r
-    TOUT SELECTIONNER($tablePtr->)  \r
-    $numberOfRecords:=Enregistrements trouves($tablePtr->)  \r
-    \r
-    Boucle ($recordNumber;1;$numberOfRecords)  \r
-      \r
-      Boucle ($fieldNumber;1;$numberOfFields)  \r
-        \r
-        $fieldPtr:=Champ($tableNumber;$fieldNumber)  \r
-        PROPRIETES CHAMP($fieldPtr;$fieldType)  \r
-        \r
-          \r
-        \r
-        Au cas ou \r
-          : (($fieldType=Est un numérique ) | ($fieldType=Est un entier ) | ($fieldType=Est un entier long ))\r
-            $fieldValue:=Chaine($fieldPtr->)  \r
-          : ($fieldType=Est une date )\r
-            $fieldValue:=Chaine($fieldPtr->;7)  \r
-          : ($fieldType=Est une heure )\r
-            $fieldValue:=Chaine($fieldPtr->;1)  \r
-          : ($fieldType=Est un booléen )\r
-            \r
-              \r
-            \r
-            $fieldValue:=Chaine(Num($fieldPtr->);"VRAI;;FAUX")  \r
-          : ($fieldType=Est une image )\r
-            $fieldValue:="Image non exportée"\r
-          : ($fieldType=Est un BLOB )\r
-            $fieldValue:="BLOB non exporté"\r
-          : ($fieldType=Est une sous table )\r
-            $fieldValue:="Sous-table non exportée"\r
-          Sinon   \r
-            $fieldValue:=$fieldPtr->  \r
-            $fieldValue:=Remplacer chaine ($fieldValue; $fieldDelimiter; " ")\r
-            $fieldValue:=Remplacer chaine ($fieldValue; $recordDelimiter; " ")\r
-            $fieldValue:=Remplacer chaine ($fieldValue; Caractere(13); " ")\r
-        Fin de cas \r
-        \r
-        Si ($fieldNumber#$numberOfFields)  \r
-          Si ($Plateforme=Windows )\r
-            ENVOYER PAQUET($documentReference;Mac vers Windows($fieldValue)+$fieldDelimiter)  \r
-          Sinon \r
-            ENVOYER PAQUET($documentReference;$fieldValue+$fieldDelimiter)  \r
-          Fin de si \r
-        Sinon \r
-          Si ($Plateforme=Windows )\r
-            ENVOYER PAQUET($documentReference;Mac vers Windows($fieldValue)+$recordDelimiter)  \r
-              \r
-          Sinon \r
-            ENVOYER PAQUET($documentReference;$fieldValue+$recordDelimiter)  \r
-              \r
-          Fin de si \r
-          \r
-        Fin de si \r
-        \r
-      Fin de boucle \r
-      \r
-      ENREGISTREMENT SUIVANT($tablePtr->)  \r
-    Fin de boucle \r
-    \r
-    FERMER DOCUMENT($documentReference)  \r
-    CHANGER CREATEUR DOCUMENT(Document;"TEXT")\r
-    \r
-  Fin de si \r
-  \r
-Fin de boucle \r
-\r
-`Export des relations des formations\r
-\r
-$tab:=Caractere(9)\r
-$fin:=Caractere(10)\r
-$ret:=Caractere(13)\r
-\r
-$doc:=Creer document("c:\export_crem\Formation.txt";"TXT")\r
-Si (ok=1)\r
-  $texte:="Cote_Phono"+$tab+"Instr_Scientif"+$tab+"Instr_Vernacul"+$tab+"Interprète"+$tab+"Total_Instrum"+$fin\r
-  ENVOYER PAQUET($doc;Mac vers Windows($texte))\r
-  TOUT SELECTIONNER([Phono])\r
-  Boucle ($i;1;Enregistrements trouves([Phono]))\r
-    $cote:=[Phono]Cote_Phono\r
-    $cote:=Remplacer chaine($cote; $tab; " ")\r
-    $cote:=Remplacer chaine($cote; $fin; " ")\r
-    $cote:=Remplacer chaine($cote; $ret; " ")\r
-    TOUS LES SOUS ENREGISTREMENTS([Phono]Formation)\r
-    Boucle ($j;1;Sous enregistrements trouves([Phono]Formation)\r
-      $instr_scientif:=Remplacer chaine([Phono]Formation'Instr_Scientif; $tab; " ")\r
-      $instr_scientif:=Remplacer chaine($instr_scientif; $fin; " ")\r
-      $instr_scientif:=Remplacer chaine($instr_scientif; $ret; " ")\r
-      $instr_vernacul:=Remplacer chaine([Phono]Formation'Instr_Vernacul; $tab; " ")\r
-      $instr_vernacul:=Remplacer chaine($instr_vernacul; $fin; " ")\r
-      $instr_vernacul:=Remplacer chaine($instr_vernacul; $ret; " ")\r
-      $interprete:=Remplacer chaine([Phono]Formation'Interprète; $tab; " ")\r
-      $interprete:=Remplacer chaine($interprete; $fin; " ")\r
-      $interprete:=Remplacer chaine($interprete; $ret; " ")\r
-      $total:=Remplacer chaine([Phono]Formation'Total_Instrum; $tab; " ")\r
-      $total:=Remplacer chaine($total; $fin; " ")\r
-      $total:=Remplacer chaine($total; $ret; " ")\r
-      $texte:=$cote+$tab+$instr_scientif+$tab+$instr_vernacul+$tab+$interprete+$tab+$total+$fin\r
-      ENVOYER PAQUET($doc;Mac vers Windows($texte))\r
-      SOUS ENREGISTREMENT SUIVANT([Phono]Formation)\r
-    Fin de boucle \r
-    LIBERER ENREGISTREMENT([Phono])\r
-    ENREGISTREMENT SUIVANT([Phono])\r
-  Fin de boucle \r
-  \r
-  FERMER DOCUMENT($doc)\r
-  \r
-Fin de si \r
-\r
-`Export des relations des mots clés\r
-\r
-$doc:=Creer document("c:\export_crem\Fonction_Usage.txt";"TXT")\r
-Si (ok=1)\r
-  $texte:="Cote_Phono"+$tab+"Mot_Clef"+$fin\r
-  ENVOYER PAQUET($doc;Mac vers Windows($texte))\r
-  TOUT SELECTIONNER([Phono])\r
-  Boucle ($i;1;Enregistrements trouves([Phono]))\r
-    $cote:=[Phono]Cote_Phono\r
-    $cote:=Remplacer chaine($cote; $tab; " ")\r
-    $cote:=Remplacer chaine($cote; $fin; " ")\r
-    $cote:=Remplacer chaine($cote; $ret; " ")\r
-    TOUS LES SOUS ENREGISTREMENTS([Phono]Fonction_Usage)\r
-    Boucle ($j;1;Sous enregistrements trouves([Phono]Fonction_Usage)\r
-      $mot_clef:=Remplacer chaine([Phono]Fonction_Usage'Mot_Clef; $tab; " ")\r
-      $mot_clef:=Remplacer chaine($mot_clef; $fin; " ")\r
-      $mot_clef:=Remplacer chaine($mot_clef; $ret; " ")\r
-      $texte:=$cote+$tab+$mot_clef+$fin\r
-      ENVOYER PAQUET($doc;Mac vers Windows($texte))\r
-      SOUS ENREGISTREMENT SUIVANT([Phono]Fonction_Usage)\r
-    Fin de boucle \r
-    LIBERER ENREGISTREMENT([Phono])\r
-    ENREGISTREMENT SUIVANT([Phono])\r
-  Fin de boucle \r
-  \r
-  FERMER DOCUMENT($doc)\r
-  \r
-Fin de si \r
-\r
-\r
-ALERTE("Export terminé.")\r
diff --git a/import/raw_conversion/import b/import/raw_conversion/import
deleted file mode 100755 (executable)
index a020f39..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/bin/bash
-
-function extract_enum
-{
-    to_table=$1
-    from_table=$2
-    from_field=$3
-    echo "DROP TABLE IF EXISTS \`$to_table\`;"
-    echo "CREATE TABLE \`$to_table\` (value TEXT NOT NULL) CHARSET=latin1;"
-    echo "INSERT INTO \`$to_table\` SELECT DISTINCT \`$from_field\` FROM \`$from_table\` WHERE \`$from_field\` <> '';";
-}
-
-src=$1
-cd $src
-
-echo "SET NAMES 'latin1';"
-echo
-
-chmod o+r *.txt
-
-ls *.txt | while read filename
-do
-    table=$(echo $filename | sed 's/.txt//')
-    echo "DROP TABLE IF EXISTS \`$table\`;"
-    echo "CREATE TABLE \`$table\` ("
-    head -n1 $filename | tr '\t' '\n' | head -n-1 | sed 's/^/    `/' | sed 's/$/` TEXT NOT NULL,/'
-    head -n1 $filename | tr '\t' '\n' | tail -n1 | sed 's/^/    `/' | sed 's/$/` TEXT NOT NULL/'
-    echo ") CHARSET=latin1;"
-    echo
-    echo "LOAD DATA INFILE '$src/$filename'"
-    echo "    INTO TABLE \`$table\`"
-    echo "    CHARACTER SET 'latin1'"
-    echo "    FIELDS TERMINATED BY '\t' ESCAPED BY '' LINES TERMINATED BY '\n'"
-    echo "    IGNORE 1 LINES;"
-    echo "SHOW WARNINGS;"
-    echo
-done
-
-extract_enum Format Support Format
-extract_enum Réédition Support Réédition
-extract_enum Mode_Acqui Support Mode_Acqui
-extract_enum Rédacteur_Fiche Support Rédacteur_Fiche
-extract_enum Saisie_Fiche Support Saisie_Fiche
-extract_enum Droit_Utiliser Support Droit_Utiliser
-extract_enum Terrain_ou_Autr Support Terrain_ou_Autr
-extract_enum Numérisation Support Numérisation
-extract_enum "FormStyl généri" Phono "FormStyl généri"
-extract_enum Editeur1 Support Editeur
-extract_enum Collection_Serie Support Collect_Série
-
diff --git a/trunk/docref/crem.sql b/trunk/docref/crem.sql
new file mode 100644 (file)
index 0000000..4f60c51
--- /dev/null
@@ -0,0 +1,378 @@
+--
+-- Copyright Samalyse SARL, 2008
+-- Auteur: Olivier Guilyardi <olivier@samalyse.com>
+-- 
+-- Structure de la nouvelle base du CREM
+-- 
+-- Ce logiciel est régi par la licence CeCILL soumise au droit français et
+-- respectant les principes de diffusion des logiciels libres. Vous pouvez
+-- utiliser, modifier et/ou redistribuer ce programme sous les conditions
+-- de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA 
+-- sur le site "http://www.cecill.info".
+-- 
+-- En contrepartie de l'accessibilité au code source et des droits de copie,
+-- de modification et de redistribution accordés par cette licence, il n'est
+-- offert aux utilisateurs qu'une garantie limitée.  Pour les mêmes raisons,
+-- seule une responsabilité restreinte pèse sur l'auteur du programme,  le
+-- titulaire des droits patrimoniaux et les concédants successifs.
+-- 
+-- A cet égard  l'attention de l'utilisateur est attirée sur les risques
+-- associés au chargement,  à l'utilisation,  à la modification et/ou au
+-- développement et à la reproduction du logiciel par l'utilisateur étant 
+-- donné sa spécificité de logiciel libre, qui peut le rendre complexe à 
+-- manipuler et qui le réserve donc à des développeurs et des professionnels
+-- avertis possédant  des  connaissances  informatiques approfondies.  Les
+-- utilisateurs sont donc invités à charger  et  tester  l'adéquation  du
+-- logiciel à leurs besoins dans des conditions permettant d'assurer la
+-- sécurité de leurs systèmes et ou de leurs données et, plus généralement, 
+-- à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. 
+-- 
+-- Le fait que vous puissiez accéder à cet en-tête signifie que vous avez 
+-- pris connaissance de la licence CeCILL, et que vous en avez accepté les
+-- termes.
+--
+-- SVN:$Id$
+--
+
+--
+-- Enumérations simples
+--
+
+CREATE TABLE physical_formats (
+    id      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
+    value   VARCHAR(250) NOT NULL
+);
+
+CREATE TABLE publishing_status (
+    id      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
+    value   VARCHAR(250) NOT NULL
+);
+
+CREATE TABLE acquisition_modes (
+    id      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
+    value   VARCHAR(250) NOT NULL
+);
+
+CREATE TABLE metadata_authors (
+    id      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
+    value   VARCHAR(250) NOT NULL
+);
+
+CREATE TABLE metadata_writers (
+    id      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
+    value   VARCHAR(250) NOT NULL
+);
+
+CREATE TABLE legal_rights (
+    id      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
+    value   VARCHAR(250) NOT NULL
+);
+
+CREATE TABLE recording_contexts (
+    id      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
+    value   VARCHAR(250) NOT NULL
+);
+
+CREATE TABLE ad_conversions (
+    id      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
+    value   VARCHAR(250) NOT NULL
+);
+
+CREATE TABLE vernacular_styles (
+    id      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
+    value   VARCHAR(250) NOT NULL
+);
+
+CREATE TABLE generic_styles (
+    id      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
+    value   VARCHAR(250) NOT NULL
+);
+
+--
+-- Editeurs et collections
+--
+
+CREATE TABLE publishers (
+    id      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
+    value   VARCHAR(250) NOT NULL
+);
+
+CREATE TABLE publisher_collections (
+    id              INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
+    publisher_id    INTEGER NOT NULL,
+    value           VARCHAR(250) NOT NULL,
+
+    FOREIGN KEY(publisher_id) REFERENCES publishers (id)
+);
+
+--
+-- Thésaurus géographique
+--
+
+CREATE TABLE location_types (
+    id              INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+    type            VARCHAR(250) NOT NULL
+);    
+
+CREATE TABLE locations (
+    name                VARCHAR(250) NOT NULL PRIMARY KEY,
+    type                ENUM('country', 'continent', 'other'),
+    complete_type_id    INTEGER NOT NULL,
+    current_name        VARCHAR(250),
+    is_authoritative    BOOLEAN NOT NULL,
+
+    FOREIGN KEY(current_name) REFERENCES locations (name),
+    FOREIGN KEY(complete_type_id) REFERENCES location_types (id)
+);
+
+CREATE TABLE location_aliases (
+    location_name       VARCHAR(250) NOT NULL,
+    alias               VARCHAR(250) NOT NULL,
+    is_authoritative    BOOLEAN NOT NULL,
+
+    PRIMARY KEY(location_name, alias),
+    FOREIGN KEY(location_name) REFERENCES locations (name)
+);
+
+CREATE TABLE location_relations (
+    location_name           VARCHAR(250) NOT NULL,
+    parent_location_name    VARCHAR(250) NOT NULL,
+
+    PRIMARY KEY(location_name, parent_location_name),
+    FOREIGN KEY(location_name) REFERENCES locations (name),
+    FOREIGN KEY(parent_location_name) REFERENCES locations (name)
+);
+
+--
+-- Ethnies
+--
+
+CREATE TABLE ethnic_groups (
+    id      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
+    name    VARCHAR(250) NOT NULL
+);
+
+CREATE TABLE ethnic_group_aliases (
+    ethnic_group_id INTEGER NOT NULL, 
+    name            VARCHAR(250) NOT NULL,
+
+    FOREIGN KEY(ethnic_group_id) REFERENCES ethnic_groups (id)
+);
+
+--
+-- Collections
+--
+
+CREATE TABLE media_collections (
+    id                      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+    reference               VARCHAR(250) NOT NULL UNIQUE,
+    physical_format_id      INTEGER NOT NULL,
+    old_code                VARCHAR(250) NOT NULL UNIQUE,
+    code                    VARCHAR(250) NOT NULL UNIQUE,
+    title                   VARCHAR(250) NOT NULL,
+    alt_title               VARCHAR(250) NOT NULL,
+    physical_items_num      INTEGER NOT NULL,
+    publishing_status_id    INTEGER NOT NULL,
+    creator                 VARCHAR(250) NOT NULL,
+    booklet_author          VARCHAR(250) NOT NULL,
+    booklet_description     TEXT NOT NULL,
+    collector               VARCHAR(250) NOT NULL,
+    collector_is_creator    BOOLEAN NOT NULL,
+    publisher_id            INTEGER NOT NULL,
+    year_published          INTEGER NOT NULL,
+    publisher_collection_id INTEGER NOT NULL,
+    publisher_serial        VARCHAR(250) NOT NULL,
+    external_references     TEXT NOT NULL,
+    acquisition_mode_id     INTEGER NOT NULL,
+    comment                 TEXT NOT NULL,
+    metadata_author_id      INTEGER NOT NULL,
+    metadata_writer_id      INTEGER NOT NULL,
+    legal_rights_id         INTEGER NOT NULL,
+    alt_ids                 VARCHAR(250) NOT NULL,
+    recorded_from_year      INTEGER NOT NULL,
+    recorded_to_year        INTEGER NOT NULL,
+    recording_context_id    INTEGER NOT NULL,
+    approx_duration         TIME NOT NULL,
+    doctype_code            INTEGER NOT NULL,
+    travail                 VARCHAR(250) NOT NULL,
+    state                   VARCHAR(250) NOT NULL,
+    cnrs_contributor        VARCHAR(250) NOT NULL,
+    items_done              VARCHAR(250) NOT NULL,
+    a_informer_07_03        VARCHAR(250) NOT NULL,
+    ad_conversion_id        INTEGER NOT NULL,
+    public_access           ENUM('none', 'metadata', 'full') NOT NULL,
+
+    FOREIGN KEY(ad_conversion_id)       REFERENCES ad_conversions (id),
+    FOREIGN KEY(publisher_collection_id) REFERENCES publisher_collections (id),
+    FOREIGN KEY(recording_context_id)   REFERENCES recording_contexts (id),
+    FOREIGN KEY(publisher_id)           REFERENCES publishers (id),
+    FOREIGN KEY(metadata_author_id)     REFERENCES metadata_authors (id),
+    FOREIGN KEY(physical_format_id)     REFERENCES physical_formats (id),
+    FOREIGN KEY(metadata_writer_id)     REFERENCES metadata_writers (id),
+    FOREIGN KEY(legal_rights_id)        REFERENCES legal_rights (id),
+    FOREIGN KEY(acquisition_mode_id)    REFERENCES acquisition_modes (id),
+    FOREIGN KEY(publishing_status_id)   REFERENCES publishing_status (id)
+);
+
+--
+-- Items
+--
+
+CREATE TABLE media_items (
+    id                      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
+    collection_id           INTEGER NOT NULL,
+    track                   VARCHAR(250) NOT NULL,
+    code                    VARCHAR(250) NOT NULL,
+    approx_duration         TIME NOT NULL,
+    recorded_from_date      DATE NOT NULL,
+    recorded_to_date        DATE NOT NULL,
+    location_name           VARCHAR(250) NOT NULL,
+    location_comment        VARCHAR(250) NOT NULL,
+    ethnic_group_id         INTEGER NOT NULL,
+    title                   VARCHAR(250) NOT NULL,
+    alt_title               VARCHAR(250) NOT NULL,
+    author                  VARCHAR(250) NOT NULL,
+    vernacular_style_id     INTEGER NOT NULL,
+    context_comment         TEXT NOT NULL,
+    external_references     VARCHAR(250) NOT NULL,
+    moda_execut             VARCHAR(250) NOT NULL,
+    copied_from_item_id     INTEGER,
+    collector               VARCHAR(250) NOT NULL,
+    cultural_area           VARCHAR(250) NOT NULL,
+    generic_style_id        INTEGER NOT NULL,
+    collector_selection     VARCHAR(250) NOT NULL,
+    creator_reference       VARCHAR(250) NOT NULL,
+    filename                VARCHAR(250) NOT NULL,
+    public_access           ENUM('none', 'metadata', 'full') NOT NULL,
+
+    FOREIGN KEY(ethnic_group_id) REFERENCES ethnic_groups (id),
+    FOREIGN KEY(collection_id) REFERENCES media_collections (id),
+    FOREIGN KEY(vernacular_style_id) REFERENCES vernacular_styles (id),
+    FOREIGN KEY(location_name) REFERENCES locations (name),
+    FOREIGN KEY(copied_from_item_id) REFERENCES media_items (id),
+    FOREIGN KEY(generic_style_id) REFERENCES generic_styles (id)
+);
+
+--
+-- Parties d'item/marqueurs
+--
+
+CREATE TABLE media_parts (
+    id                      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
+    item_id                 INTEGER NOT NULL,
+    title                   VARCHAR(250) NOT NULL,
+    start                   FLOAT NOT NULL,
+    end                     FLOAT NOT NULL,
+
+    FOREIGN KEY(item_id) REFERENCES media_items (id)
+);
+
+--
+-- Instruments et formations
+--
+
+CREATE TABLE instruments (
+    id      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
+    name    VARCHAR(250) NOT NULL
+);
+
+CREATE TABLE instrument_relations (
+    instrument_id           INTEGER NOT NULL, 
+    parent_instrument_id    INTEGER NOT NULL,
+
+    FOREIGN KEY(instrument_id)          REFERENCES instruments (id),
+    FOREIGN KEY(parent_instrument_id)   REFERENCES instruments (id)
+);
+
+CREATE TABLE instrument_aliases (
+    id      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
+    name    VARCHAR(250) NOT NULL
+);
+
+CREATE TABLE instrument_alias_relations (
+    alias_id                INTEGER NOT NULL, 
+    instrument_id           INTEGER NOT NULL,
+
+    FOREIGN KEY(alias_id)       REFERENCES instrument_aliases (id),
+    FOREIGN KEY(instrument_id)  REFERENCES instruments (id)
+);
+
+CREATE TABLE media_item_performances (
+    media_item_id           INTEGER NOT NULL,
+    instrument_id           INTEGER NOT NULL,
+    alias_id                INTEGER NOT NULL, 
+    instruments_num         VARCHAR(250) NOT NULL,
+    musicians               VARCHAR(250) NOT NULL,
+
+    FOREIGN KEY(media_item_id)  REFERENCES media_items (id),
+    FOREIGN KEY(instrument_id)  REFERENCES instruments (id),
+    FOREIGN KEY(alias_id)       REFERENCES instrument_aliases (id)
+);
+
+--
+-- Contexte ethnographique
+--
+
+CREATE TABLE context_keywords (
+    id      INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
+    value   VARCHAR(250) NOT NULL
+);
+
+CREATE TABLE media_item_keywords (
+    item_id     INTEGER NOT NULL,
+    keyword_id  INTEGER NOT NULL,
+
+    PRIMARY KEY(item_id, keyword_id),
+    FOREIGN KEY(item_id) REFERENCES media_items (id),
+    FOREIGN KEY(keyword_id) REFERENCES context_keywords (id)
+);
+
+--
+-- Utilisateurs
+--
+
+CREATE TABLE users (
+    username    VARCHAR(64) NOT NULL PRIMARY KEY,
+    level       ENUM ('user', 'maintainer', 'admin') NOT NULL,
+    first_name  VARCHAR(250) NOT NULL,
+    last_name   VARCHAR(250) NOT NULL,
+    phone       VARCHAR(250) NOT NULL,
+    email       VARCHAR(250) NOT NULL
+);
+
+--
+-- Séléctions
+--
+
+CREATE TABLE playlists (
+    id              INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+    owner_username  VARCHAR(250) NOT NULL,
+    name            VARCHAR(250) NOT NULL,
+
+    FOREIGN KEY(owner_username) REFERENCES users (username)
+);
+
+CREATE TABLE playlist_resources (
+    playlist_id     INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
+    resource_type   ENUM('item', 'collection') NOT NULL,
+    resource_id     INTEGER NOT NULL,
+
+    FOREIGN KEY(playlist_id) REFERENCES playlists (id)
+);
+
+
+--
+-- Historique des modifications
+--
+
+CREATE TABLE revisions (
+    id              INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, 
+    element_type    VARCHAR(32) NOT NULL,
+    element_id      INTEGER NOT NULL,
+    change_type     ENUM('create', 'update', 'delete') NOT NULL,
+    time            DATETIME NOT NULL,
+    username        VARCHAR(64) NOT NULL,
+
+    FOREIGN KEY(username) REFERENCES users (username)
+);
+
diff --git a/trunk/docref/crem.zargo b/trunk/docref/crem.zargo
new file mode 100644 (file)
index 0000000..4f7b7e8
Binary files /dev/null and b/trunk/docref/crem.zargo differ
diff --git a/trunk/docref/docref-0.1-prealpha.odt b/trunk/docref/docref-0.1-prealpha.odt
new file mode 100644 (file)
index 0000000..4c8a8df
Binary files /dev/null and b/trunk/docref/docref-0.1-prealpha.odt differ
diff --git a/trunk/docref/docref-0.2-prealpha.odt b/trunk/docref/docref-0.2-prealpha.odt
new file mode 100644 (file)
index 0000000..79cba1f
Binary files /dev/null and b/trunk/docref/docref-0.2-prealpha.odt differ
diff --git a/trunk/docref/docref-0.3-alpha.odt b/trunk/docref/docref-0.3-alpha.odt
new file mode 100644 (file)
index 0000000..4295755
Binary files /dev/null and b/trunk/docref/docref-0.3-alpha.odt differ
diff --git a/trunk/docref/docref-0.4-beta.odt b/trunk/docref/docref-0.4-beta.odt
new file mode 100644 (file)
index 0000000..f043e96
Binary files /dev/null and b/trunk/docref/docref-0.4-beta.odt differ
diff --git a/trunk/docref/docref.odt b/trunk/docref/docref.odt
new file mode 100644 (file)
index 0000000..5e96532
Binary files /dev/null and b/trunk/docref/docref.odt differ
diff --git a/trunk/docref/spec/build.sh b/trunk/docref/spec/build.sh
new file mode 100644 (file)
index 0000000..14af7e3
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+python parse.py
+cd build
+rst2html docref.txt docref.html && rst2latex docref.txt docref.tex && pdflatex docref.tex
+
diff --git a/trunk/docref/spec/docref.txt b/trunk/docref/spec/docref.txt
new file mode 100644 (file)
index 0000000..48bb608
--- /dev/null
@@ -0,0 +1,223 @@
+
+
+===================================================================
+Recommandations pour la réorganisation de la base de donnée du CREM
+===================================================================
+------------------------------------
+Document de référence, version alpha
+------------------------------------
+
+
+I - Enjeux
+==========
+
+I.1 - Recherche d'informations
+------------------------------
+
+L'analyse de la structure de données et la rencontre des personnes concernées par son usage
+permettent de délimiter des enjeux majeurs. Il apparaît notamment que le fond documentaire
+que constitue cette base n'est actuellement pas mis à profit comme il pourrait l'être. Cette
+base est largement sous-utilisée, les chercheurs, pour certains, ne l'utilisent pas du tout.
+
+La raison principale de cette situation est le fait que l'environnement technique et la
+structure de la base ont été conçus pour s'inscrire dans un environnement documentaire
+traditionnel, qui implique généralement de prendre contact avec un documentaliste pour effectuer
+une recherche. Le documentaliste est un spécialiste de la base, il possède les connaissances
+techniques nécessaires à sa consultation.
+
+Mais à l'heure d'Internet, ce processus de recherche est trop lourd et inadapté, en un mot
+: obsolète. Les chercheurs lui préfèrent d'autres fonds documentaires accessibles en ligne,
+de façon immédiate, et équipés d'outils de recherche puissants et ergonomiques.
+
+L'enjeu principal de la réorganisation de la base du CREM consiste donc à : sous-tendre le
+développement d'un outil moderne de gestion et de consultation en ligne, avec des fonctions
+de recherche puissantes et intuitives déterminer et améliorer les données de la base qui
+sont prioritaires pour la recherche d'information
+
+En de-ça des-dits champs prioritaires, il existe un grand nombre d'information techniques de
+second ordre, qui soit ne sont utiles qu'aux documentalistes, soit ne présentent pas d'intérêt
+majeur pour la recherche d'information. Ces informations peuvent être conservées telles quelles,
+sans grand effort de réorganisation, et resteront ainsi disponibles lors de la consultation
+individuelle des fiches.
+
+En procédant de cette façon, c'est à dire en délimitant les-dîtes priorités, il semble
+possible de dégager une véritable plus-value, de rendre le fond documentaire du CREM plus vivant,
+sans pour autant engager des moyens démesurés dans la réorganisation de la base de donnée.
+
+I.2 - Gestion et mise à jour des données
+----------------------------------------
+
+Il est entendu qu'au delà de la consultation d'information, il s'agit également de faciliter
+la gestion des données, leur mise à jour. Cette question implique pour une large part des
+problématiques d'ordre ergonomique, liées au développement d'un outil logiciel autour de la
+base, ce qui n'entre pas dans le cadre de la réorganisation de la base de données.
+
+Cependant, au niveau de la base, certains choix sont structurant. Par exemple l'emploi d'une
+liste hiérarchisée de lieux telle que le Thesaurus of Geographical Names (TGN, recommandé par
+Dublin Core), permet, en choisissant une région, une sous-région ou un village, de renseigner
+automatiquement le pays (et les autres zones géographiques intermédiaires), ce qui diminue
+l'effort et prévient les erreurs de saisie.
+
+Pour un grand nombre de champs, l'emploi d'énumérations (liste de valeurs valides pour
+un champ donné) facilite et valide déjà la mise à jour des données. Cet aspect de la base
+devra être conservé.
+
+Cependant, il semble que l'enjeu majeur de la réorganisation, du point de vue de la gestion
+des données, est de permettre un travail collaboratif, entre chercheurs et documentalistes. C'est
+là, d'une manière générale, ce qui permet sur Internet de rendre un fond documentaire vivant.
+
+Dans le cadre du CREM, il serait ainsi idéal d'amener les chercheurs à alimenter la base de
+façon autonome, en sus des documentalistes dont c'est le métier. Ce serait là une véritable
+nouveauté, représentant un fort potentiel d'enrichissement des données.
+
+D'une façon générale, une application en ligne ("webifiée") bien conçue se prête
+très bien au travail collaboratif. Cependant, il semble que dans notre cas, les potentielles
+contributions des chercheurs se heurtent à une question importante de confidentialité et
+de propriété intellectuelle. Des cas ont en effet été rapportés d'usage détournés du
+fruit du travail du centre de recherche, et d'une manière générale, il semble qu'il faille
+observer une grande prudence pour la mise en commun d'enregistrement sonores et autres données,
+qui représentent une matière précieuse aux yeux des chercheurs.
+
+La sécurité informatique est pour une large part distinct de la base de donnée ; elle
+implique des efforts particuliers au niveau du développement applicatif, et de l'administration
+de l'infrastructure réseau.
+
+Cependant, au niveau de la base de donnée, il est possible de mettre l'accent sur la
+propriété des données. Chaque ressource (collection, item) peut en effet se voir attribuer
+un propriétaire. Le dit propriétaire devrait ensuite pouvoir choisir quel autre utilisateur
+et/ou groupe d'utilisateur est autorisé à consulter, écouter, et/ou modifier la ressource.
+
+En rassurant ainsi les chercheurs, il est envisageable que la base s'enrichisse notablement
+par leurs contributions, dont certaines d'abord privées, pourront, à leur guise, devenir
+petit à petit accessibles à un nombre grandissant d'utilisateurs et de groupes de travail.
+
+I.3 - Données prioritaires
+
+Après consultation des différents utilisateurs il apparaît que les meta-données principales
+pour chaque item sont :
+
+* l'identifiant unique de l'item
+* le titre de l'item
+* la zone géographique
+* le nom du collecteur, c'est à dire le chercheur qui a collecté cet enregistrement
+* les instruments de musique utilisés
+* l'année d'enregistrement
+* le contexte ethnographique
+* l'ethnie
+
+Il s'agit d'apporter une attention particulière à celles-ci, notamment en les normalisant,
+pour faciliter la recherche d'informations, mais aussi pour l'ajout et la gestion simplifiés
+d'items.
+
+Les autres données pourront être conservées telles quelles sans grand effort de normalisation.
+
+I.4 - Dublin Core
+-----------------
+
+...
+
+II - Modalités de conversion/réorganisation de la base
+======================================================
+
+II.1 - Enumérations simples
+---------------------------
+
+dynamic:tables.describe_enums()
+
+II.2 - Collections
+------------------
+
+Ancien nom de table : support
+
+Nouveau nom de table : media_collections
+
+II.2.1 - Champs convertis
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+dynamic:tables.media_collections.describe_conversion()
+
+II.2.2 - Nouveaux champs
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+dynamic:tables.media_collections.describe_new_fields()
+
+II.2.3 - Champs supprimés
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+dynamic:tables.media_collections.describe_removed_fields()
+
+II.3 - Items 
+------------
+
+Ancien nom de table : phono
+
+Nouveau nom de table : media_items
+
+II.3.1 - Champs convertis
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+dynamic:tables.media_items.describe_conversion()
+
+II.3.2 - Nouveaux champs
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+dynamic:tables.media_items.describe_new_fields()
+
+II.3.3 - Champs supprimés
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+dynamic:tables.media_items.describe_removed_fields()
+
+II.4 - Sélections 
+-----------------
+
+II.4.1 - Liste
+~~~~~~~~~~~~~~
+
+Nom de table:
+dynamic:tables.media_playlists.name
+
+dynamic:tables.media_playlists.describe_new_fields()
+
+II.4.2 - Table de relation interne
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Nom de table:
+dynamic:tables.media_playlist_resources.name
+
+dynamic:tables.media_playlist_resources.describe_new_fields()
+
+II.5 - Thesaurus Géographique
+-----------------------------
+
+II.5.1 - Lieux
+~~~~~~~~~~~~~~
+
+Nom de table:
+dynamic:tables.locations.name
+
+dynamic:tables.locations.describe_new_fields()
+
+II.5.2 - Alias des lieux
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Nom de table:
+dynamic:tables.location_aliases.name
+
+dynamic:tables.location_aliases.describe_new_fields()
+
+II.5.3 - Relations hiérarchiques
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Nom de table:
+dynamic:tables.location_relations.name
+
+dynamic:tables.location_relations.describe_new_fields()
+
+II.6 - Utilisateurs
+-------------------
+
+Nom de table: 
+dynamic:tables.users.name
+
+dynamic:tables.users.describe_new_fields()
diff --git a/trunk/docref/spec/elements.py b/trunk/docref/spec/elements.py
new file mode 100644 (file)
index 0000000..e46b8d7
--- /dev/null
@@ -0,0 +1,136 @@
+#coding: utf-8
+import sqlalchemy
+import texttable
+
+def make_table(rows, width=20):
+    return texttable.indent(rows, hasHeader = True, separateRows = True,
+        prefix=u'| ', postfix=u' |',
+        wrapfunc = lambda x: texttable.wrap_onspace(x, width=width))
+        
+def describe_enums(metadata):
+    rows = [['Nom interne', 'Ancien nom', 'Description']]
+    for enum in metadata.enums:
+        rows.append([enum.name, enum.old_name, enum.label])
+    return make_table(rows, 40)
+
+class Column(sqlalchemy.Column):
+    old_name = ''
+    label = ''
+    desc = ''
+    dc = ''
+    comment = ''
+    conversion = ''
+    enum = None
+
+    def __init__(self, name, type, *args, **kwargs):
+        parent_args = {}
+        for key, value in kwargs.items():
+            if key == 'old_name':
+                if isinstance(value, list):
+                    self.old_name = unicode(",\n".join(value), 'utf-8')
+                    #self.old_name = []
+                    #for item in value:
+                    #    self.old_name.append(unicode(item, 'utf-8'))
+                else:
+                    self.old_name = unicode(value, 'utf-8')
+            elif key == 'label':
+                self.label = unicode(value, 'utf-8')
+            elif key == 'desc':
+                self.desc = unicode(value, 'utf-8')
+            elif key == 'dc':
+                self.dc = value
+            elif key == 'comment':
+                self.comment = unicode(value, 'utf-8')
+            elif key == 'conversion':
+                self.conversion = unicode(value, 'utf-8')
+            else:
+                parent_args[key] = value
+        
+        if isinstance(type, Enumeration):
+            args = (sqlalchemy.ForeignKey(type.name + '.id'),) + args
+            self.enum = type
+            type = sqlalchemy.Integer
+
+        super(Column, self).__init__(name, type, *args, **parent_args)
+
+class RemovedColumn(object):
+    old_name = ''
+    comment = ''
+
+    def __init__(self, old_name, comment=''):
+        self.old_name = unicode(old_name, 'utf-8')
+        self.comment = unicode(comment, 'utf-8')
+
+class Table(sqlalchemy.Table):
+
+    def __init__(self, table_name, metadata, label, *args):
+        self.label = unicode(label, 'utf-8')
+        real_columns = []
+        self.removed_columns = []
+        for column in args:
+            if isinstance(column, RemovedColumn):
+                self.removed_columns.append(column)
+            else:
+                real_columns.append(column)
+        super(Table, self).__init__(table_name, metadata, *real_columns) 
+
+
+    def describe_new_fields(self):
+        rows = [['Nom', 'Nom interne', 'Dublin Core']]
+        for column in self.columns:
+            if not column.old_name:
+                rows.append([column.label, column.name, column.dc])
+        
+        return make_table(rows)
+
+    def describe_conversion(self):        
+        rows = [['Nouveau nom', 'Ancien nom', 'Nouveau nom interne', 'Dublin Core']]
+        for column in self.columns:
+            if column.old_name:
+                rows.append([column.label, column.old_name, column.name, column.dc])
+        
+        return make_table(rows)
+            
+    def describe_removed_fields(self):        
+        rows = [['Nom', 'Commentaire']]
+        for column in self.removed_columns:
+            rows.append([column.old_name, column.comment])
+        
+        return make_table(rows, 50)
+
+    def to_dot(self):
+        dot  = u'digraph g {\n'
+        dot += '  charset = "utf-8";\n'
+        dot += '  node [shape=record, charset="utf-8"];\n'
+        dot += '  rankdir = LR;\n'
+        dot += '  subgraph cluster_new_fields {\n'
+        dot += '    label = "Nouveaux champs";\n'
+        dot += '    color = black;\n'
+        old_fields = ''
+        conversion = ''
+        for column in self.columns:
+            dot += '    ' + column.name + '[label = "{' + column.label + ' | ' + column.name + '}"];\n'
+            if column.old_name:
+                old_fields += '    old_' + column.name + '[label = "' + column.old_name  + '"];\n'
+                conversion += '  old_' + column.name + ' -> ' + column.name + ';\n'
+        dot += '  }\n'            
+        dot += '  subgraph cluster_old_fields {\n'
+        dot += '    label = "Anciens champs";\n'
+        dot += '    color = black;\n'
+        dot += old_fields
+        dot += '  }\n'            
+        dot += conversion
+        dot += '}\n'            
+        return dot            
+
+class Enumeration(Table):
+
+    def __init__(self, name, metadata, label='', old_name=''):
+        self.old_name = unicode(old_name, 'utf-8')
+        if not hasattr(metadata, 'enums'):
+            metadata.enums = []
+        metadata.enums.append(self)
+        super(Enumeration, self).__init__(name, metadata, label,
+            Column('id', sqlalchemy.Integer, primary_key=True),
+            Column('value', sqlalchemy.String(250), unique=True)
+        )
diff --git a/trunk/docref/spec/parse.py b/trunk/docref/spec/parse.py
new file mode 100644 (file)
index 0000000..535832c
--- /dev/null
@@ -0,0 +1,18 @@
+
+import tables
+import codecs
+input = codecs.open('docref.txt', 'r', "utf-8")
+output = codecs.open('build/docref.txt', 'w', "iso-8859-1")
+
+for line in input:
+    if line[0:8] == 'dynamic:':
+        output.write(eval(line[8:], globals(), locals()) + "\n")
+    else:
+        output.write(line)
+
+input.close()
+output.close()
+
+output = codecs.open('build/collections.dot', 'w', 'utf-8')
+output.write(tables.media_collections.to_dot())
+output.close()
diff --git a/trunk/docref/spec/staticenum.py b/trunk/docref/spec/staticenum.py
new file mode 100644 (file)
index 0000000..d364f5b
--- /dev/null
@@ -0,0 +1,69 @@
+#!python\r
+\r
+## The MIT License\r
+\r
+## Copyright (c) <year> <copyright holders>\r
+\r
+## Permission is hereby granted, free of charge, to any person obtaining a copy\r
+## of this software and associated documentation files (the "Software"), to deal\r
+## in the Software without restriction, including without limitation the rights\r
+## to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
+## copies of the Software, and to permit persons to whom the Software is\r
+## furnished to do so, subject to the following conditions:\r
+\r
+## The above copyright notice and this permission notice shall be included in\r
+## all copies or substantial portions of the Software.\r
+\r
+## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
+## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
+## AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
+## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
+## OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r
+## THE SOFTWARE.\r
+\r
+\r
+from sqlalchemy import types, exceptions\r
+\r
+class StaticEnum(types.TypeDecorator):\r
+    impl = types.Unicode\r
+    \r
+    def __init__(self, values, empty_to_none=False, strict=False):\r
+        """Emulate an Enum type.\r
+\r
+        values:\r
+           A list of valid values for this column\r
+        empty_to_none:\r
+           Optional, treat the empty string '' as None\r
+        strict:\r
+           Also insist that columns read from the database are in the\r
+           list of valid values.  Note that, with strict=True, you won't\r
+           be able to clean out bad data from the database through your\r
+           code.\r
+        """\r
+\r
+        if values is None or len(values) is 0:\r
+            raise exceptions.AssertionError('StaticEnum requires a list of values')\r
+        self.empty_to_none = empty_to_none\r
+        self.strict = strict\r
+        self.values = values[:]\r
+\r
+        # The length of the string/unicode column should be the longest string\r
+        # in values\r
+        size = max([len(v) for v in values if v is not None])\r
+        super(StaticEnum, self).__init__(size)        \r
+        \r
+        \r
+    def convert_bind_param(self, value, engine):\r
+        if self.empty_to_none and value is '':\r
+            value = None\r
+        if value not in self.values:\r
+            raise exceptions.AssertionError('"%s" not in StaticEnum.values' % value)\r
+        return super(StaticEnum, self).convert_bind_param(value, engine)\r
+        \r
+        \r
+    def convert_result_value(self, value, engine):\r
+        if self.strict and value not in self.values:\r
+            raise exceptions.AssertionError('"%s" not in StaticEnum.values' % value)\r
+        return super(StaticEnum, self).convert_result_value(value, engine)\r
+\r
diff --git a/trunk/docref/spec/tables.py b/trunk/docref/spec/tables.py
new file mode 100644 (file)
index 0000000..41fd6d4
--- /dev/null
@@ -0,0 +1,331 @@
+#coding: utf-8
+
+import sqlalchemy
+from sqlalchemy import String, Integer, ForeignKey, Time, Date, MetaData, Text, Boolean
+from elements import Column, RemovedColumn, Table, Enumeration
+import elements
+from staticenum import StaticEnum
+
+metadata = MetaData()
+def describe_enums():
+    return elements.describe_enums(metadata)
+
+# Users
+
+users = Table('users', metadata, 'Utilisateurs',
+    Column('username', String(250), primary_key=True, label='Nom d\'utilisateur'),
+    Column('level', StaticEnum('user,maintainer,administrator'), label='Niveau de permissions'),
+    Column('first_name', String(250), label='Prénom'),
+    Column('last_name', String(250), label='Nom'),
+    Column('phone', String(250), label='Téléphone'),
+    Column('email', String(250), label='E-Mail')
+)    
+
+# Playlists
+
+media_playlists = Table('playlists', metadata, 'Sélections personelles d\'items et de collections',
+    Column('id', Integer, primary_key='true', label='Identifiant'),
+    Column('owner_username', String(250), ForeignKey('users.username'), label='Propriétaire'),
+    Column('name', String(250), label='Intitulé'))
+
+media_playlist_resources = Table('playlist_resources', metadata, 'Ressources associées aux sélections personelles ',
+    Column('playlist_id', Integer, ForeignKey('playlists.id'), label='Identifiant de la sélection'),
+    Column('resource_type', StaticEnum('item', 'collection'), label='Type de ressource (item, collection)'),
+    Column('resource_id', String(250), label='Identifiant de la ressource')
+)
+
+# Simple enumerations
+
+physical_formats = Enumeration('physical_formats', metadata, 'Formats physiques', old_name='Format (e)')
+publishing_status = Enumeration('publishing_status', metadata, 'Status d\'édition/réédition', old_name='Réédition (e)')
+publishers = Enumeration('publishers', metadata, 'Editeurs', old_name='Editeur1 (e)')
+acquisition_modes = Enumeration('acquisition_modes', metadata, 'Modes d\'acquisition', old_name='Mode_Acqui (e)')
+metadata_authors = Enumeration('record_authors', metadata, 'Rédacteurs des fiches', old_name='Rédacteur_Fiche (e)')
+metadata_writers = Enumeration('metadata_writers', metadata, 'Opérateur de saisie des fiches', old_name='Saisie_Fiche (e)')
+legal_rights = Enumeration('legal_rights', metadata, 'Statuts juridiques', old_name='Droit_d\'Utiliser (e)')
+recording_contexts = Enumeration('recording_contexts', metadata, 'Contextes d\'enregistrement', old_name='Terrain_ou_Autre (e)')
+ad_conversions = Enumeration('ad_conversions', metadata, 'Statuts de numérisation', old_name='Numérisation (e)')
+ethnic_groups = Enumeration('ethnic_groups', metadata, 'Ethnies/Groupe social', old_name='Ethnie (t)')
+vernacular_styles = Enumeration('vernacular_styles', metadata, 'Forme / genre vernaculaire', old_name='Form (t)')
+generic_styles = Enumeration('generic_styles', metadata, 'Forme / genre générique', old_name='FormStyle générique (e)')
+context_keywords = Enumeration('context_keywords', metadata, 'Mots clés du contexte ethnographique', old_name='Mot_Clef (t)')
+publisher_collections = Enumeration('publisher_collections', metadata, 'Collections éditeur', old_name='Collection_Série (e)')
+
+# Geographic Thesaurus
+
+location_types = Enumeration('location_types', metadata, 'GeoEthno / Types de lieux')
+
+locations = Table('locations', metadata, 'GeoEthno / Lieux)',
+    Column('name', String(127), primary_key=True, label='Terme descripteur'),
+    Column('type', StaticEnum('country', 'continent', 'other')),
+    Column('complete_type', location_types),
+    Column('current_name', String(127), ForeignKey('locations.name'), label='Nom actuel'),
+    Column('is_authoritative', Boolean),
+)
+
+location_aliases = Table('location_aliases', metadata, 'GeoEthno / Alias des lieux',
+    Column('location_name', String(127), ForeignKey('locations.name'), primary_key=True),
+    Column('alias', String(127), primary_key=True),
+    Column('is_authoritative', Boolean))
+
+location_relations = Table('location_relations', metadata, 'GeoEthno / Relations hiérachiques',
+    Column('location_name', String(127), ForeignKey('locations.name'), primary_key=True),
+    Column('parent_location_name', String(127), ForeignKey('locations.name'), primary_key=True)
+)    
+
+# Media Collections
+
+media_collections = Table('media_collections', metadata, 'Collections',
+    Column('reference', 
+        String(250), unique=True, 
+        old_name='Réf', label='Référence'),
+    Column('physical_format_id', 
+        physical_formats,
+        old_name='Format', label='Format', 
+        desc="Format du 1er exemplaire archivé"),
+    Column('old_id', 
+        String(250), 
+        old_name='Cote', label='Ancienne cote'),
+    Column('id', 
+        String(250), primary_key=True, 
+        dc='identifier',
+        label='Cote', conversion='à préciser'),
+    Column('title', 
+        String(250), 
+        dc='title',
+        old_name='Titre', label='Titre'),
+    Column('native_title', 
+        String(250), 
+        dc='title',
+        old_name='Transcrip_Trad', label='Traduction du titre'),
+    Column('physical_items_num', 
+        Integer, 
+        old_name='Nb_de_pieces', label='Nombre de supports physiques'),
+    Column('publishing_status_id', 
+        publishing_status,
+        old_name='Réédition', label='Réédition'),
+    RemovedColumn(old_name='Original'),
+    RemovedColumn(old_name='Copie_TotPartie'),
+    RemovedColumn(old_name='Copié_de'),
+    Column('creator', 
+        String(250), 
+        dc='creator',
+        old_name='Auteur_Compil', label='Auteur / Cédant'),
+    Column('booklet_author', 
+        String(250),
+        dc='contributor',
+        old_name='Auteur_Notice', label='Auteur notice'),
+    Column('booklet_description', 
+        Text, 
+        old_name='Notice', label='Notice / Dossier technique'),
+    Column('collector',
+        Text, 
+        dc='contributor',
+        old_name='Collecteur', label='Collecteur'),
+    Column('publisher_id', 
+        publishers,
+        dc='publisher',
+        old_name='Editeur', label='Editeur', 
+        desc='Pour les documents ÉDITÉS:Nom et État de l\'Editeur. Pour les INÉDITS :voir champ "Type de document".'),
+    Column('year_published', 
+        Integer,
+        dc='date',
+        old_name='Année_parution', label='Année de parution',
+        desc='Ne concerne que les documents ÉDITÉS.',
+        conversion='à préciser, traiter les nombres négatifs ?'),
+    Column('publisher_collection', 
+        publisher_collections,
+        old_name='Collect_Série', label='Collection éditeur',
+        comment='faux: nom de la collection, suivi du n° dans la collection.'),
+    Column('publisher_serial',
+        String(250),
+        old_name='Num_Dans_Collec', label='Numéro de série',
+        desc='Numéro de série dans la collection éditeur', 
+        comment='à valider'),
+    Column('external_references', 
+        Text,
+        old_name='Réf_Biblio', label='Bibliographie', 
+        desc='Références biblio/disco/filmographiques, uniquement liées à ce support'),
+    Column('acquisition_mode_id',
+        acquisition_modes,
+        old_name='Mod_Acqui', label='Mode d\'acquisition'),
+    Column('comment',
+        Text,
+        old_name='Commentaire', label='Commentaire'),
+    Column('metadata_author_id', 
+        metadata_authors,
+        dc='contributor',
+        old_name='Rédacteur_Fiche', label='Rédacteur fiche',
+        desc='Responsable de l\'analyse documentaire'),
+    Column('metadata_writer_id',
+        metadata_writers,
+        old_name='Saisie_Fiche', label='Saisie fiches',
+        desc='Personne qui a saisi les fiches dans la base de données.'),
+    Column('legal_rights_id',
+        legal_rights,
+        dc='rights',
+        old_name='Droit_Utiliser', label='Statut juridique'),
+    Column('alt_ids', 
+        String(250),
+        old_name='Autres_Cotes', label='Autres exemplaires'),
+    Column('recorded_from_year',
+        Integer,
+        dc='date',
+        old_name='Année_Enreg', label='Années d\'enregistrement',
+        conversion="split"),
+    Column('recorded_to_year',
+        Integer,
+        dc='date',
+        old_name='Année_Enreg', label='Années d\'enregistrement',
+        conversion="split"),
+    Column('recording_context_id',
+        recording_contexts, 
+        old_name='Terrain_ou_Autr', label='Contexte d\'enregistrement'),
+    Column('approx_duration', 
+        Time(),
+        old_name='Durée_approx', label='Durée approximative'),
+    Column('doctype_code', 
+        Integer,
+        old_name='Tri_DiBm', label='Type de document'), 
+    Column('travail', 
+        String(250),
+        old_name='Travail', label='?'), 
+    Column('state',
+        String(250),
+        old_name='Compil_Face_Plage', label="Etat"),
+    Column('cnrs_contributor',
+        String(250),
+        old_name='Déposant_CNRS', label="Déposant CNRS",
+        desc='Pour les INÉDITS uniquement. Signale les collectes ayant bénéficées d\'une aide du CNRS.'), 
+    Column('items_done',
+        String(250),
+        old_name='Fiches', label='Fiches faîtes', 
+        desc="Signale que les fiches Item de ce support sont présentes dans la base."),
+    Column('a_informer_07_03',
+        String(250),
+        old_name='A informer_07-03', label='?'), 
+    Column('ad_conversion_id',
+        ad_conversions,
+        old_name='Numérisation', label="Historique de numérisation"),
+    RemovedColumn(old_name='Champ36'),
+)
+
+# Media Items
+
+media_item_context_keywords = Table('media_item_context_keywords', metadata, 
+    'Mots clés associés à un item',
+    Column('media_item_id', Integer, ForeignKey('media_items.id')),
+    Column('context_keyword_id', context_keywords))
+
+media_items = Table('media_items', metadata, 'Items',
+    RemovedColumn(old_name='Réf', comment='Calculé en temps réel à partir de la collection'),
+    Column('collection_id', 
+        String(250), ForeignKey('media_collections.id'), 
+        dc='relation/isPartOf',
+        label='Collection'),
+    RemovedColumn(old_name='Format', comment='Calculé en temps réel à partir de la collection'),
+    RemovedColumn(old_name='Cote_Support', comment='Calculé en temps réel à partir de la collection'),
+    Column('track',
+        String(250),
+        old_name="Face_Plage", label="N° de l'item"),
+    Column('id', 
+        String(250),
+        old_name='Cote_Phono', label="Cote item"),
+    Column('approx_duration', 
+        Time(),
+        old_name='Durée', label='Durée'),
+    Column('recorded_from_date',
+        Date(),
+        dc='date',
+        old_name='Date_enregistr', label='Date', desc='Date de l\'enregistrement'),
+    Column('recorded_to_date',
+        Date(),
+        dc='date',
+        old_name='Date_enregistr', label='Date'),
+    Column('location_name',
+        Integer, ForeignKey('locations.name'),
+        dc='coverage',
+        old_name=['Continent', 'Etat', 'Région_Village'], label='Lieu',
+        desc='(?) Lieu de provenance de la  musique. Si le lieu de l\'enregistrement est autre, l\'indiquer en "Remarques".'),
+    Column('location_comment',
+        String(250),
+        old_name='Région_Village', label='Commentaire lieu'),
+    Column('ethnic_group_id',
+        ethnic_groups,
+        old_name='Ethnie_GrSocial', label='Ethnie/Groupe social', comment='attention alias ethnies'),
+    RemovedColumn(old_name='Titre_Support', comment='Calculé en temps réel à partir de la collection'),
+    Column('title', 
+        String(250),
+        dc='title', 
+        old_name='Titre_pièce', label='Titre Item'),
+    Column('native_title', 
+        String(250),
+        dc='title', 
+        old_name='Transcrip_Trad', label='Traduction du titre', 
+        desc='Traduction des langues non communes, plus translittération des langues n\'utilisant pas l\'alphabet latin.'),
+    Column('author',
+        String(250),
+        dc='creator',
+        old_name='Auteur', label='Auteur',
+        desc='Le cas échéant, faire suivre le nom par une mention "-auteur /-compositeur / -arrangeur"'),
+    Column('vernacular_style_id',
+        vernacular_styles,
+        old_name='Form_Genr_Style', label='Forme / genre vernaculaire [nom à revoir]', 
+        desc='Nom local de la forme ou du genre'),
+    RemovedColumn(old_name='Struct_Modale'),        
+    RemovedColumn(old_name='Struct_Rythm'), 
+    RemovedColumn(old_name='Struct_Rythm'), 
+    RemovedColumn(old_name='Fonction_Usage', 
+        comment='Champ inutile, les mots clés sont associés via une table de relation externe'), 
+    Column('context_comment',
+        Text,
+        old_name='Comm_FonctUsage', label='Contexte ethnographique : commentaires'),
+    Column('external_references', 
+        String(250),
+        old_name='Documentation', label='Références', 
+        desc='Références directement liées à l\'item.'),
+    Column('moda_execut', 
+        String(250),
+        old_name='Moda_Execut', comment='à supprimer ?'),
+    Column('copied_from_item_id',
+        String(250), ForeignKey('media_items.id'),
+        dc='relation/isVersionOf',
+        old_name='Copie_de', label='Copie de'),
+    Column('collector',
+        String(250),
+        dc='contributor',
+        old_name='Enregistré_par', label='Collecteur'),
+    Column('cultural_area',
+        String(250),
+        old_name='Aire culturelle', label='Aire culturelle'),
+    RemovedColumn(old_name='Année_Enreg', 
+        comment='calculé en temps-réel à partir de la date d\'enregistrement'),
+    Column('generic_style',
+        generic_styles,
+        old_name='FormStyl généri', label='Forme / genre générique'),
+    Column('collector_selection',
+        String(250),
+        old_name='ChoixCollecteur', label='Choix du collecteur', 
+        desc='Permet au collecteur de repérer les items les plus intéressants'),
+    RemovedColumn(old_name='Repère_bande'),        
+    Column('creator_reference', 
+        String(250),
+        old_name='NroBandNroPièc', label='Référence du déposant'),    
+)                        
+                
+
+            
+            
+            
+            
+            
+
+            
+
+            
+    
+
+        
+
+
+
diff --git a/trunk/docref/spec/texttable.py b/trunk/docref/spec/texttable.py
new file mode 100644 (file)
index 0000000..3d07d25
--- /dev/null
@@ -0,0 +1,155 @@
+#coding: utf-8
+import cStringIO,operator
+
+def indent(rows, hasHeader=False, headerChar=u'-', delim=u' | ', justify=u'left',
+           separateRows=False, prefix=u'', postfix=u'', wrapfunc=lambda x:x):
+    """Indents a table by column.
+       - rows: A sequence of sequences of items, one sequence per row.
+       - hasHeader: True if the first row consists of the columns' names.
+       - headerChar: Character to be used for the row separator line
+         (if hasHeader==True or separateRows==True).
+       - delim: The column delimiter.
+       - justify: Determines how are data justified in their column. 
+         Valid values are 'left','right' and 'center'.
+       - separateRows: True if rows are to be separated by a line
+         of 'headerChar's.
+       - prefix: A string prepended to each printed row.
+       - postfix: A string appended to each printed row.
+       - wrapfunc: A function f(text) for wrapping text; each element in
+         the table is first wrapped by this function."""
+    # closure for breaking logical rows to physical, using wrapfunc
+    def rowWrapper(row):
+        newRows = [wrapfunc(item).split('\n') for item in row]
+        return [[substr or '' for substr in item] for item in map(None,*newRows)]
+    # break each logical row into one or more physical ones
+    logicalRows = [rowWrapper(row) for row in rows]
+    # columns of physical rows
+    columns = map(None,*reduce(operator.add,logicalRows))
+    # get the maximum of each column by the string length of its items
+    maxWidths = [max([len(item) for item in column]) for column in columns]
+    rowSeparator = u"+" + u"+".join([u'-' * (width + len(delim) - 1) for width in maxWidths]) + u"+"
+    headerSep = u"+" + u"+".join([u'=' * (width + len(delim) - 1) for width in maxWidths]) + u"+"
+    #headerChar * (len(prefix) + len(postfix) + sum(maxWidths) + \
+    #                             len(delim)*(len(maxWidths)-1))
+    #headerSep = u"=" * (len(prefix) + len(postfix) + sum(maxWidths) + \
+    #                             len(delim)*(len(maxWidths)-1))                                
+    # select the appropriate justify method
+    #justify = {'center':str.center, 'right':str.rjust, 'left':str.ljust}[justify.lower()]
+    output=u''
+    if separateRows: 
+        output += rowSeparator + "\n"
+
+    for physicalRows in logicalRows:
+        for row in physicalRows:
+            output += \
+                prefix \
+                + delim.join([item.ljust(width) for (item,width) in zip(row,maxWidths)]) \
+                + postfix + "\n"
+        if hasHeader: output += headerSep + "\n"; hasHeader=False
+        elif separateRows: output += rowSeparator + "\n"
+    return output
+
+# written by Mike Brown
+# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/148061
+def wrap_onspace(text, width):
+    """
+    A word-wrap function that preserves existing line breaks
+    and most spaces in the text. Expects that existing line
+    breaks are posix newlines (\n).
+    """
+    return reduce(lambda line, word, width=width: '%s%s%s' %
+                  (line,
+                   ' \n'[(len(line[line.rfind('\n')+1:])
+                         + len(word.split('\n',1)[0]
+                              ) >= width)],
+                   word),
+                  text.split(' ')
+                 )
+
+import re
+def wrap_onspace_strict(text, width):
+    """Similar to wrap_onspace, but enforces the width constraint:
+       words longer than width are split."""
+    wordRegex = re.compile(r'\S{'+str(width)+r',}')
+    return wrap_onspace(wordRegex.sub(lambda m: wrap_always(m.group(),width),text),width)
+
+import math
+def wrap_always(text, width):
+    """A simple word-wrap function that wraps text on exactly width characters.
+       It doesn't split the text in words."""
+    return '\n'.join([ text[width*i:width*(i+1)] \
+                       for i in xrange(int(math.ceil(1.*len(text)/width))) ])
+    
+if __name__ == '__main__':
+    labels = ('First Name', 'Last Name', 'Age', 'Position')
+    data = \
+    '''John,Smith,24,Software Engineer
+       Mary,Brohowski,23,Sales Manager
+       Aristidis,Papageorgopoulos,28,Senior Reseacher'''
+    rows = [row.strip().split(',')  for row in data.splitlines()]
+
+    print 'Without wrapping function\n'
+    print indent([labels]+rows, hasHeader=True)
+    # test indent with different wrapping functions
+    width = 10
+    for wrapper in (wrap_always,wrap_onspace,wrap_onspace_strict):
+        print 'Wrapping function: %s(x,width=%d)\n' % (wrapper.__name__,width)
+        print indent([labels]+rows, hasHeader=True, separateRows=True,
+                     prefix='| ', postfix=' |',
+                     wrapfunc=lambda x: wrapper(x,width))
+    
+    # output:
+    #
+    #Without wrapping function
+    #
+    #First Name | Last Name        | Age | Position         
+    #-------------------------------------------------------
+    #John       | Smith            | 24  | Software Engineer
+    #Mary       | Brohowski        | 23  | Sales Manager    
+    #Aristidis  | Papageorgopoulos | 28  | Senior Reseacher 
+    #
+    #Wrapping function: wrap_always(x,width=10)
+    #
+    #----------------------------------------------
+    #| First Name | Last Name  | Age | Position   |
+    #----------------------------------------------
+    #| John       | Smith      | 24  | Software E |
+    #|            |            |     | ngineer    |
+    #----------------------------------------------
+    #| Mary       | Brohowski  | 23  | Sales Mana |
+    #|            |            |     | ger        |
+    #----------------------------------------------
+    #| Aristidis  | Papageorgo | 28  | Senior Res |
+    #|            | poulos     |     | eacher     |
+    #----------------------------------------------
+    #
+    #Wrapping function: wrap_onspace(x,width=10)
+    #
+    #---------------------------------------------------
+    #| First Name | Last Name        | Age | Position  |
+    #---------------------------------------------------
+    #| John       | Smith            | 24  | Software  |
+    #|            |                  |     | Engineer  |
+    #---------------------------------------------------
+    #| Mary       | Brohowski        | 23  | Sales     |
+    #|            |                  |     | Manager   |
+    #---------------------------------------------------
+    #| Aristidis  | Papageorgopoulos | 28  | Senior    |
+    #|            |                  |     | Reseacher |
+    #---------------------------------------------------
+    #
+    #Wrapping function: wrap_onspace_strict(x,width=10)
+    #
+    #---------------------------------------------
+    #| First Name | Last Name  | Age | Position  |
+    #---------------------------------------------
+    #| John       | Smith      | 24  | Software  |
+    #|            |            |     | Engineer  |
+    #---------------------------------------------
+    #| Mary       | Brohowski  | 23  | Sales     |
+    #|            |            |     | Manager   |
+    #---------------------------------------------
+    #| Aristidis  | Papageorgo | 28  | Senior    |
+    #|            | poulos     |     | Reseacher |
+    #---------------------------------------------
+
diff --git a/trunk/docref/tools/analyse_collection_ids.py b/trunk/docref/tools/analyse_collection_ids.py
new file mode 100644 (file)
index 0000000..d180f55
--- /dev/null
@@ -0,0 +1,150 @@
+import MySQLdb
+import _mysql_exceptions
+import re
+from sys import stdout
+
+"""
+CREATE TABLE `coll` (
+  `cote` varchar(255) default NULL,
+  `format` varchar(255) default NULL,
+  `regex` varchar(255) default NULL,
+  `new_id` varchar(64) default NULL,
+  `dup` BOOLEAN NOT NULL,
+  UNIQUE KEY `new_id` (`new_id`),
+  UNIQUE KEY `cote` (`cote`)
+)
+"""
+
+
+collection_patterns = [
+    { 'format': 'BM.aaa.nnn.mmm',           'regex': r'^(BM)\.([0-9]{3})\.([0-9]{3})\.([0-9]{3})$'}, 
+    { 'format': 'BM.aaaa.nnn.mmm/pp',       'regex': r'^(BM)\.([0-9]{4})\.([0-9]{3})\.([0-9]{3})/[0-9]{2}$'}, 
+    { 'format': 'BM.aaaa.nnn.mmm',          'regex': r'^(BM)\.([0-9]{4})\.([0-9]{3})\.([0-9]{3})$'}, 
+    { 'format': 'BM.aaaa.nnn.mmm/',         'regex': r'^(BM)\.([0-9]{4})\.([0-9]{3})\.([0-9]{3})/$'}, 
+    { 'format': 'BM.aaaa.nnn.mmm/ppp',      'regex': r'^(BM)\.([0-9]{4})\.([0-9]{3})\.([0-9]{3})/[0-9]{3}$'}, 
+    { 'format': 'BM.aaaa.nnn.mm/pp',        'regex': r'^(BM)\.([0-9]{4})\.([0-9]{3})\.([0-9]{2})/[0-9]{2}$'}, 
+    { 'format': 'BM.aaaa.nnn',              'regex': r'^(BM)\.([0-9]{4})\.([0-9]{3})$'}, 
+    { 'format': 'BM.aaa.nnn.mmm/pp',        'regex': r'^(BM)\.([0-9]{3})\.([0-9]{3})\.([0-9]{3})/[0-9]{2}$'}, 
+    { 'format': 'BM.aaa.nnn FANTOME',       'regex': r'^(BM)\.([0-9]{3})\.([0-9]{3}) FANTOME$'}, 
+    { 'format': 'BM.aaa.nnn',               'regex': r'^(BM)\.([0-9]{3})\.([0-9]{3})$'}, 
+    { 'format': 'BM.aaa.nnnBISoo/pp',       'regex': r'^(BM)\.([0-9]{3})\.([0-9]{3})BIS([0-9]{2})/[0-9]{2}$'}, 
+    { 'format': 'BM.aaa.nnn.mmm.ppp',       'regex': r'^(BM)\.([0-9]{3})\.([0-9]{3})\.([0-9]{3})\.[0-9]{3}$'}, 
+    { 'format': 'BM.aaa.nnn.mmm/ppp',       'regex': r'^(BM)\.([0-9]{3})\.([0-9]{3})\.([0-9]{3})/[0-9]{3}$'}, 
+    { 'format': 'BM.aaa.nnn/pp',            'regex': r'^(BM)\.([0-9]{3})\.([0-9]{3})/[0-9]{2}$'}, 
+    { 'format': 'BM.aaa.nnn-BIS.ooo/pp',    'regex': r'^(BM)\.([0-9]{3})\.([0-9]{3})-BIS\.([0-9]{3})/[0-9]{2}$'}, 
+    { 'format': 'BM.aaaa.nnn.mmm/NN',       'regex': r'^(BM)\.([0-9]{4})\.([0-9]{3})\.([0-9]{3})/NN$'}, 
+    { 'format': 'BM.aaa.nnn.mmm/pp-DEPOT',  'regex': r'^(BM)\.([0-9]{3})\.([0-9]{3})\.([0-9]{3})/[0-9]{2}-DEPOT$'}, 
+    { 'format': 'BM.aaa.nnn.mmm-o>p',       'regex': r'^(BM)\.([0-9]{3})\.([0-9]{3})\.([0-9]{3})-[0-9]>[0-9]$'}, 
+    { 'format': 'CY.aaaa.nnn',              'regex': r'^(CY)\.([0-9]{4})\.([0-9]{3})$'}, 
+    { 'format': 'DI.aaaa.nnn.mmm',          'regex': r'^(DI)\.([0-9]{4})\.([0-9]{3})\.([0-9]{3})$'}, 
+    { 'format': 'DI.aaaa.nnn.mmm/pp',       'regex': r'^(DI)\.([0-9]{4})\.([0-9]{3})\.([0-9]{3})/[0-9]{2}$'}, 
+    { 'format': 'DI.aaa.nnn.mmm',           'regex': r'^(DI)\.([0-9]{3})\.([0-9]{3})\.([0-9]{3})$'}, 
+    { 'format': 'DI.aaa.nnn.mmm/pp',        'regex': r'^(DI)\.([0-9]{3})\.([0-9]{3})\.([0-9]{3})/[0-9]{2}$'}, 
+    { 'format': 'DI.aaa.nnn.mmm-o/p',       'regex': r'^(DI)\.([0-9]{3})\.([0-9]{3})\.([0-9]{3})-[0-9]/[0-9]$'}, 
+    { 'format': 'FANTOME 2*',               'regex': r'FANTOME 2\*$'}, 
+]
+
+db = MySQLdb.connect(user='root', db='test');
+
+rcursor = db.cursor()
+wcursor = db.cursor()
+
+wcursor.execute("UPDATE coll SET format='', new_id = NULL, dup = 0")
+
+nrow = 0
+for pattern in collection_patterns:
+    stdout.write('* format: ' + pattern['format'] + '\n')
+    wcursor.execute("UPDATE coll SET format=%s WHERE cote REGEXP %s",
+        (pattern['format'], pattern['regex']))
+    rcursor.execute("SELECT COUNT(*) FROM coll")        
+    row = rcursor.fetchone()
+    count = row[0]
+    rcursor.execute("SELECT cote FROM coll WHERE cote REGEXP %s", (pattern['regex'],))    
+    row = rcursor.fetchone()
+    while row:
+        if nrow % 200 == 0:
+            stdout.write("  row " + str(nrow) + "/" + str(count) + '\n')
+        id = row[0]
+        match = re.match(pattern['regex'], id)
+
+        published = False
+        year = -1
+        serial = -1
+        physical = -1
+
+        if (match.lastindex >= 1):
+            published = (match.group(1) == 'DI')
+        if (match.lastindex >= 2):
+            year = int(match.group(2)) 
+        if (match.lastindex >= 3):
+            serial = int(match.group(3))
+        if (match.lastindex >= 4):
+            physical = int(match.group(4)) 
+        
+        if (year == -1 or serial == -1):
+            stdout.write('    missing year or serial: ' + id + '\n')
+        else:            
+            tokens = []
+            if published:
+                tokens.append('CNRSMH_E')
+            else:                
+                tokens.append('CNRSMH_I')
+            
+            if year < 1000:
+                if year < 100:
+                    year += 2000
+                else:
+                    year += 1000
+            tokens.append(str(year))
+                            
+            tokens.append(str(serial).rjust(3, '0'))
+
+            if published:
+                if physical != -1:
+                    tokens.append(str(physical).rjust(3, '0'))
+                else:
+                    tokens.append('001')
+            
+            new_id = '_'.join(tokens)
+
+            try:
+                wcursor.execute("UPDATE coll SET new_id = %s WHERE cote = %s", (new_id, id))           
+            except _mysql_exceptions.IntegrityError, (errno, errstr):
+                if errno == 1062:
+                    stdout.write('    duplicate entry: ' + id + ' -> ' + new_id + '\n')
+                    wcursor.execute("UPDATE coll SET dup = 1 WHERE cote = %s", (id,))           
+                else:
+                    raise
+
+        row = rcursor.fetchone()
+        nrow += 1      
+
+rcursor.execute("SELECT format, cote, COUNT(*), SUM(dup) FROM coll GROUP BY format");
+
+stdout.write("\nFORMAT STATS:\n")
+row = rcursor.fetchone()
+stdout.write("format\texample\tcount\tduplicates\n");
+while row:
+    stdout.write(row[0] + "\t" + row[1] + "\t" + str(row[2]) + "\t" + str(row[3]) + '\n')
+    row = rcursor.fetchone()
+
+rcursor.execute("SELECT cote FROM coll WHERE new_id IS NULL AND dup = 1")
+stdout.write("\nUNCONVERTED IDs (duplicates):\n")
+row = rcursor.fetchone()
+while row:
+    stdout.write(row[0] + '\n')
+    row = rcursor.fetchone()
+    
+rcursor.execute("SELECT cote FROM coll WHERE new_id IS NULL AND dup = 0")
+stdout.write("\nUNCONVERTED IDs (non duplicates):\n")
+row = rcursor.fetchone()
+while row:
+    stdout.write(row[0] + '\n')
+    row = rcursor.fetchone()
+    
+    
+
+    
+            
+
+    
diff --git a/trunk/import/README b/trunk/import/README
new file mode 100644 (file)
index 0000000..7b6f193
--- /dev/null
@@ -0,0 +1,13 @@
+
+==========================================
+CREM data import instructions and programs
+==========================================
+
+* ``prototype`` : this directory contains scripts to perform an experimental
+  import of the CREM database into Telemeta 0.3.x. It is only meant as a
+  proof of concept.
+* ``raw_conversion`` : instructions and scripts to perform a full raw conversion 
+  of the CREM database from 4D to MySQL. The result has the same structure
+  as the original 4D database, and, as such, can't be used directly in 
+  Telemeta. 
+
diff --git a/trunk/import/prototype/README b/trunk/import/prototype/README
new file mode 100644 (file)
index 0000000..88c4a14
--- /dev/null
@@ -0,0 +1,37 @@
+==================================================
+CREM data and how to import it into Telemeta 0.3.x
+==================================================
+
+Warning: the following instructions allow you to import the CREM's data
+into telemeta. However, it is currently a rather data destructive process,
+only meant for demonstration and testing purpose. Do not use this in a
+production environment.
+
+1.  Install Telemeta upon MySQL. Initialize the database using Telemeta's
+    Django models. Ensure that everything is running fine before going any 
+    further.
+
+2.  Run prepare on the source directory. The source directory must contain
+    text files as they were exported from the 4D database. These files are 
+    expected to be gzipped. 
+
+    Example::
+
+    $ scripts/prepare src/2007-05-09
+
+3.  Use the import.sql script to insert the data into your MySQL database.
+
+    Example::
+
+    $ mysql your_telemeta_database < scripts/import.sql
+
+4.  Copy the WAV test file of your choice, into <MEDIA_ROOT>/items/test.wav
+    This single file is associated with all media items, for testing purpose.
+
+That should be it. If you want to run Telemeta against SQLite instead of 
+MySQL, first follow the above instructions to import the data into MySQL.
+Then convert your data from MySQL to SQLite, this is a common task, google 
+about it.
+
+
+
diff --git a/trunk/import/prototype/scripts/import.sql b/trunk/import/prototype/scripts/import.sql
new file mode 100644 (file)
index 0000000..0bb05be
--- /dev/null
@@ -0,0 +1,31 @@
+DELETE FROM telemeta_collection;
+LOAD DATA INFILE '/tmp/crem_import/support.txt' INTO TABLE telemeta_collection
+FIELDS TERMINATED BY '\t'
+LINES TERMINATED BY '\r\n';
+
+UPDATE telemeta_collection SET id=REPLACE(id, '/', '--');
+UPDATE telemeta_collection SET copied_from_id = NULL WHERE copied_from_id = '';
+
+DELETE FROM telemeta_item;
+LOAD DATA INFILE '/tmp/crem_import/phono.txt' INTO TABLE telemeta_item
+FIELDS TERMINATED BY '\t'
+LINES TERMINATED BY '\r\n';
+
+UPDATE telemeta_item SET id=REPLACE(id, ":", "__");
+UPDATE telemeta_item SET id=REPLACE(id, '/', '--');
+UPDATE telemeta_item SET id=REPLACE(id, '?', 'i');
+UPDATE telemeta_item SET collection_id=REPLACE(collection_id, '/', '--');
+UPDATE telemeta_item SET title='' WHERE title='N';
+UPDATE telemeta_item SET etat=REPLACE(etat, ')', '_');
+UPDATE telemeta_item SET etat=REPLACE(etat, '(', '_');
+UPDATE telemeta_item SET file="items/test.wav";
+
+DELETE FROM telemeta_physicalformat;
+INSERT INTO telemeta_physicalformat (value)
+    SELECT DISTINCT physical_format FROM telemeta_collection
+    WHERE physical_format <> '' AND physical_format IS NOT NULL;
+
+DELETE FROM telemeta_publishingstatus;
+INSERT INTO telemeta_publishingstatus (value)
+    SELECT DISTINCT publishing_status FROM telemeta_collection
+    WHERE publishing_status <> '' AND publishing_status IS NOT NULL;
diff --git a/trunk/import/prototype/scripts/prepare b/trunk/import/prototype/scripts/prepare
new file mode 100755 (executable)
index 0000000..92a7618
--- /dev/null
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+if [ "$1" == "" ]
+then 
+    echo "Please provide the source directory"
+    exit 1
+fi
+
+src=$1
+tmpdir=crem_import
+required="support.txt.gz phono.txt.gz"
+
+for f in $required
+do
+    if ! [ -f $src/$f ]
+    then 
+        echo "Can't find $f in $src"
+        exit 1
+    fi
+done    
+
+if [ -d /tmp/$tmpdir ]
+then
+    rm /tmp/$tmpdir/*
+else
+    mkdir /tmp/$tmpdir
+fi    
+
+echo -n "Converting charset and cleaning text files.. "
+
+zcat $src/support.txt.gz | tail -n +2 \
+    | sed 's/^ *//' | sed 's/ *\t */\t/g'| sed 's/ *$//' \
+    | iconv -f WINDOWS-1252 -c -t latin1 \
+    > /tmp/$tmpdir/support.txt
+
+zcat $src/phono.txt.gz | tail -n +2 \
+    | sed 's/^ *//' | sed 's/ *\t */\t/g'| sed 's/ *$//' \
+    | iconv -f WINDOWS-1252 -c -t latin1 | sed '/^\t/d' \
+    > /tmp/$tmpdir/phono.txt
+
+echo "Done"
+
+
diff --git a/trunk/import/prototype/src/2007-05-09/phono.txt.gz b/trunk/import/prototype/src/2007-05-09/phono.txt.gz
new file mode 100755 (executable)
index 0000000..fd0be4a
Binary files /dev/null and b/trunk/import/prototype/src/2007-05-09/phono.txt.gz differ
diff --git a/trunk/import/prototype/src/2007-05-09/support.txt.gz b/trunk/import/prototype/src/2007-05-09/support.txt.gz
new file mode 100755 (executable)
index 0000000..a7ec8c6
Binary files /dev/null and b/trunk/import/prototype/src/2007-05-09/support.txt.gz differ
diff --git a/trunk/import/raw_conversion/README b/trunk/import/raw_conversion/README
new file mode 100644 (file)
index 0000000..17f2195
--- /dev/null
@@ -0,0 +1,43 @@
+==========================================================
+Base de données du CREM : conversion brut de 4D vers MySQL
+==========================================================
+
+Le présent document décrit la procédure de conversion brut de la base de 
+données du CREM de 4D vers MySQL. La base MySQL obtenue a la même structure
+que la base originale 4D.
+
+Cette procédure doit être effectuée par un informaticien.
+
+Les instructions ci-dessous nécessitent l'emploi de la version 6.5.x de 4D pour 
+Windows.
+
+Avertissement: il est fortement recommandé de réaliser ces opérations sur une
+copie de la base 4D, et non sur la version de production.
+
+1.  Sur un poste Windows où se trouve la base du CREM, et équipé de 4D 6.5.x,
+    créer le répertoire C:\export_crem
+
+2.  Lancer 4D, ouvrir la base du CREM, créer une nouvelle méthode 4D avec 
+    le code source fourni dans le fichier ``export.4d.txt``, et lancer cette 
+    méthode de façon à exporter toute la base et les relations dans le 
+    répertoire C:\export_crem
+
+    Cette opération peut prendre plusieurs minutes. Une fenêtre "Export terminé"
+    s'affiche à la fin.
+
+    Remarque: si vous utilisez une version de démonstration de 4D, vous ne pouvez
+    pas créer de nouvelle méthode, mais vous pouvez remplacer une méthode existante.
+    
+3.  Placer le répertoire export_crem sur un poste linux, de façon à ce qu'il soit
+    accessible à l'import MySQL, par exemple dans /tmp/export_crem avec 777 pour
+    permissions
+
+4.  Créer une base MySQL, par exemple: crem
+
+5.  Importer la toutes les données dans la base MySQL avec la commande::
+
+        ./import /tmp/export_crem | mysql -vvv crem
+    
+    Vérifiez que chaque requête se termine par "Query OK" avec "Warnings: 0", 
+    pour vous assurer du bon déroulement de l'opération.
+
diff --git a/trunk/import/raw_conversion/export.4d.txt b/trunk/import/raw_conversion/export.4d.txt
new file mode 100755 (executable)
index 0000000..bd30cd6
--- /dev/null
@@ -0,0 +1,187 @@
+`Export de toutes les tables\r
+\r
+C_ALPHA(1;$fieldDelimiter;$recordDelimiter)\r
+C_ALPHA(32;$tableName;$fieldName)\r
+C_ENTIER LONG($numberOfTables;$tableNumber;$numberOfFields;$fieldNumber)\r
+C_ENTIER LONG($numberOfRecords;$fieldType)\r
+C_POINTEUR($tablePtr;$fieldPtr)\r
+C_TEXTE($fieldValue)\r
+C_HEURE($documentReference)\r
+C_REEL($Plateforme)\r
+PROPRIETES PLATE FORME($Plateforme)\r
+\r
+$fieldDelimiter:=Caractere(9)  \r
+$recordDelimiter:=Caractere(10)  \r
+\r
+$numberOfTables:=Nombre de tables  \r
+\r
+Boucle ($tableNumber;1;$numberOfTables)  \r
+  \r
+  $tablePtr:=Table($tableNumber)  \r
+  $tableName:=Nom de la table($tableNumber)  \r
+  \r
+  $documentReference:=Creer document("C:\export_crem\"+$tableName+".txt";"TEXT")  \r
+  \r
+  Si (OK=1)  \r
+    $numberOfFields:=Nombre de champs($tableNumber)  \r
+    \r
+    Boucle ($fieldNumber;1;$numberOfFields)  \r
+      $fieldName:=Nom du champ($tableNumber;$fieldNumber)  \r
+      Si ($fieldNumber#$numberOfFields)  \r
+        Si ($Plateforme=Windows )\r
+          ENVOYER PAQUET($documentReference;Mac vers Windows($fieldName)+$fieldDelimiter)\r
+            \r
+        Sinon \r
+          ENVOYER PAQUET($documentReference;$fieldName+$fieldDelimiter)\r
+            \r
+        Fin de si \r
+      Sinon \r
+        Si ($plateforme=Windows )\r
+          ENVOYER PAQUET($documentReference;Mac vers Windows($fieldName)+$recordDelimiter)\r
+            \r
+        Sinon \r
+          ENVOYER PAQUET($documentReference;$fieldName+$recordDelimiter)\r
+            \r
+        Fin de si \r
+      Fin de si \r
+    Fin de boucle \r
+    \r
+    TOUT SELECTIONNER($tablePtr->)  \r
+    $numberOfRecords:=Enregistrements trouves($tablePtr->)  \r
+    \r
+    Boucle ($recordNumber;1;$numberOfRecords)  \r
+      \r
+      Boucle ($fieldNumber;1;$numberOfFields)  \r
+        \r
+        $fieldPtr:=Champ($tableNumber;$fieldNumber)  \r
+        PROPRIETES CHAMP($fieldPtr;$fieldType)  \r
+        \r
+          \r
+        \r
+        Au cas ou \r
+          : (($fieldType=Est un numérique ) | ($fieldType=Est un entier ) | ($fieldType=Est un entier long ))\r
+            $fieldValue:=Chaine($fieldPtr->)  \r
+          : ($fieldType=Est une date )\r
+            $fieldValue:=Chaine($fieldPtr->;7)  \r
+          : ($fieldType=Est une heure )\r
+            $fieldValue:=Chaine($fieldPtr->;1)  \r
+          : ($fieldType=Est un booléen )\r
+            \r
+              \r
+            \r
+            $fieldValue:=Chaine(Num($fieldPtr->);"VRAI;;FAUX")  \r
+          : ($fieldType=Est une image )\r
+            $fieldValue:="Image non exportée"\r
+          : ($fieldType=Est un BLOB )\r
+            $fieldValue:="BLOB non exporté"\r
+          : ($fieldType=Est une sous table )\r
+            $fieldValue:="Sous-table non exportée"\r
+          Sinon   \r
+            $fieldValue:=$fieldPtr->  \r
+            $fieldValue:=Remplacer chaine ($fieldValue; $fieldDelimiter; " ")\r
+            $fieldValue:=Remplacer chaine ($fieldValue; $recordDelimiter; " ")\r
+            $fieldValue:=Remplacer chaine ($fieldValue; Caractere(13); " ")\r
+        Fin de cas \r
+        \r
+        Si ($fieldNumber#$numberOfFields)  \r
+          Si ($Plateforme=Windows )\r
+            ENVOYER PAQUET($documentReference;Mac vers Windows($fieldValue)+$fieldDelimiter)  \r
+          Sinon \r
+            ENVOYER PAQUET($documentReference;$fieldValue+$fieldDelimiter)  \r
+          Fin de si \r
+        Sinon \r
+          Si ($Plateforme=Windows )\r
+            ENVOYER PAQUET($documentReference;Mac vers Windows($fieldValue)+$recordDelimiter)  \r
+              \r
+          Sinon \r
+            ENVOYER PAQUET($documentReference;$fieldValue+$recordDelimiter)  \r
+              \r
+          Fin de si \r
+          \r
+        Fin de si \r
+        \r
+      Fin de boucle \r
+      \r
+      ENREGISTREMENT SUIVANT($tablePtr->)  \r
+    Fin de boucle \r
+    \r
+    FERMER DOCUMENT($documentReference)  \r
+    CHANGER CREATEUR DOCUMENT(Document;"TEXT")\r
+    \r
+  Fin de si \r
+  \r
+Fin de boucle \r
+\r
+`Export des relations des formations\r
+\r
+$tab:=Caractere(9)\r
+$fin:=Caractere(10)\r
+$ret:=Caractere(13)\r
+\r
+$doc:=Creer document("c:\export_crem\Formation.txt";"TXT")\r
+Si (ok=1)\r
+  $texte:="Cote_Phono"+$tab+"Instr_Scientif"+$tab+"Instr_Vernacul"+$tab+"Interprète"+$tab+"Total_Instrum"+$fin\r
+  ENVOYER PAQUET($doc;Mac vers Windows($texte))\r
+  TOUT SELECTIONNER([Phono])\r
+  Boucle ($i;1;Enregistrements trouves([Phono]))\r
+    $cote:=[Phono]Cote_Phono\r
+    $cote:=Remplacer chaine($cote; $tab; " ")\r
+    $cote:=Remplacer chaine($cote; $fin; " ")\r
+    $cote:=Remplacer chaine($cote; $ret; " ")\r
+    TOUS LES SOUS ENREGISTREMENTS([Phono]Formation)\r
+    Boucle ($j;1;Sous enregistrements trouves([Phono]Formation)\r
+      $instr_scientif:=Remplacer chaine([Phono]Formation'Instr_Scientif; $tab; " ")\r
+      $instr_scientif:=Remplacer chaine($instr_scientif; $fin; " ")\r
+      $instr_scientif:=Remplacer chaine($instr_scientif; $ret; " ")\r
+      $instr_vernacul:=Remplacer chaine([Phono]Formation'Instr_Vernacul; $tab; " ")\r
+      $instr_vernacul:=Remplacer chaine($instr_vernacul; $fin; " ")\r
+      $instr_vernacul:=Remplacer chaine($instr_vernacul; $ret; " ")\r
+      $interprete:=Remplacer chaine([Phono]Formation'Interprète; $tab; " ")\r
+      $interprete:=Remplacer chaine($interprete; $fin; " ")\r
+      $interprete:=Remplacer chaine($interprete; $ret; " ")\r
+      $total:=Remplacer chaine([Phono]Formation'Total_Instrum; $tab; " ")\r
+      $total:=Remplacer chaine($total; $fin; " ")\r
+      $total:=Remplacer chaine($total; $ret; " ")\r
+      $texte:=$cote+$tab+$instr_scientif+$tab+$instr_vernacul+$tab+$interprete+$tab+$total+$fin\r
+      ENVOYER PAQUET($doc;Mac vers Windows($texte))\r
+      SOUS ENREGISTREMENT SUIVANT([Phono]Formation)\r
+    Fin de boucle \r
+    LIBERER ENREGISTREMENT([Phono])\r
+    ENREGISTREMENT SUIVANT([Phono])\r
+  Fin de boucle \r
+  \r
+  FERMER DOCUMENT($doc)\r
+  \r
+Fin de si \r
+\r
+`Export des relations des mots clés\r
+\r
+$doc:=Creer document("c:\export_crem\Fonction_Usage.txt";"TXT")\r
+Si (ok=1)\r
+  $texte:="Cote_Phono"+$tab+"Mot_Clef"+$fin\r
+  ENVOYER PAQUET($doc;Mac vers Windows($texte))\r
+  TOUT SELECTIONNER([Phono])\r
+  Boucle ($i;1;Enregistrements trouves([Phono]))\r
+    $cote:=[Phono]Cote_Phono\r
+    $cote:=Remplacer chaine($cote; $tab; " ")\r
+    $cote:=Remplacer chaine($cote; $fin; " ")\r
+    $cote:=Remplacer chaine($cote; $ret; " ")\r
+    TOUS LES SOUS ENREGISTREMENTS([Phono]Fonction_Usage)\r
+    Boucle ($j;1;Sous enregistrements trouves([Phono]Fonction_Usage)\r
+      $mot_clef:=Remplacer chaine([Phono]Fonction_Usage'Mot_Clef; $tab; " ")\r
+      $mot_clef:=Remplacer chaine($mot_clef; $fin; " ")\r
+      $mot_clef:=Remplacer chaine($mot_clef; $ret; " ")\r
+      $texte:=$cote+$tab+$mot_clef+$fin\r
+      ENVOYER PAQUET($doc;Mac vers Windows($texte))\r
+      SOUS ENREGISTREMENT SUIVANT([Phono]Fonction_Usage)\r
+    Fin de boucle \r
+    LIBERER ENREGISTREMENT([Phono])\r
+    ENREGISTREMENT SUIVANT([Phono])\r
+  Fin de boucle \r
+  \r
+  FERMER DOCUMENT($doc)\r
+  \r
+Fin de si \r
+\r
+\r
+ALERTE("Export terminé.")\r
diff --git a/trunk/import/raw_conversion/import b/trunk/import/raw_conversion/import
new file mode 100755 (executable)
index 0000000..a020f39
--- /dev/null
@@ -0,0 +1,50 @@
+#!/bin/bash
+
+function extract_enum
+{
+    to_table=$1
+    from_table=$2
+    from_field=$3
+    echo "DROP TABLE IF EXISTS \`$to_table\`;"
+    echo "CREATE TABLE \`$to_table\` (value TEXT NOT NULL) CHARSET=latin1;"
+    echo "INSERT INTO \`$to_table\` SELECT DISTINCT \`$from_field\` FROM \`$from_table\` WHERE \`$from_field\` <> '';";
+}
+
+src=$1
+cd $src
+
+echo "SET NAMES 'latin1';"
+echo
+
+chmod o+r *.txt
+
+ls *.txt | while read filename
+do
+    table=$(echo $filename | sed 's/.txt//')
+    echo "DROP TABLE IF EXISTS \`$table\`;"
+    echo "CREATE TABLE \`$table\` ("
+    head -n1 $filename | tr '\t' '\n' | head -n-1 | sed 's/^/    `/' | sed 's/$/` TEXT NOT NULL,/'
+    head -n1 $filename | tr '\t' '\n' | tail -n1 | sed 's/^/    `/' | sed 's/$/` TEXT NOT NULL/'
+    echo ") CHARSET=latin1;"
+    echo
+    echo "LOAD DATA INFILE '$src/$filename'"
+    echo "    INTO TABLE \`$table\`"
+    echo "    CHARACTER SET 'latin1'"
+    echo "    FIELDS TERMINATED BY '\t' ESCAPED BY '' LINES TERMINATED BY '\n'"
+    echo "    IGNORE 1 LINES;"
+    echo "SHOW WARNINGS;"
+    echo
+done
+
+extract_enum Format Support Format
+extract_enum Réédition Support Réédition
+extract_enum Mode_Acqui Support Mode_Acqui
+extract_enum Rédacteur_Fiche Support Rédacteur_Fiche
+extract_enum Saisie_Fiche Support Saisie_Fiche
+extract_enum Droit_Utiliser Support Droit_Utiliser
+extract_enum Terrain_ou_Autr Support Terrain_ou_Autr
+extract_enum Numérisation Support Numérisation
+extract_enum "FormStyl généri" Phono "FormStyl généri"
+extract_enum Editeur1 Support Editeur
+extract_enum Collection_Serie Support Collect_Série
+