aboutsummaryrefslogtreecommitdiff |
diff options
author | Nathanael Sensfelder <SpamShield0@MultiAgentSystems.org> | 2016-05-27 07:04:24 -0700 |
---|---|---|
committer | Nathanael Sensfelder <SpamShield0@MultiAgentSystems.org> | 2016-05-27 07:04:24 -0700 |
commit | beb18f93d221241a9306cd31d48f0b847f22468c (patch) | |
tree | c02f8f9b3f4441a1dfb7cccc13c88ab76a21e9a9 | |
parent | 6b673bcb11c01dec2406080d8fe2cba2f3a4ff5f (diff) | |
parent | 94b924963d7927fba0bafa268c8477de2794a6da (diff) | |
download | calendar-beb18f93d221241a9306cd31d48f0b847f22468c.zip calendar-beb18f93d221241a9306cd31d48f0b847f22468c.tar.bz2 |
Merging website side of calendar.
35 files changed, 3077 insertions, 0 deletions
@@ -0,0 +1,24 @@ +Copyright (c) 2015, Nathanael Sensfelder +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the <organization> nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL NATHANAEL SENSFELDER BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e8db877 --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +calendar: + javac src/*.java -d bin/ + +clean: + rm -f output/* + rm -f bin/*.class + +test: + cd bin; \ + java Calendar ../data/KNOWN_CLASSES ../data/GROUPS ../input ../output 8 diff --git a/data/CURRICULUMS b/data/CURRICULUMS new file mode 100644 index 0000000..a575642 --- /dev/null +++ b/data/CURRICULUMS @@ -0,0 +1,10 @@ +M1 Informatique::M1INFO_GROUPS::M1INFO_CLASSES +M2R IT - IAICI::M2RIT_IAICI_GROUPS::M2RIT_IAICI_CLASSES +M2R IT - RIBDM::M2RIT_RIBDM_GROUPS::M2RIT_RIBDM_CLASSES +M2R IT - RO::M2RIT_RO_GROUPS::M2RIT_RO_CLASSES +M2R IT - RT::M2RIT_RT_GROUPS::M2RIT_RT_CLASSES +M2R IT - SRLC::M2RIT_SRLC_GROUPS::M2RIT_SRLC_CLASSES +M2 Image & Multimedia::M2IM_GROUPS::M2IM_CLASSES +M2 Développement Logiciel::M2DL_GROUPS::M2DL_CLASSES +M2 CAMSI::M2CAMSI_GROUPS::M2CAMSI_CLASSES +L3 Informatique (Rennes)::L3INFO_RENNES_GROUPS::L3INFO_RENNES_CLASSES diff --git a/data/L3INFO_RENNES_CLASSES b/data/L3INFO_RENNES_CLASSES new file mode 100644 index 0000000..12f74a6 --- /dev/null +++ b/data/L3INFO_RENNES_CLASSES @@ -0,0 +1,17 @@ +Anglais::ANG::Anglais +Algorithmique des graphes::AGR::AGR +Architecture des ordinateurs 1::ARC1::ARC1 +Organisation des systèmes d'exploitation 1::SYR1::SYR1 +Langages formels::LF::LF +Bases de la modélisation par objets::BMO::BMO +Programmation 1::PRG1::PRG1 +::contrôle TP PRG1::PRG1 +Méthodes algorithmiques::ALG::ALGO +::Contrôle Continu ALG::ALGO +Architecture des ordinateurs 2::ARC2::ARC2 +Organisation et utilisation des systèmes d'exploitation 2::SYR2::SYR2 +Programmation 2::PRG2::PRG2 +Compilation::CMPL::COMP +::Contrôle Projet CMPL::COMP +Logique::LOG::LOG +::MN.LOG::LOG diff --git a/data/L3INFO_RENNES_GROUPS b/data/L3INFO_RENNES_GROUPS new file mode 100644 index 0000000..699452b --- /dev/null +++ b/data/L3INFO_RENNES_GROUPS @@ -0,0 +1 @@ +Groupe 1::L3INFO_RENNES_1::lazy_ics_nouid::https://planning.univ-rennes1.fr/jsp/custom/modules/plannings/anonymous_cal.jsp?data=8241fc387320021460eb67564d761472bd72d825015315fe9b2ebb35bd288075ec7f554d6ed7ba1bbad7b9bdf5b7bdb27fbb53e06bf966cea3b3f4c7cc4cd75b8af069ff1fd12df94a3649013d5b5ccc8edd3cda7b61e593 diff --git a/data/M1INFO_CLASSES b/data/M1INFO_CLASSES new file mode 100644 index 0000000..7f45ace --- /dev/null +++ b/data/M1INFO_CLASSES @@ -0,0 +1,87 @@ +Modèles et Concepts du Parallélisme et de la Répartition::MODELES CONCEPT PARA. (EM7INFAM)::MCPR +::EM7INFAM (MODELES CONCEPT PARA.)::MCPR +Modélisation, Conception et Programmation Orientée Objet::MODEL. CONCEPT PROG. (EM7INFBM)::MCPOO +::EM7INFBM (MODEL. CONCEPT PROG.)::MCPOO +Traduction des Langages::TRADUCT. LANGAGES (EM7INFCM)::TL +::EM7INFCM (TRADUCT. LANGAGES)::TL +Architecture et Programmation Parallèle::ARCH. PROG. PARALLELE (EM7INFDM)::APP +::EM7INFDM (ARCH. PROG. PARALLELE)::APP +Systèmes de Bases de Données Relationnels::SYS BD RELATIONNELS (EM7INFEM)::SBDR +::EM7INFEM (SYS BD RELATIONNELS)::SBDR +Techniques de base pour la Résolution des Problèmes::TECH. BASE RESOL. PROB. (EM7INFFM)::TRP +::EM7INFFM (TECH. BASE RESOL. PROB.)::TRP +Outils Informatiques pour le Multimédia::OUTILS INFO MULTIMEDIA (EM7INFGM)::OIM +::EM7INFGM (OUTILS INFO MULTIMEDIA)::OIM +Mise à Niveau::MISE A NIVEAU (EM7INFHM)::MaN +::EM7INFHM (MISE A NIVEAU)::MaN +Communication et Gestion::COMM. ET GESTION (EM7INFIM)::CGE +::EM7INFIM (COMM. ET GESTION)::CGE +Langues Vivantes Anglais::ANGLAIS (EM7INFJM)::Anglais +::EM7INFJM (ANGLAIS)::Anglais +Réseaux::RESEAUX (EM7ICAAM)::R +::EM7ICAAM (RESEAUX)::R +Conception Interactive des Systèmes Interactifs::CONCEPT. INTER. SYS INTER (EM7IHMAM)::CISI +::EM7IHMAM (CONCEPT. INTER. SYS INTER)::CISI +Techniques Avancées de l’Intelligence Artificielle::TECH. AVANCEE IA (EM7IARBM)::TIA +::EM7IARBM (TECH. AVANCEE IA)::TIA +Agents Intelligents : Raisonnement et Comportement Collectif::AGENTS INTEL. RAISON. (EM8IARJM)::AIRC2 +::EM8IARJM (AGENTS INTEL. RAISON.)::AIRC2 +Algorithmes et Structures de Données pour la Synthèse d'Images::ALGO. STRUCT. DONNEES (EM8IIMBM)::ASDSI +::EM8IIMBM (ALGO. STRUCT. DONNEES)::ASDSI +Architecture Logicielle::ARCH. LOGICIELLES (EM8IDLEM)::AL +::EM8IDLEM (ARCH. LOGICIELLES)::AL +Architecture Haute Performance::ARCHIT. HAUTE PERFOR. (EM8ICAAM)::AHP +::EM8ICAAM (ARCHIT. HAUTE PERFOR.)::AHP +Architectures multi-couches et développement avec Java JEE::ARCHIT. MULTI-COUCHES (EM8IDLGM)::JEE +::EM8IDLGM (ARCHIT. MULTI-COUCHES)::JEE +Architectures Spécialisées::ARCHIT. SPECIALISEES (EM8ICABM)::AS +::EM8ICABM (ARCHIT. SPECIALISEES)::AS +Bases de Données Parallèles et Réparties::BDD PARALLELES::BDPR +::BASES DE DONNEES (MA08U05)::BDPR +::MA08U05 (BASES DE DONNEES)::BDPR +Conception des Systèmes répartis::CONCEPT. SYST. REPARTIS (EM8ICAFM)::CSR +::EM8ICAFM (CONCEPT. SYST. REPARTIS)::CSR +Développement Collaboratif et Logiciels Libres::DEV. COLL. LOG. LIBRES (EM8IDLBM)::DCLL +::EM8IDLBM (DEV. COLL. LOG. LIBRES)::DCLL +Gestion de projet (CMI)::GESTION DE PROJET (EM7ICMAM)::GestionProjet +::EM7ICMAM (GESTION DE PROJET)::GestionProjet +GRH et Communication (CMI)::GRH et Communication::GRH_Comm +Interopérabilité et Web Services::INTEROPERABILITE APPL. (EM8IDLDM)::IAWS +::EM8IDLDM (INTEROPERABILITE APPL.)::IAWS +Introduction à l'Informatique Graphique 3D::INTR. INFO GRAPHE 3D (EM8IIMAM)::IG3D +::EM8IIMAM (INTR. INFO GRAPHE 3D)::IG3D +Introduction à l'Analyse et au Traitement d'Images::INTROD. ANA. TRAIT. IMAGE (EM8IIMCM)::IATI +::EM8IIMCM (INTROD. ANA. TRAIT. IMAGE)::IATI +Introduction à l'Apprentissage Automatique::INTROD. APPR. AUTO. (EM8IARFM)::IAA +::EM8IARFM (INTROD. APPR. AUTO.)::IAA +Introduction à la Vision par Ordinateur::INTROD. VISION ORDINATEUR (EM8IIMDM)::IVO +::EM8IIMDM (INTROD. VISION ORDINATEUR)::IVO +Introduction à l'Audio Numérique::INTROD. AUDIO NUMERIQUE (EM8IIMEM)::IAN +::EM8IIMEM (INTROD. AUDIO NUMERIQUE)::IAN +Introduction à l'Interaction Homme-Machine et à l'Usabilité de Logiciels::INTRO. INTER HM UTIL. LOG (EM8IHMGM)::IHMUL +::EM8IHMGM (INTRO. INTER HM UTIL. LOG)::IHMUL +Logique constructive et Sémantique des Langages de programmation::UNKNOWN12::LSL +Management de Projets Informatiques::MANAG. DE PROJ. INFO. (EM8IDLCM)::MPI +::EM8IDLCM (MANAG. DE PROJ. INFO.)::MPI +Marketing et Stratégie::Marketing et Stratégie::MarketStrat +Méthodes Agiles::METHODES AGILES (EM8IDLAM)::MA +::EM8IDLAM (METHODES AGILES)::MA +Modélisation, Conception et Programmation Orientées Objet - Approfondissement::MOD. CONCEPT. PROG. OO (EM8IDLFM)::MCPOOA +::EM8IDLFM (MOD. CONCEPT. PROG. OO)::MCPOOA +Noyaux Systèmes Temps Réel::NOYAUX SYST. TEMPS REEL (EM8ICADM)::NSTR +::EM8ICADM (NOYAUX SYST. TEMPS REEL)::NSTR +Optimisation de Programmes Parallèles::UNKNOWN13::OPP +Préparation au CLES (CMI)::Prépa CLES (CMI)::CLES +Préparation au C2i (CMI)::Prépa C2iMI (E48ICMB2)::C2i +::E48ICMB2 (Prépa C2iMI)::C2i +Projet de développement::PROJET DEVELOPPEMENT (EM8INFAM)::PROJET +::EM8INFAM (PROJET DEVELOPPEMENT)::PROJET +Recherche Opérationnelle::RECHERCHE OPERATIONNELLE (EM8IARDM)::RO +::EM8IARDM (RECHERCHE OPERATIONNELLE)::RO +Représentation et manipulation de contenus 3D, Image et Son::REP. MANIP. CONTENU 3D (EM8IARGM)::3DIS +::EM8IARGM (REP. MANIP. CONTENU 3D)::3DIS +Représentation des connaissances::REPRESENT. DES CONNAIS. (EM8IARIM)::RC +::EM8IARIM (REPRESENT. DES CONNAIS.)::RC +Techniques Avancées des Systèmes d'Exploitation::UNKNOWN14::TAS +Travail Encadré de Recherche::TER (EM8INFBM)::TER +::EM8INFBM (TER)::TER diff --git a/data/M1INFO_GROUPS b/data/M1INFO_GROUPS new file mode 100644 index 0000000..094b495 --- /dev/null +++ b/data/M1INFO_GROUPS @@ -0,0 +1,10 @@ +Groupe 1::M1_Info_1::celcat::https://edt.univ-tlse3.fr/FSI/FSIpargroupes/g1667.xml +Groupe 2::M1_Info_2::celcat::https://edt.univ-tlse3.fr/FSI/FSIpargroupes/g1668.xml +Groupe 3::M1_Info_3::celcat::https://edt.univ-tlse3.fr/FSI/FSIpargroupes/g1669.xml +Groupe 4::M1_Info_4::celcat::https://edt.univ-tlse3.fr/FSI/FSIpargroupes/g1670.xml +Groupe 5::M1_Info_5::celcat::https://edt.univ-tlse3.fr/FSI/FSIpargroupes/g1671.xml +Groupe 6::M1_Info_6::celcat::https://edt.univ-tlse3.fr/FSI/FSIpargroupes/g1672.xml +Groupe 7::M1_Info_7::celcat::https://edt.univ-tlse3.fr/FSI/FSIpargroupes/g1673.xml +Groupe 8::M1_Info_8::celcat::https://edt.univ-tlse3.fr/FSI/FSIpargroupes/g1674.xml +Groupe 9::M1_Info_9::celcat::https://edt.univ-tlse3.fr/FSI/FSIpargroupes/g1675.xml +Groupe 10::M1_Info_10::celcat::https://edt.univ-tlse3.fr/FSI/FSIpargroupes/g1676.xml diff --git a/data/M2CAMSI_CLASSES b/data/M2CAMSI_CLASSES new file mode 100644 index 0000000..6f3c65f --- /dev/null +++ b/data/M2CAMSI_CLASSES @@ -0,0 +1,35 @@ +Architectures Embarquées et Production de Code::UE10 : Cours Architectures Embarquées et Production de Code::AEPC +::UE10 : Architectures Embarquées et Production de Code::AEPC +::UE10 : Examen Architectures Embarquées et Production de Code::AEPC +Architecture Matérielle/Logicielle des Systèmes Temps-réel::UE11 : Cours Architecture Matérielle/Logicielle des Systèmes Temps-réel::AMLST +::UE11 : Examen Architecture Matérielle/Logicielle des Systèmes Temps-réel::AMLST +Réseaux pour les Systèmes Temps-réel et Embarqués::UE9 : Cours Réseaux pour les Systèmes Temps-réel et Embarqués::RSTE +::UE9 : TP Réseaux pour les Systèmes Temps-réel et Embarqués::RSTE +::UE9 : Examen Réseaux pour les Systèmes Temps-réel et Embarqués::RSTE +Systèmes d'Exploitation et Pilotes de périphériques::UE2 : Cours Systèmes d'Exploitation et Pilotes de périphériques::CEP +::UE2 : TP Systèmes d'Exploitation et Pilotes de périphériques::CEP +::UE2 : TP BE Systèmes d'exploitation et Pilotes de périphériques::CEP +::UE2 : BE Systèmes d'exploitation et Pilotes de périphériques::CEP +::UE2 : Examen Systèmes d'exploitation et Pilotes de périphériques::CEP +Communication et Connaissance de l'entreprise::UE7 : Cours Communication et Connaissance de l'entreprise::CC +::UE7 : Communication et Connaissance de l'entreprise::CC +::UE7 : Examen Communication et Connaissance de l'entreprise::CC +Systèmes Temps-réel et Embarqués::UE5 : Cours Systèmes Temps-réel et Embarqués::STE +::UE5 : Systèmes Temps-réel et Embarqués::STE +::UE5 : Examen Systèmes Temps-réel et Embarqués::STE +Structure et Conception de Base des Machines Informatiques::UE1 : Cours Structure et Conception de Base des Machines Informatiques::SCBMI +::UE1 : TP Structure et Conception de Base des Machines Informatiques::SCBMI +::UE1 : Structure et Conception de Base des Machines Informatiques::SCBMI +Langage de description du matériel : VHDL::UE0 : Cours Langage de description du matériel : VHDL::LVHDL +::UE0 : TP Langage de description du matériel : VHDL::LVHDL +::UE0 : Examen Langage de description du matériel : VHDL::LVHDL +::UE0 : Examen de TP Langage de description du matériel : VHDL::LVHDL +Anglais::UE6 : TD Anglais::Anglais +Techniques de Conception Avancée des Machines Informatiques::UE4 : Cours Techniques de Conception Avancée des Machines Informatiques::TCAMI +::UE4 : TP Techniques de Conception Avancée des Machines Informatiques::TCAMI +::UE11 : Techniques de Conception Avancée des Machines Informatiques::TCAMI +::UE11 : Conférence Continental::TCAMI +::UE4 : Techniques de Conception Avancée des Machines Informatiques::TCAMI +Techniques de Compilation::UE3 : Cours Techniques de Compilation::TC +::UE3 : Examen Techniques de Compilation::TC +Projets::UE99 : TP Projets::Projets diff --git a/data/M2CAMSI_GROUPS b/data/M2CAMSI_GROUPS new file mode 100644 index 0000000..1b9f312 --- /dev/null +++ b/data/M2CAMSI_GROUPS @@ -0,0 +1 @@ +All Students::M2CAMSI::camsi::http://planning.camsi.fr/ShowListeCreneaux.aspx diff --git a/data/M2DL_CLASSES b/data/M2DL_CLASSES new file mode 100644 index 0000000..4beb7e1 --- /dev/null +++ b/data/M2DL_CLASSES @@ -0,0 +1,131 @@ +Langue Vivante::Anglais::LV +::TD Ue Anglais::LV +::Cours Ue Anglais::LV +::LV Groupe::LV +::Réunion UE ANGLAIS::LV +::LV G1::LV +::LV G2::LV +Vie des Entreprises::Intervention des entreprises::VE +::Ue Vie des entreprises::VE +::VE::VE +::Cours Vie des entreprises::VE +::Ue Vie des Entreprises::VE +::Cours Ue Vie des Entreprises::VE +::EXAM VE::VE +::RAO Vie des entreprises::VE +Ingénierie Système::IS::IS +::TP IS::IS +::Cours IS::IS +::cours IS::IS +::Cours Ue IS::IS +::EXAM IS::IS +::Ue IS::IS +::Cours Ingénierie des Systèmes::IS +Processus de l'Ingénierie Système et Modélisation de Processus::PCIS::PCIS +::Cours Ue PCIS::PCIS +::C Ue PCIS::PCIS +::EXAM PCIS::PCIS +::Cours PCIS::PCIS +::Cours Processus de l'Ingénierie Système::PCIS +::G2 PCIS::PCIS +::G1 PCIS::PCIS +Intégration, Vérification, Validation, Qualification::IVVQ::IVVQ +::EXAM IVVQ::IVVQ +::Soutenances IVVQ::IVVQ +::C IVVQ::IVVQ +::Ue IVVQ::IVVQ +::Cours Ue IVVQ::IVVQ +::Cours Ue Intégration Vérification Validation Qualification::IVVQ +::Session 2 IVVQ::IVVQ +::Cours IVVQ::IVVQ +Outils Formels pour l'Ingénierie::OFI::OFI +::Contrôle Terminal OFI::OFI +::Contrôle OFI::OFI +::Cours Ue OFI::OFI +::Cours Ue Outils Formels pour l'Ingénierie::OFI +::CC Ue OFI::OFI +::TP Ue OFI::OFI +::TP OFI::OFI +::Exam OFI::OFI +::Contrôle Continu Ue OFI::OFI +::Contrôle continu OFI::OFI +::Ue OFI::OFI +Conception de Systèmes Ambiants::CSA::CSA +::G1 CSA::CSA +::G2 CSA::CSA +Spécification Formelle des Systèmes::SFS::SFS +::TP Spécification Formelle des Systèmes::SFS +::TP Ue Spécification Formelle des Systèmes::SFS +::Cours Ue Spécification Formelle des Systèmes::SFS +::Cours Ue SFS::SFS +::examen SFS::SFS +::EXAM SFS::SFS +::Exam SFS::SFS +::Contrôle SFS::SFS +Travaux d'Etudes et de Recherche::TER::TER +::cours TER::TER +::Cours TER::TER +::Ue TER::TER +Stage::STA::STA +::Préparation soutenances::STA +::Présentation des stages::STA +::Prépa au stage::STA +::Soutenances à confirmer::STA +::Préparation rapport et soutenance::STA +::Soutenances stages::STA +::Point d'avancement sur la recherche de stages::STA +::Présentation stages::STA +::Point stage::STA +::Cours Préparation au stage::STA +::SOUTENANCES DE STAGE::STA +::Stage::STA +::Préparation au rapport de stage::STA +::STAGE::STA +::POINT STAGE::STA +::Préparation rapport de stage::STA +::Réunion stage::STA +::Soutenances des stages::STA +::Préparation du rapport de stage::STA +::SOUTENANCES DES STAGES::STA +::Accompagnement à la recherche de stage::STA +Développement de Logiciels Critiques::UNKNOWN10::DLC +Ingénierie Dirigée par les Modèles::UNKNOWN11::IDM +Simulation de Modèles::UNKNOWN12::SM +Validation d'Applications pour le Domaine des Transports::UNKNOWN13::VADT +Vérification de Systèmes Réactifs::UNKNOWN14::VSR +Conférences::UE Conférence::C +::Conférence::C +::Exam UE Conférence::C +::Ue Conférence::C +::Contrôle UE Conférences::C +::EXAM UE CONF::C +::Examen - UE-Conférences::C +::Contrôle - UE-Conférences::C +::UE CONFERENCES::C +Programmation Concurrente et Répartie::PCR::PCR +::EXAM PCR::PCR +::Examen UE PCR::PCR +::UE PCR::PCR +::Contrôle PCR::PCR +Processus Métier et Développement .Net::PMDD::PPMD +::PMDN::PPMD +::UE PMDD::PPMD +::EXAM PMDD::PPMD +Sécurité::SECU::SE +::EXAM SECU::SE +::Sécurité::SE +::UE Sécurité::SE +Applications Réparties à Grande Echelle::ARGE::ARGE +::Examen UE ARGE::ARGE +::UE ARGE::ARGE +::EXAM ARGE::ARGE +Systèmes Multi-Agents::SMA::SMA +::Examen UE SMA::SMA +::EXAM SMA::SMA +::UE SMA::SMA +Facteurs Humains dans la Conception d'Interfaces::FHCI::FHCI +::Cours FHCI::FHCI +::C FHCI::FHCI +::Cours Ue Facteurs Humains dans la Conception d'Interfaces::FHCI +::TP FHCI::FHCI +::Cours Ue FHCI::FHCI diff --git a/data/M2DL_GROUPS b/data/M2DL_GROUPS new file mode 100644 index 0000000..e16ad70 --- /dev/null +++ b/data/M2DL_GROUPS @@ -0,0 +1 @@ +All Students::M2DL::lazy_ics::https://www.google.com/calendar/ical/master.developpement.logiciel%40gmail.com/public/basic.ics diff --git a/data/M2IHM_CLASSES b/data/M2IHM_CLASSES new file mode 100644 index 0000000..29c841f --- /dev/null +++ b/data/M2IHM_CLASSES @@ -0,0 +1 @@ +None::UNKNOWN0::UNKNOWN1 diff --git a/data/M2IHM_GROUPS b/data/M2IHM_GROUPS new file mode 100644 index 0000000..d2b43df --- /dev/null +++ b/data/M2IHM_GROUPS @@ -0,0 +1 @@ +All Students::M2IHM::ics::https://www.google.com/calendar/ical/4lum4m9ols52i71dpvgnkc25r0%40group.calendar.google.com/public/basic.ics diff --git a/data/M2IM_CLASSES b/data/M2IM_CLASSES new file mode 100644 index 0000000..a1bca63 --- /dev/null +++ b/data/M2IM_CLASSES @@ -0,0 +1,23 @@ +Anglais::LANGUE VIVANTE-ANGLAIS (EI9IMMAM)::Anglais +Gestion et communication en entreprise - Initiation à la recherche::GESTION ET COMMUNICATION (EI9IMMBM)::GCEIR +Conception et metaprogrammation C++::CONCEPTION ET METAPROG. (EI9IMMDM)::CMC +Outils en -ique pour l'image et le multimedia::OUTILS EN -IQUE (EI9IMMEM)::OIIM +Traitement du signal::TRAITEMENT DU SIGNAL (EI9IMMFM)::TS +Fondements de la synthèse d'images::SYNTHESE D'IMAGES (EI9IMMGM)::FSI +Fondements de l'analyse d'images et de la vision par ordinateur::UNKNOWN6::FAIVO +Méthodes de compression audio-video::METHODES DE COMPRESSION (EI9IMMIM)::MCAV +Modélisation géométrique 3D::MODELISATION GEOM. 3D (EI9IG3AM)::MG3D +Rendu temps réel::RENDU TEMPS REEL (EI9IG3BM)::RTR +Traitement et analyse d’images::ANALYSE D'IMAGES (EI9IMMHM)::TAI +Méthodes et concepts avancés pour la vision par ordinateur::UNKNOWN11::MCAVO +Humain virtuel : du mouvement au comportement::HUMAIN VIRTUEL (EIAIMMAM)::HVMC +Environnements virtuels interactifs et partagés::ENVIRONNEMENT VIRTUELS (EIAIG3AM)::EVIP +Traitement de la géométrie et simulation de l’éclairage en synthèse d’images::TRAITEMENT DE LA GEOMET. (EIAIG3BM)::TGSESI +Reconnaissance des formes et interprétation d’images::UNKNOWN15::RFIA +Imagerie médicale et spatiale::IMAGERIE MEDICALE (EIAIANBM)::IMS +Reconnaissance des personnes dans les enregistrements audiovisuels::UNKNOWN17::RPEA +Game design::UNKNOWN18::GD +Algorithmique des architectures spécialisées pour l’image et le multimedia::UNKNOWN19::AASIM +Traitement automatique parole et musique::UNKNOWN20::TAPM +Analyse et synthèse des environnements sonores::UNKNOWN21::ASES +Réalité augmentée::UNKNOWN22::RA diff --git a/data/M2IM_GROUPS b/data/M2IM_GROUPS new file mode 100644 index 0000000..983ecf7 --- /dev/null +++ b/data/M2IM_GROUPS @@ -0,0 +1 @@ +All Students::M2IM::celcat::https://edt.univ-tlse3.fr/FSI/FSIpargroupes/g1128.xml diff --git a/data/M2RIT_IAICI_CLASSES b/data/M2RIT_IAICI_CLASSES new file mode 100644 index 0000000..17e2861 --- /dev/null +++ b/data/M2RIT_IAICI_CLASSES @@ -0,0 +1,30 @@ +Anglais::ANGLAIS (ER9INTBM)::Anglais +::[BONUS][Anglais]::Anglais +Apprentissage::APPRENTISSAGE (ER9IAIAM)::AP +::[BONUS][AP]::AP +Systèmes multi-agents::SYST. MULTI-AGENTS (ER9IAIBM)::SMA +::[BONUS][SMA]::SMA +Systèmes autonomes auto-adaptatifs::SYST. AUTON. AUTO-ADAPT. (ER9IAICM)::SAAA +::[BONUS][SAAA]::SAAA +Modèles et algorithmes pour les problèmes d'optimisation complexes de l'IA::MOD. ALGO. PB. OPT.COM.IA (ER9IAIEM)::MPOSC +::[BONUS][MPOSC]::MPOSC +Simulation de systèmes complexes::SIMULATION SYST. COMPLEXE (ER9IAIFM)::SSC +::[BONUS][SSC]::SSC +Planification et décision::PLANIFICATION ET DECISION (ER9IAIHM)::PLD +::[BONUS][PLD]::PLD +Modèles probabilistes et algorithmes pour la bio-informatique::MOD. PROBA. ALGO. BIO-INF (ER9IAIJM)::AMB +::[BONUS][AMB]::AMB +Logique du premier ordre et types de raisonnement::LOG. 1er ORDRE\, TYPES RAI (ER9IAIKM)::LPOTR +::[BONUS][LPOTR]::LPOTR +Modèles logiques d'agents et de leur interaction::MOD. LOG. AGENTS INTERAC. (ER9IAILM)::MLAI +::[BONUS][MLAI]::MLAI +Techniques fondamentales pour le traitement automatique du langage et applications::TECH. FOND. TRAIT. A.L.A. (ER9IAIDM)::TAL +::[BONUS][TAL]::TAL +Systèmes coopératifs::UNKNOWN10::SC +::[BONUS][SC]::SC +Représentation et traitement de l'incertitude::REPRESENT. TRAIT. INCERT. (ER9IAIIM)::RTI +::[BONUS][RTI]::RTI +Fondements de l'interaction et de la coopération::UNKNOWN12::FIE +::[BONUS][FIE]::FIE +[BONUS] Seminaires Toulousains::S�minaire::BONUS_ST +::[BONUS][SemToulouse]::BONUS_ST diff --git a/data/M2RIT_IAICI_GROUPS b/data/M2RIT_IAICI_GROUPS new file mode 100644 index 0000000..3a2e723 --- /dev/null +++ b/data/M2RIT_IAICI_GROUPS @@ -0,0 +1 @@ +All Students::M2RIT_IAICI::celcat::https://celcatfsi.ups-tlse.fr/FSIvetsem/g985.xml::lazy_ics::http://www.laas.fr/template/laas-cnrs-2009/support/protected/modules/seminaires/seminaires/calendrier/seminaires_laas.ics::lazy_ics::https://www.multiagentsystems.org/calendar/seminaires_toulouse.ics::celcat::https://edt.univ-tlse3.fr/FSI/FSIpargroupes/g2090.xml::lazy_ics::https://www.multiagentsystems.org/calendar/iaici_from_email_or_website.ics diff --git a/data/M2RIT_RIBDM_CLASSES b/data/M2RIT_RIBDM_CLASSES new file mode 100644 index 0000000..a75c287 --- /dev/null +++ b/data/M2RIT_RIBDM_CLASSES @@ -0,0 +1,21 @@ +Anglais::ANGLAIS (ER9INTBM)::Anglais +::[BONUS] Anglais::Anglais +Modèles de recherche d'information::MOD. RECHERCHE INFORMAT° (ER9IRIAM)::MRI +Médiation de sources de données hétérogènes::UNKNOWN3::MSDH +Analyses exploratoires multidimensionnelles et visualisations::UNKNOWN4::AEMV +Bases de données multidimensionnelles::BD MULTIDIMENSIONNELLES (ER9IRIDM)::BDM +Accès à l'information sur le web::ACCES INFORMATION WEB (ER9IRIEM)::AIW +Bases de données réparties et mobiles::BD REPARTIES MOBILES (ER9IRIFM)::BDRM +Ontologies et Web sémantique::ONTOLOGIES WEB SEMANT. (ER9IRIGM)::OWS +Requêtes multimédia::UNKNOWN9::RM +Recherche de contenus multimédia::UNKOWN10::RCM +Classification et reconnaissance de formes::UNKNOWN11::CRF +Fondements de l'analyse d'images::UNKNOWN12::FAI +Analyse, codage et indexation de la vidéo::UNKNOWN13::ACIV +Audio numérique : Parole et musique::AUDIONUMERIQUE MIT RIBDM::ANPM +::NEII5D - TP - Audionumérique : parole et musique::ANPM +::NEII5C::ANPM +Humain virtuel, du mouvement au comportement::UNKNOWN15::HVMC +Fondements de la synthèse d'images::UNKNOWN16::FSI +[BONUS] Seminaires Toulousains::S�minaire::BONUS_ST +::[BONUS][SemToulouse]::BONUS_ST diff --git a/data/M2RIT_RIBDM_GROUPS b/data/M2RIT_RIBDM_GROUPS new file mode 100644 index 0000000..f6ea790 --- /dev/null +++ b/data/M2RIT_RIBDM_GROUPS @@ -0,0 +1 @@ +All Students::M2RIT_RIBDM::lazy_ics::https://edt.inp-toulouse.fr/jsp/custom/modules/plannings/anonymous_cal.jsp?resources=2748&projectId=1&calType=ical&nbWeeks=20::celcat::https://edt.univ-tlse3.fr/FSI/FSIpargroupes/g2091.xml::lazy_ics::http://www.laas.fr/template/laas-cnrs-2009/support/protected/modules/seminaires/seminaires/calendrier/seminaires_laas.ics::lazy_ics::https://www.multiagentsystems.org/calendar/seminaires_toulouse.ics diff --git a/data/M2RIT_RO_CLASSES b/data/M2RIT_RO_CLASSES new file mode 100644 index 0000000..1c4e5b0 --- /dev/null +++ b/data/M2RIT_RO_CLASSES @@ -0,0 +1,78 @@ +Anglais::Anglais::Anglais +::Anglais (que pour les inscrits UPS)::Anglais +::Anglais (?)::Anglais +::Anglais ?::Anglais +::Rattrapage 2 - 2014-2015 : Anglais::Anglais +Fondamentaux de la RO::Fond. de la RO::FRO +::TP Fond. de la RO : groupe A::FRO +::TP Fond. de la RO : groupe B::FRO +::TP Fond. de la RO::FRO +::EXAMEN Fond. de la RO::FRO +::TP groupe 1 Fond. de la RO::FRO +::TP groupe 2 Fond. de la RO::FRO +::Examen rattrapage 2014-2015 Fond. de la RO::FRO +Graphes et réseaux : modélisation et algorithmes::Graphes et r�seaux : mod�lisation et algorithmes::GRMA +::Graphes::GRMA +::EXAMEN Graphes::GRMA +::Graphes : S�ance report�e � une date ult�rieure::GRMA +Optimisation numérique locale::Opti num locale::ONL +::TD Opti num locale Groupe B::ONL +::TD Opti num locale Groupe A::ONL +::TD Opti num locale::ONL +::TP Opti num locale::ONL +::TD A Opti num locale::ONL +::TD B Opti num locale::ONL +::TP A Opti num locale::ONL +::TP B Opti num locale::ONL +::EXAMEN : Opti num locale::ONL +::EXAMEN Opti num locale::ONL +::EXAMEN 1 - Opti num locale::ONL +Bases de l’optimisation combinatoire::TP Bases Opti combin::BOC +::Bases Opti combin::BOC +::Bases Opti combin EXAMEN::BOC +::EXAMEN Bases Opti combin::BOC +Optimisation combinatoire avancée::Opti Combin Av::OCA +::EXAMEN de rattrapage Opti Combin Av::OCA +::EXAMEN Opti Combin Av::OCA +Introduction à l’optimisation et la commande optimale::Introduction � l'optimisation et la commande optimale::IOCO +::Intro Opti Commande::IOCO +::Intro Opti Commande : � Optimisation stochastique �::IOCO +::EXAMEN Intro Opti Commande : � Optimisation stochastique �::IOCO +Méthodes stochastiques pour l'optimisation globale::M�thodes Sto::MSOG +::TD M�thodes Sto::MSOG +::TP M�thodes Sto::MSOG +::EXAMEN M�thodes Sto::MSOG +::EXAMEN TP M�thodes Sto::MSOG +::EXAMEN de RATTRAPAGE - M�thodes Sto::MSOG +Production et logistique::Prod & Logis::PL +::BE Prod & Logis::PL +::EXAMEN Prod & Logis::PL +::EXAMEN : Prod & Logis::PL +::EXAMEN - Prod & Logis::PL +::EXAMEN rattrapage 2014-2015 Prod & Logis::PL +Optimisation sous incertitude::Optimisation sous incertitude::OSI +::Opti Incertitude::OSI +::Examen Opti Incertitude::OSI +::EXAMEN Opti Incertitude::OSI +::Examen rattrapage 2014-2015 : Opti Incertitude::OSI +Optimisation globale déterministe::Opti Globale D�t::OGD +::EXAMEN Opti Globale D�t::OGD +::TP Opti Globale D�t::OGD +::S�ance report�e � une date ult�rieure - Opti Globale D�t::OGD +Applications aux transports et à l'aéronautique::Appli A�ro::ATA +::Examen Appli A�ro::ATA +::EXAMEN Appli A�ro::ATA +::TD Appli A�ro::ATA +::EXAMEN de RATTRAPAGE - Appli A�ro::ATA +::TP Appli A�ro::ATA +Formation d'appoint en aéronautique::Formation d appoint en a�ronautique::FAA +::Formation d appoint en a�ronautiqueo::FAA +Complexité des algorithmes::Complexit�::CA +::EXAMEN Complexit�::CA +::EXAMEN - Complexit�::CA +::EXAMEN : Complexit�::CA +Optimisation et Recherche Opérationnelle (2012-2013)::Optimisation et Recherche op�rationnelle::ORO +::Opti & RO::ORO +::TP Opti & RO::ORO +[BONUS] Seminaires Toulousains::S�minaire::BONUS_ST +::[BONUS][SemToulouse]::BONUS_ST diff --git a/data/M2RIT_RO_GROUPS b/data/M2RIT_RO_GROUPS new file mode 100644 index 0000000..790d0de --- /dev/null +++ b/data/M2RIT_RO_GROUPS @@ -0,0 +1 @@ +All Students::M2RIT_RO::dhx_cal::http://m2rit-ro.recherche.enac.fr/calendrier/php/events.php::lazy_ics::http://www.laas.fr/template/laas-cnrs-2009/support/protected/modules/seminaires/seminaires/calendrier/seminaires_laas.ics::lazy_ics::https://www.multiagentsystems.org/calendar/seminaires_toulouse.ics diff --git a/data/M2RIT_RT_CLASSES b/data/M2RIT_RT_CLASSES new file mode 100644 index 0000000..913b042 --- /dev/null +++ b/data/M2RIT_RT_CLASSES @@ -0,0 +1,36 @@ +Anglais::CM Anglais::Anglais +::ANGLAIS (ER9INTBM)::Anglais +Algorithmes et protocoles de gestion de la qualité de service::Algorithme et protocole de gestion::APGQS +::EXAMEN Algorithme et protocole de gestion::APGQS +::ALGO. MECA. GEST. QUAL. S (ER9IRTFM)::APGQS +Techniques et protocoles de sécurité dans les réseaux et systèmes d'exploitation::UNKNOWN1::TPSRSE +Architectures et protocoles de gestion de la QoS dans l'Internet::UNKNOWN2::APGQSI +Composition de services pour le multimédia dans l'Internet::UNKNOWN3::CSMI +Réseaux opérateurs haut débit::NI1E22::ROHD +::NI1E24::ROHD +Réseaux embarqués::Réseaux Embarqués::RE +::EXAMEN Réseaux Embarqués::RE +Développement d’applications réparties::UNKNOWN6::DAR +Modélisation et évaluation de performance des réseaux::UNKNOWN7::MEPR +Gestion de réseaux et de services::NETG3C::GRS +Modèles et politiques de sécurité::UNKNOWN9::MPS +Réseaux sans fil et mobiles::NETG2C::RSFM +::NETG2B::RSFM +Modulations numériques avancées::NETG1D::MNA +Communications aéronautiques::UNKNOWN12::CA +Egalisation et modèles de canaux::UNKNOWN13::EMC +Récepteurs numériques::UNKNOWN14::RN +Accès multiple par codage et détection multi-utilisateurs::UNKNOWN15::AMCDMU +Compression du signal::UNKNOWN16::CS +Techniques multi-porteuses::UNKNOWN17::TMP +Systèmes de communication mobiles terrestres::NETG1C::SCMT +Télécommunications par satellite::UNKNOWN19::TPS +Diffusion et multimédia par satellite::UNKNOWN20::DMS +Architectures et protocoles de l'Internet::Architecture et protocole de l'Internet::API +Déploiement de l'Internet et interconnexion avancée::Déploiement de l'Internet et interconnexion avancée::DIIA +Principes des communications::Principe des Communications::PC +::EXAMEN Principe des Communications::PC +Techniques de communications pour les mobiles::UNKNOWN23::TCM +Modélisation et processus stochastiques::UNKNOWN24::MPSt +[BONUS] Seminaires Toulousains::S�minaire::BONUS_ST +::[BONUS][SemToulouse]::BONUS_ST diff --git a/data/M2RIT_RT_GROUPS b/data/M2RIT_RT_GROUPS new file mode 100644 index 0000000..54dd30c --- /dev/null +++ b/data/M2RIT_RT_GROUPS @@ -0,0 +1 @@ +All Students::M2RIT_RT::lazy_ics::https://edt.inp-toulouse.fr/jsp/custom/modules/plannings/anonymous_cal.jsp?resources=20&projectId=1&calType=ical&nbWeeks=20::celcat::https://edt.univ-tlse3.fr/FSI/FSIpargroupes/g2094.xml::lazy_ics::http://www.laas.fr/template/laas-cnrs-2009/support/protected/modules/seminaires/seminaires/calendrier/seminaires_laas.ics::lazy_ics::https://www.multiagentsystems.org/calendar/seminaires_toulouse.ics diff --git a/data/M2RIT_SRLC_CLASSES b/data/M2RIT_SRLC_CLASSES new file mode 100644 index 0000000..7b952ed --- /dev/null +++ b/data/M2RIT_SRLC_CLASSES @@ -0,0 +1,28 @@ +Anglais::ANGLAIS (ER9INTBM)::Anglais +::[BONUS] Anglais::Anglais +Complexité des algorithmes::CTD Complexité des algorithmes::CA +Algorithmique et systèmes répartis::NEI2A - CM - Systèmes et algorithmes répartis::ASR +::NEI2A - EXAM - Systèmes et algorithmes répartis::ASR +Intergiciels::NEIL5A - TP - Systèmes avancés::I +::NEIL5A - EXAM - Systèmes avancés::I +::NEIL5A - CM - Systèmes avancés::I +::NEIL5A - TPA - Systèmes avancés::I +::NEIL5A - TPB - Systèmes avancés::I +Calcul réparti et Grid computing::NEI2B - CM - Calcul réparti et grid computing::CRGC +::NEI2B - EXAM - Calcul réparti et grid computing::CRGC +Modèles d’exécution et architectures parallèles::UNKNOWN4::MEAP +Architectures : parallélisme et systèmes critiques::UNKNOWN5::APSC +Conception de systèmes temps réel::UNKNOWN6::CSTR +Conception conjointe de systèmes temps réel et langages (a)synchrones::UNKNOWN7::CCSTRLA +Ordonnancement dans les systèmes temps réel et embarqués::UNKNOWN8::OSTRE +Ingénierie des modèles::UNKNOWN9::IM +Modèle d'ingénierie du processus de développement::UNKNOWN10::MIPD +Spécification formelle des systèmes::UNKNOWN11::SFS +Vérification de systèmes réactifs::UNKNOWN12::VSR +Validation par analyse statique::NEIL4A - CM -Vérification par analyse statique::VAS +::NEIL4B - BE -Vérification par analyse statique::VAS +::NEIL4B - CM -Vérification par analyse statique::VAS +Techniques de compilation::UNKNOWN14::TC +Théorie des types et applications::UNKNOWN15::TTA +[BONUS] Seminaires Toulousains::S�minaire::BONUS_ST +::[BONUS][SemToulouse]::BONUS_ST diff --git a/data/M2RIT_SRLC_GROUPS b/data/M2RIT_SRLC_GROUPS new file mode 100644 index 0000000..34bd671 --- /dev/null +++ b/data/M2RIT_SRLC_GROUPS @@ -0,0 +1 @@ +All Students::M2RIT_SRLC::ics::https://edt.inp-toulouse.fr/jsp/custom/modules/plannings/anonymous_cal.jsp?resources=15&projectId=1&calType=ical&nbWeeks=20::celcat::https://edt.univ-tlse3.fr/FSI/FSIpargroupes/g2092.xml::lazy_ics::http://www.laas.fr/template/laas-cnrs-2009/support/protected/modules/seminaires/seminaires/calendrier/seminaires_laas.ics::lazy_ics::https://www.multiagentsystems.org/calendar/seminaires_toulouse.ics diff --git a/src/CAMSIParser.java b/src/CAMSIParser.java new file mode 100644 index 0000000..b074b16 --- /dev/null +++ b/src/CAMSIParser.java @@ -0,0 +1,125 @@ +import java.util.TimeZone; +import java.util.Calendar; +import java.util.Locale; + +import java.util.regex.Pattern; +import java.util.regex.Matcher; + +import java.io.BufferedReader; + +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamException; + +/** + * This class stores the incoming data from XML. + * It is needed because of the stream nature of the XML parser. + **/ +public class CAMSIParser +{ + final static Pattern event_pattern; + + static + { + event_pattern = Pattern.compile + ( + "[^<]*<td><[^>]*>([0-9]+)/([0-9]+)/([0-9]+)</[^>]*></td>" + + "<td><[^>]*>([0-9]+):([0-9]+)</[^>]*></td>" + + "<td><[^>]*>([0-9]+):([0-9]+)</[^>]*></td>" + + "<td><[^>]*>([^<]*)</[^>]*></td>" // 8th + + "<td><[^>]*>([^<]*)</[^>]*></td>" + + "<td><[^>]*>([^<]*)</[^>]*></td>" + ); + } + + public static void parse + ( + final BufferedReader reader, + final Group group, + final String uid_prefix + ) + throws Exception + { + int uid; + String line; + Matcher matcher; + + uid = 0; + + while (reader.ready()) + { + line = reader.readLine(); + matcher = event_pattern.matcher(line); + + if (matcher.matches()) + { + final Event e; + final java.util.Calendar c_start, c_end; + + c_start = java.util.Calendar.getInstance + ( + TimeZone.getTimeZone("Europe/Paris"), + Locale.FRENCH + ); + + c_start.set + ( + java.util.Calendar.DAY_OF_MONTH, + Integer.parseInt(matcher.group(1)) + ); + + c_start.set + ( + java.util.Calendar.MONTH, + /* It's Java... don't question it. */ + (Integer.parseInt(matcher.group(2)) - 1) + ); + + c_start.set + ( + java.util.Calendar.YEAR, + Integer.parseInt(matcher.group(3)) + ); + + c_start.set + ( + java.util.Calendar.HOUR_OF_DAY, + Integer.parseInt(matcher.group(4)) + ); + + c_start.set + ( + java.util.Calendar.MINUTE, + Integer.parseInt(matcher.group(5)) + ); + + + c_end = (java.util.Calendar) c_start.clone(); + + c_end.set + ( + java.util.Calendar.HOUR_OF_DAY, + Integer.parseInt(matcher.group(6)) + ); + + c_end.set + ( + java.util.Calendar.MINUTE, + Integer.parseInt(matcher.group(7)) + ); + + e = new Event(); + + e.set_start_time(c_start); + e.set_end_time(c_end); + e.set_name(matcher.group(8)); + e.add_speaker(matcher.group(9)); + e.add_location(matcher.group(10)); + e.set_uid(uid_prefix + (uid++)); + + group.add_event(e); + } + } + + reader.close(); + } +} diff --git a/src/Calendar.java b/src/Calendar.java new file mode 100644 index 0000000..18c097d --- /dev/null +++ b/src/Calendar.java @@ -0,0 +1,39 @@ +import java.util.ArrayList; +import java.util.List; +import java.util.HashMap; + +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.InputStreamReader; + +import java.util.concurrent.Callable; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; + +public class Calendar +{ + private Calendar () {} /* Utility class */ + + public static void main (final String[] args) + { + if (!Parameters.set_parameters(args)) + { + /** + * Printed usage. + **/ + return; + } + + Error.init_handler(); + + try + { + Classes.read_all(); + Group.read_all(); + Group.run_all(); + } + catch (final Exception e) {} + + Error.finalize_handler(); + } +} diff --git a/src/CelcatParser.java b/src/CelcatParser.java new file mode 100644 index 0000000..01e0314 --- /dev/null +++ b/src/CelcatParser.java @@ -0,0 +1,482 @@ +import java.util.HashMap; +import java.util.ArrayList; +import java.util.List; +import java.util.Calendar; +import java.util.Locale; +import java.util.Iterator; +import java.util.TimeZone; + +import java.io.PrintWriter; + +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamException; + +/** + * This class stores the incoming data from XML. + * It is needed because of the stream nature of the XML parser. + **/ +public class CelcatParser +{ + private final HashMap<Integer, Calendar> weeks; + private final Group group; + private String day; + private String week; + private String start_time; + private String end_time; + private String uid_prefix; + private Event event; + private DataType data_type; + private ListType current_list_type; + private int event_count; + + public static void parse + ( + final XMLStreamReader stream_reader, + final Group group, + final String uid_prefix + ) + throws XMLStreamException + { + final CelcatParser parser; + + parser = new CelcatParser(group, uid_prefix); + + while (stream_reader.hasNext()) + { + switch (stream_reader.next()) + { + case XMLStreamReader.START_ELEMENT: + parser.handle_new_element(stream_reader); + break; + + case XMLStreamReader.CDATA: + case XMLStreamReader.CHARACTERS: + parser.handle_data(stream_reader.getText().trim()); + break; + + case XMLStreamReader.END_DOCUMENT: + parser.flush(); + break; + + default: + break; + } + } + } + + private CelcatParser + ( + final Group group, + final String uid_prefix + ) + { + this.group = group; + this.uid_prefix = uid_prefix; + + event = null; + event_count = 0; + weeks = new HashMap<Integer, Calendar>(); + } + + /** + * Called when entering an new element. + **/ + private void handle_new_element (final XMLStreamReader stream_reader) + { + final DataType new_data_type; + + new_data_type = DataType.get(stream_reader.getLocalName()); + + switch (new_data_type) + { + case EVENT: + /** We're done handling the previous event. **/ + flush(); + break; + + case SPAN: + /** This contains information about the weeks. **/ + weeks.put + ( + Integer.parseInt + ( + stream_reader.getAttributeValue(null, "rawix") + ), + get_calendar_from_span + ( + stream_reader.getAttributeValue(null, "date") + ) + ); + break; + + case ROOM: + /** + * Multiple rooms may be concerned, hence the List. + * Any following ITEM elements should be considered as describing + * a room for this event. + **/ + current_list_type = ListType.ROOMS; + break; + + case GROUP: + /** + * Multiple groups may be concerned, hence the List. + * Any following ITEM elements should be considered as describing + * a group for this event. + **/ + current_list_type = ListType.GROUPS; + break; + + case ITEM: + if (data_type == DataType.MODULE) + { + /** + * The XML file will consider that the event may concern + * multiple modules. It makes sense, but I've never seen + * it happen and it complicates the process. + * Not updating the data_type here will make the next + * data be considered as the Module's name instead of + * something to add to a list. + **/ + + /* [XXX][Improvement] Handle it. */ + + return; + } + break; + + default: + break; + } + + data_type = new_data_type; + } + + private void flush () + { + week = null; + start_time = null; + end_time = null; + + if (event == null) + { + /** + * This is the first event, we don't have anything to write. + **/ + + event = new Event(); + event.set_uid(uid_prefix + (event_count++)); + + return; + } + + group.add_event(event); + + event = new Event(); + event.set_uid(uid_prefix + (event_count++)); + + current_list_type = ListType.IGNORED; + } + + /** + * Called when finding actual data. + **/ + private void handle_data (final String data) + { + if (data.equals("")) + { + /** + * Data was garbage. + * It happens sometimes, I don't know why. + **/ + + /* [XXX][Improvement] Prevent this from happening. */ + return; + } + + /** + * Uses the previously set "data_type" to know where the data belongs. + **/ + switch (data_type) + { + case MODULE: + event.set_name(data); + break; + + case STARTTIME: + if ((week == null) || (day == null)) + { + start_time = data; + } + else + { + event.set_start_time + ( + get_calendar + ( + week_to_calendar(week), + day, + data + ) + ); + } + break; + + case ENDTIME: + if ((week == null) || (day == null)) + { + end_time = data; + } + else + { + event.set_end_time + ( + get_calendar + ( + week_to_calendar(week), + day, + data + ) + ); + } + break; + + case NOTES: + if (event != null) + { + event.set_description("[Notes] " + data); + } + break; + + case RAWWEEKS: + week = data; + + if ((start_time != null) && (day != null)) + { + event.set_start_time + ( + get_calendar + ( + week_to_calendar(week), + day, + start_time + ) + ); + } + + if ((end_time != null) && (day != null)) + { + event.set_end_time + ( + get_calendar + ( + week_to_calendar(week), + day, + end_time + ) + ); + } + + break; + + case DAY: + day = data; + + if ((start_time != null) && (week != null)) + { + event.set_start_time + ( + get_calendar + ( + week_to_calendar(week), + day, + start_time + ) + ); + } + + if ((end_time != null) && (week != null)) + { + event.set_end_time + ( + get_calendar + ( + week_to_calendar(week), + day, + end_time + ) + ); + } + break; + + case CATEGORY: + event.set_category(data); + break; + + case ITEM: + switch (current_list_type) + { + case ROOMS: + event.add_location(data); + break; + + case GROUPS: + event.add_attendee(data); + break; + + default: + break; + } + break; + } + } + + /** + * Retrieves the relevant data from a week description. + **/ + private Calendar get_calendar_from_span (final String spandata) + { + final String[] data; + final Calendar result; + + data = spandata.split("/"); + + result = + java.util.Calendar.getInstance + ( + TimeZone.getTimeZone("Europe/Paris"), + Locale.FRENCH + ); + + if (data.length != 3) + { + Error.ERROR.from_thread + ( + group.get_abbreviation(), + ("Invalid date format for week:" + spandata) + ); + + return null; + } + + result.set(java.util.Calendar.DAY_OF_MONTH, Integer.parseInt(data[0])); + + /* Java... don't ask... */ + result.set(java.util.Calendar.MONTH, Integer.parseInt(data[1]) - 1); + + result.set(java.util.Calendar.YEAR, Integer.parseInt(data[2])); + + return result; + } + + + /** + * Retrieves the week relevant to the event being processed. + **/ + private Calendar week_to_calendar + ( + final String week + ) + { + final java.util.Calendar result; + int pos; + + for (pos = 0; week.charAt(pos) != 'Y'; ++pos); + + result = weeks.get(pos + 1); + + if (result == null) + { + Error.ERROR.from_thread + ( + group.get_abbreviation(), + "An event appeared before its week description did." + ); + } + + return result; + } + + private java.util.Calendar get_calendar + ( + final Calendar week, + final String day, + final String hourmin + ) + { + final String[] time; + final java.util.Calendar result; + + time = hourmin.split(":"); + + result = (java.util.Calendar) week.clone(); + + result.set(java.util.Calendar.HOUR_OF_DAY, Integer.parseInt(time[0])); + result.set(java.util.Calendar.MINUTE, Integer.parseInt(time[1])); + result.add(java.util.Calendar.DAY_OF_YEAR, Integer.parseInt(day)); + + return result; + } + + private static enum ListType + { + IGNORED, ROOMS, GROUPS; + } + + /** + * This enum is used to sort what is relevant in the XML file. + * Sadly, for justified reasons, Java does not permit access to the static + * members of an enum from its constructor, hence the "static"'s redundancy. + **/ + private static enum DataType + { + IRRELEVANT, + EVENT, + DAY, + STARTTIME, + ENDTIME, + CATEGORY, + RAWWEEKS, + ITEM, + MODULE, + ROOM, + SPAN, + NOTES, + GROUP; + + private static final HashMap<String, DataType> FROM_STRING; + + static + { + FROM_STRING = new HashMap<String, DataType>(); + + FROM_STRING.put("irrelevant", IRRELEVANT); + FROM_STRING.put("event", EVENT); + FROM_STRING.put("day", DAY); + FROM_STRING.put("starttime", STARTTIME); + FROM_STRING.put("endtime", ENDTIME); + FROM_STRING.put("category", CATEGORY); + FROM_STRING.put("item", ITEM); + FROM_STRING.put("module", MODULE); + FROM_STRING.put("room", ROOM); + FROM_STRING.put("group", GROUP); + FROM_STRING.put("rawweeks", RAWWEEKS); + FROM_STRING.put("span", SPAN); + FROM_STRING.put("notes", NOTES); + } + + public static DataType get (final String e) + { + final DataType result; + + result = FROM_STRING.get(e); + + if (result == null) + { + return IRRELEVANT; + } + + return result; + } + } +} diff --git a/src/Classes.java b/src/Classes.java new file mode 100644 index 0000000..31cc0fa --- /dev/null +++ b/src/Classes.java @@ -0,0 +1,341 @@ +import java.util.List; +import java.util.Set; +import java.util.HashMap; + +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.InputStreamReader; + +public class Classes +{ + private static final HashMap<String, Classes> FROM_ABBREVIATION; + private static final HashMap<String, Classes> FROM_NAME; + private static final String SEPARATOR = " ,.?-&:;"; + + private final String name; + private final String abbreviation; + + static + { + FROM_ABBREVIATION = new HashMap<String, Classes>(); + FROM_NAME = new HashMap<String, Classes>(); + } + + private Classes (final String name, final String abbreviation) + { + this.name = name; + this.abbreviation = abbreviation; + } + + private void register () + throws Classes.AlreadyRegisteredException + { + /** + * We allow multiple (unique) names for the same class, but not + * multiple abbreviations + **/ + + if (FROM_NAME.containsKey(name)) + { + throw (new Classes.AlreadyRegisteredException()); + } + + if (!FROM_ABBREVIATION.containsKey(abbreviation)) + { + FROM_ABBREVIATION.put(abbreviation, this); + } + + FROM_NAME.put(name, this); + } + + @Override + public boolean equals (Object a) + { + if (a instanceof Classes) + { + return abbreviation.equals(((Classes) a).abbreviation); + } + + return false; + } + + @Override + public String toString () + { + return abbreviation; + } + + public static String name_from_abbreviation (final String abbr) + { + final Classes c; + + c = FROM_ABBREVIATION.get(abbr); + + if (c == null) + { + return "unknown"; + } + + return c.name; + } + + private static boolean word_is_isolated + ( + final String word, + final String sentence + ) + { + final int index_start, index_end; + + index_start = sentence.indexOf(word); + + if + ( + (index_start == -1) + || (index_start == 0) + || (SEPARATOR.indexOf(sentence.charAt(index_start - 1)) == -1) + ) + { + return false; + } + + index_end = (index_start + word.length()); + + if (index_end == sentence.length()) + { + return true; + } + + return (SEPARATOR.indexOf(sentence.charAt(index_end)) != -1); + } + + private static Classes ambiguous_entry_guard + ( + final String entry, + final String class_name + ) + { + final String rest_of_entry_name; + boolean ambiguous; + + ambiguous = false; + rest_of_entry_name = entry.substring(class_name.length()); + + for (final String other_class_name: FROM_NAME.keySet()) + { + if + ( + !other_class_name.equals(class_name) + && word_is_isolated(other_class_name, rest_of_entry_name) + && !FROM_NAME.get(class_name).equals + ( + FROM_NAME.get(other_class_name) + ) + ) + { + final StringBuilder sb; + + sb = new StringBuilder(); + + sb.append("Ambiguous event summary \""); + sb.append(entry); + sb.append("\". Starts with \""); + sb.append(class_name); + sb.append("\" ("); + sb.append(FROM_NAME.get(class_name)); + sb.append("), but also contains \""); + sb.append(other_class_name); + sb.append("\" ("); + sb.append(FROM_NAME.get(other_class_name)); + sb.append(")"); + + Error.WARNING.from_file + ( + Parameters.get_known_classes_filename(), + sb.toString() + ); + + ambiguous = true; + + break; + } + } + + return ambiguous ? null : FROM_NAME.get(class_name); + } + public static String abbreviation_from_name + ( + final String name, + final boolean lazy + ) + { + Classes c; + + if (lazy) + { + c = null; + + for (final String n: FROM_NAME.keySet()) + { + if (name.startsWith(n)) + { + c = ambiguous_entry_guard(name, n); + + break; + } + } + } + else + { + c = FROM_NAME.get(name); + } + + if (c == null) + { + return "unknown"; + } + + return c.abbreviation; + } + + public static Set<String> get_all_abbreviations () + { + return FROM_ABBREVIATION.keySet(); + } + + public static void read_all () + throws Exception + { + BufferedReader br; + String input_line; + String[] data; + Classes new_class; + + br = null; + + try + { + br = + new BufferedReader + ( + new InputStreamReader + ( + new FileInputStream(Parameters.get_known_classes_filename()) + ) + ); + + while ((input_line = br.readLine()) != null) + { + data = input_line.split("::"); + + if (data.length != 3) + { + final StringBuilder sb; + + sb = new StringBuilder(); + + sb.append("Invalid class entry: \""); + sb.append(input_line); + + Error.ERROR.from_file + ( + Parameters.get_known_classes_filename(), + sb.toString() + ); + + continue; + } + + new_class = new Classes(data[1], data[2]); + + if (!data[0].equals("") && FROM_ABBREVIATION.containsKey(data[2])) + { + final StringBuilder sb; + + sb = new StringBuilder(); + + sb.append("Abbreviation \""); + sb.append(data[2]); + sb.append("\" is already in use."); + + Error.ERROR.from_file + ( + Parameters.get_known_classes_filename(), + sb.toString() + ); + + continue; + } + + try + { + new_class.register(); + } + catch (final Classes.AlreadyRegisteredException care) + { + final StringBuilder sb; + + sb = new StringBuilder(); + + sb.append("Duplicate entry for class \""); + sb.append(data[1]); + sb.append("\"."); + + Error.ERROR.from_file + ( + Parameters.get_known_classes_filename(), + sb.toString() + ); + + continue; + } + } + } + catch (final Exception e) + { + Error.FATAL.from_file + ( + Parameters.get_known_classes_filename(), + "Error while reading class file:", + e.getMessage() + ); + + if (br != null) + { + try + { + br.close(); + } + catch (final Exception e2) + { + Error.WARNING.from_file + ( + Parameters.get_known_classes_filename(), + "Error while closing class file:", + e2.getMessage() + ); + } + } + + throw e; + } + + try + { + br.close(); + } + catch (final Exception e) + { + Error.WARNING.from_file + ( + Parameters.get_known_classes_filename(), + "Error while closing class file:", + e.getMessage() + ); + + throw e; + } + } + + private static class AlreadyRegisteredException extends Exception {} +} diff --git a/src/DHXCalParser.java b/src/DHXCalParser.java new file mode 100644 index 0000000..bad0581 --- /dev/null +++ b/src/DHXCalParser.java @@ -0,0 +1,263 @@ +import java.util.HashMap; +import java.util.ArrayList; +import java.util.List; +import java.util.Calendar; +import java.util.Locale; +import java.util.Iterator; +import java.util.TimeZone; + +import java.io.PrintWriter; + +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamException; + +/** + * This class stores the incoming data from XML. + * It is needed because of the stream nature of the XML parser. + **/ +public class DHXCalParser +{ + private final Group group; + private String uid_prefix; + private Event event; + private DataType data_type; + private int event_count; + + public static void parse + ( + final XMLStreamReader stream_reader, + final Group group, + final String uid_prefix + ) + throws XMLStreamException + { + final DHXCalParser parser; + + parser = new DHXCalParser(group, uid_prefix); + + while (stream_reader.hasNext()) + { + switch (stream_reader.next()) + { + case XMLStreamReader.START_ELEMENT: + parser.handle_new_element(stream_reader); + break; + + case XMLStreamReader.CDATA: + case XMLStreamReader.CHARACTERS: + parser.handle_data(stream_reader.getText().trim()); + break; + + case XMLStreamReader.END_DOCUMENT: + parser.flush(); + break; + + default: + break; + } + } + } + + private DHXCalParser + ( + final Group group, + final String uid_prefix + ) + { + this.group = group; + this.uid_prefix = uid_prefix; + + event = null; + event_count = 0; + } + + /** + * Called when entering an new element. + **/ + private void handle_new_element (final XMLStreamReader stream_reader) + { + final DataType new_data_type; + + new_data_type = DataType.get(stream_reader.getLocalName()); + + switch (new_data_type) + { + case EVENT: + /** We're done handling the previous event. **/ + flush(); + break; + + default: + break; + } + + data_type = new_data_type; + } + + private void flush () + { + if (event == null) + { + /** + * This is the first event, we don't have anything to write. + **/ + + event = new Event(); + event.set_uid(uid_prefix + (event_count++)); + + return; + } + + group.add_event(event); + + event = new Event(); + event.set_uid(uid_prefix + (event_count++)); + } + + /** + * Called when finding actual data. + **/ + private void handle_data (final String data) + { + final String[] info; + final StringBuilder sb; + int i; + + if (data.equals("")) + { + /** + * Data was garbage. + * It happens sometimes, I don't know why. + **/ + + /* [XXX][Improvement] Prevent this from happening. */ + return; + } + + /** + * Uses the previously set "data_type" to know where the data belongs. + **/ + switch (data_type) + { + case START_DATE: + event.set_start_time(date_to_calendar(data)); + break; + + case END_DATE: + event.set_end_time(date_to_calendar(data)); + break; + + case TEXT: + info = + data.replaceAll + ( + "<b>|</b>", + "" + ).replaceAll + ( + "\\s+", + " " + ).split("<br />"); + + event.set_name(info[0]); + + sb = new StringBuilder(); + + for (i = 1; i < info.length; ++i) + { + sb.append(info[i].trim()); + sb.append(", "); + } + + if (info.length > 1) + { + sb.delete((sb.length() - 2), sb.length()); + } + + event.set_description(sb.toString()); + break; + + case DETAILS: + // TODO + break; + + default: + break; + } + } + + private static Calendar date_to_calendar (final String data) + { + final String[] day_hour; + final String[] hour; + final String[] day; + final java.util.Calendar result; + + day_hour = data.split(" "); + hour = day_hour[1].split(":"); + day = day_hour[0].split("-"); + + result = + java.util.Calendar.getInstance + ( + TimeZone.getTimeZone("Europe/Paris"), + Locale.FRENCH + ); + + result.set(java.util.Calendar.DAY_OF_MONTH, Integer.parseInt(day[2])); + + /* Java... don't ask... */ + result.set(java.util.Calendar.MONTH, Integer.parseInt(day[1]) - 1); + result.set(java.util.Calendar.YEAR, Integer.parseInt(day[0])); + + result.set(java.util.Calendar.HOUR_OF_DAY, Integer.parseInt(hour[0])); + result.set(java.util.Calendar.MINUTE, Integer.parseInt(hour[1])); + + return result; + } + + /** + * This enum is used to sort what is relevant in the XML file. + * Sadly, for justified reasons, Java does not permit access to the static + * members of an enum from its constructor, hence the "static"'s redundancy. + **/ + private static enum DataType + { + IRRELEVANT, + EVENT, + START_DATE, + END_DATE, + TEXT, + DETAILS, + DATA; + + private static final HashMap<String, DataType> FROM_STRING; + + static + { + FROM_STRING = new HashMap<String, DataType>(); + + FROM_STRING.put("irrelevant", IRRELEVANT); + FROM_STRING.put("event", EVENT); + FROM_STRING.put("start_date", START_DATE); + FROM_STRING.put("end_date", END_DATE); + FROM_STRING.put("text", TEXT); + FROM_STRING.put("details", DETAILS); + FROM_STRING.put("data", DATA); + } + + public static DataType get (final String e) + { + final DataType result; + + result = FROM_STRING.get(e); + + if (result == null) + { + return IRRELEVANT; + } + + return result; + } + } +} diff --git a/src/Error.java b/src/Error.java new file mode 100644 index 0000000..2f40e4b --- /dev/null +++ b/src/Error.java @@ -0,0 +1,196 @@ +import java.util.concurrent.Semaphore; + +import java.io.PrintWriter; +import java.io.FileWriter; + +public enum Error +{ + WARNING("[W]"), + ERROR("[E]"), + FATAL("[F]"), + PROGRAM("[P]"); /* Errors that should not if the code's logic was correct. */ + + private static final Semaphore MUTEX; + private static PrintWriter OUTPUT; + private final String emblem; + private int count; + + static + { + MUTEX = new Semaphore(1); + } + + private Error (final String emblem) + { + this.emblem = emblem; + this.count = 0; + } + + public static int init_handler () + { + try + { + OUTPUT = + new PrintWriter + ( + new FileWriter(Parameters.get_log_filename()) + ); + } + catch (final Exception e) + { + System.err.println("[F] Could not init the Error Handler:"); + e.printStackTrace(); + + return -1; + } + + return 0; + } + + public static void finalize_handler () + { + OUTPUT.flush(); + OUTPUT.close(); + + summary(); + } + + public void from_thread + ( + final String thread_id, + final String error + ) + { + try + { + MUTEX.acquire(); + + OUTPUT.print(emblem); + OUTPUT.print("[Thread: "); + OUTPUT.print(thread_id); + OUTPUT.print("] "); + OUTPUT.println(error); + + ++count; + + MUTEX.release(); + } + catch (final InterruptedException ie) + { + System.err.println + ( + "[W] An thread was interrupted while trying to report an error." + ); + } + } + + public void from_thread + ( + final String thread_id, + final String error, + final String report + ) + { + try + { + MUTEX.acquire(); + + OUTPUT.print(emblem); + OUTPUT.print("[Thread: "); + OUTPUT.print(thread_id); + OUTPUT.print("] "); + OUTPUT.println(error); + OUTPUT.println(report); + + ++count; + + MUTEX.release(); + } + catch (final InterruptedException ie) + { + System.err.println + ( + "[W] An thread was interrupted while trying to report an error." + ); + } + } + + public void from_file + ( + final String filename, + final String error + ) + { + try + { + MUTEX.acquire(); + + OUTPUT.print(emblem); + OUTPUT.print("[File: "); + OUTPUT.print(filename); + OUTPUT.print("] "); + OUTPUT.println(error); + + ++count; + + MUTEX.release(); + } + catch (final InterruptedException ie) + { + System.err.println + ( + "[W] An thread was interrupted while trying to report an error." + ); + } + } + + public void from_file + ( + final String filename, + final String error, + final String report + ) + { + try + { + MUTEX.acquire(); + + OUTPUT.print(emblem); + OUTPUT.print("[File: "); + OUTPUT.print(filename); + OUTPUT.print("] "); + OUTPUT.println(error); + OUTPUT.println(report); + + ++count; + + MUTEX.release(); + } + catch (final InterruptedException ie) + { + System.err.println + ( + "[W] An thread was interrupted while trying to report an error." + ); + } + } + + private static void summary () + { + final StringBuilder sb; + + sb = new StringBuilder(); + + sb.append("Log report:\n"); + + for (final Error e: Error.values()) + { + sb.append(e.emblem); + sb.append(" "); + sb.append(e.count); + sb.append("\n"); + } + + System.out.println(sb.toString()); + } +} diff --git a/src/Event.java b/src/Event.java new file mode 100644 index 0000000..4a56475 --- /dev/null +++ b/src/Event.java @@ -0,0 +1,286 @@ +import java.util.ArrayList; +import java.util.List; + +import java.util.Locale; +import java.util.Calendar; +import java.util.TimeZone; + +public class Event +{ + private final List<String> locations; + private final List<String> speakers; + private final List<String> attendees; + private String name; + private String category; + private String uid; + private String description; + private java.util.Calendar start_time; + private java.util.Calendar end_time; + private java.util.Calendar creation_time; + + public Event () + { + locations = new ArrayList<String>(); + speakers = new ArrayList<String>(); + attendees = new ArrayList<String>(); + + name = null; + category = null; + description = null; + start_time = null; + end_time = null; + + creation_time = + java.util.Calendar.getInstance + ( + TimeZone.getTimeZone("Europe/Paris"), + Locale.FRENCH + ); + } + + public String get_name () + { + return name; + } + + public void set_name (final String val) + { + if (val != null) + { + name = + val.trim + ( + ).replaceAll + ( + "(?<!\\\\),", + "\\\\," + ).replaceAll + ( + "(?<!\\\\);", + "\\\\;" + ); + } + } + + public void set_description (final String val) + { + if (val != null) + { + description = + val.replaceAll + ( + "(?<!\\\\),", + "\\\\," + ).replaceAll + ( + "(?<!\\\\);", + "\\\\;" + ); + } + } + + public void set_category (final String val) + { + if (val != null) + { + category = val; + } + } + + public void set_uid (final String val) + { + if (val != null) + { + uid = val; + } + } + + public void set_start_time (final java.util.Calendar val) + { + if (val != null) + { + start_time = val; + } + } + + public void set_end_time (final java.util.Calendar val) + { + if (val != null) + { + end_time = val; + } + } + + public void add_location (final String str) + { + locations.add(str); + } + + public void add_speaker (final String str) + { + speakers.add(str); + } + + public void add_attendee (final String str) + { + attendees.add(str); + } + + public String toString() + { + final StringBuilder sb; + final String creation_time_str; + + sb = new StringBuilder(); + + creation_time_str = get_time(creation_time); + + sb.append("BEGIN:VEVENT"); + + sb.append("\r\nSUMMARY:"); + + if (category != null) + { + sb.append("["); + sb.append(category); + sb.append("] "); + } + + if (name != null) + { + sb.append(name); + } + + if (!locations.isEmpty()) + { + sb.append("\r\nLOCATION:"); + + for (final String s: locations) + { + sb.append(s); + sb.append("\\n"); + } + + sb.delete(sb.length() - 2, sb.length()); + } + + sb.append("\r\nDESCRIPTION:"); + + if (description != null) + { + sb.append(description); + + if + ( + !speakers.isEmpty() + || !attendees.isEmpty() + ) + { + sb.append("\\n"); + } + } + if (!speakers.isEmpty()) + { + + for (final String s: speakers) + { + sb.append("[Speaker] "); + sb.append(s); + sb.append("\\n"); + } + + if (attendees.isEmpty()) + { + sb.delete(sb.length() - 2, sb.length()); + } + } + + if (!attendees.isEmpty()) + { + + for (final String s: attendees) + { + sb.append("[Attendee] "); + sb.append(s); + sb.append("\\n"); + } + + sb.delete(sb.length() - 2, sb.length()); + } + + + sb.append("\r\nUID:"); + sb.append(uid); + + sb.append("\r\nCREATED:"); + sb.append(creation_time_str); + + sb.append("\r\nLAST-MODIFIED:"); + sb.append(creation_time_str); + + sb.append("\r\nDTSTART:"); + sb.append(get_time(start_time)); + + sb.append("\r\nDTEND:"); + sb.append(get_time(end_time)); + + sb.append("\r\nSTATUS:CONFIRMED"); + + sb.append("\r\nSEQUENCE:0"); + + sb.append("\r\nTRANSP:OPAQUE"); + + sb.append("\r\nEND:VEVENT"); + + return sb.toString(); + } + + private String get_time (final java.util.Calendar cal) + { + final StringBuilder sb; + int val; + + sb = new StringBuilder(); + + sb.append(cal.get(java.util.Calendar.YEAR)); + + val = cal.get(java.util.Calendar.MONTH) + 1; /* Java... don't ask... */ + + if (val < 10) + { + sb.append("0"); + } + + sb.append(val); + + append_two_digit(sb, cal, java.util.Calendar.DAY_OF_MONTH); + + sb.append("T"); + + append_two_digit(sb, cal, java.util.Calendar.HOUR_OF_DAY); + append_two_digit(sb, cal, java.util.Calendar.MINUTE); + + sb.append("00"); + + return sb.toString(); + } + + private void append_two_digit + ( + final StringBuilder sb, + final java.util.Calendar cal, + final int val_id + ) + { + final int val; + + val = cal.get(val_id); + + if (val < 10) + { + sb.append("0"); + } + + sb.append(val); + } +} diff --git a/src/Group.java b/src/Group.java new file mode 100644 index 0000000..3e1a1f2 --- /dev/null +++ b/src/Group.java @@ -0,0 +1,560 @@ +import java.util.HashMap; +import java.util.List; +import java.util.ArrayList; +import java.util.Arrays; + +import java.util.concurrent.Callable; +import java.util.concurrent.Executors; +import java.util.concurrent.ExecutorService; + +import java.io.BufferedReader; +import java.io.PrintWriter; +import java.io.FileWriter; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.io.IOException; + +import java.net.URL; + +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamReader; + +public class Group extends Thread +{ + private static final HashMap<String, Group> KNOWN_GROUPS; + private final HashMap<String, PrintWriter> class_files; + private final String name; + private final String abbreviation; + private final String[] url; + private final Group.Type[] type; + + static + { + KNOWN_GROUPS = new HashMap<String, Group>(); + } + + private Group + ( + final String name, + final String abbreviation, + final String[] types_and_urls + ) + { + final int sources; + int j; + + sources = (types_and_urls.length / 2); + + this.name = name; + this.abbreviation = abbreviation; + + url = new String[sources]; + type = new Group.Type[sources]; + + for (int i = 0; i < sources; ++i) + { + j = (i * 2); + type[i] = Type.get(types_and_urls[j]); + url[i] = types_and_urls[j + 1]; + } + + class_files = new HashMap<String, PrintWriter>(); + } + + private void register () + throws Group.AlreadyRegisteredException + { + if (KNOWN_GROUPS.containsKey(abbreviation)) + { + throw (new Group.AlreadyRegisteredException()); + } + + KNOWN_GROUPS.put(abbreviation, this); + } + + public String get_abbreviation () + { + return abbreviation; + } + + public void add_event (final Event event) + { + final PrintWriter pw; + + pw = + class_files.get + ( + Classes.abbreviation_from_name + ( + event.get_name(), + false + ) + ); + + pw.println(event.toString()); + pw.flush(); + } + + public void add_ICS_fragment + ( + final String fragment, + final String class_name, + final boolean lazy + ) + { + final PrintWriter pw; + + pw = + class_files.get + ( + Classes.abbreviation_from_name(class_name, lazy) + ); + + // Escapes all ',' or ';' not directly preceded by '\'. + // That's quite an inefficient way to do it btw. + pw.print + ( + fragment.replaceAll + ( + "(?<!\\\\),", + "\\\\," + ).replaceAll + ( + "(?<!\\\\);", + "\\\\;" + ) + ); + + pw.flush(); + } + + private static enum Type + { + CELCAT(true), + DHX_CAL(true), + ICS(false), + LAZY_ICS(false), + ICS_NOUID(false), + LAZY_ICS_NOUID(false), + CAMSI(false); + + public final boolean uses_xml; + + private Type (final boolean uses_xml) + { + this.uses_xml = uses_xml; + } + + public static Type get (final String str) + { + if (str.equals("celcat")) + { + return CELCAT; + } + else if (str.equals("dhx_cal")) + { + return DHX_CAL; + } + else if (str.equals("ics_nouid")) + { + return ICS_NOUID; + } + else if (str.equals("lazy_ics_nouid")) + { + return LAZY_ICS_NOUID; + } + else if (str.equals("ics")) + { + return ICS; + } + else if (str.equals("lazy_ics")) + { + return LAZY_ICS; + } + else if (str.equals("camsi")) + { + return CAMSI; + } + + return null; + } + } + + private boolean create_class_files () + { + try + { + for (final String abbr: Classes.get_all_abbreviations()) + { + class_files.put + ( + abbr, + new PrintWriter + ( + new FileWriter + ( + Parameters.get_output_directory() + + "/" + + abbreviation + + "_" + + abbr + + ".ics" + ) + ) + ); + } + + class_files.put + ( + "unknown", + new PrintWriter + ( + new FileWriter + ( + Parameters.get_output_directory() + + "/" + + abbreviation + + "_unknown.ics" + ) + ) + ); + } + catch (final IOException e) + { + Error.ERROR.from_thread + ( + abbreviation, + ("Could not create output file: " + e.toString()) + ); + + return false; + } + + return true; + } + + private void finalize_class_files () + { + for (final PrintWriter pw: class_files.values()) + { + pw.flush(); + pw.close(); + } + } + + private InputStreamReader remove_fuckups + ( + final InputStreamReader irs + ) + throws Exception + { + final BufferedReader in; + final PrintWriter pw; + final String filename; + String input; + boolean first_line; + + filename = + ( + Parameters.get_output_directory() + + "/" + + abbreviation + + ".fuckup" + ); + + in = new BufferedReader(irs); + pw = new PrintWriter(filename); + + first_line = true; + + while ((input = in.readLine()) != null) + { + if (!input.equals("")) + { + if (first_line) + { + pw.println(input.trim().replaceFirst("^([\\W]+)<","<")); + first_line = false; + } + else + { + pw.println(input); + } + } + } + + pw.close(); + irs.close(); + + return (new InputStreamReader(new FileInputStream(filename))); + } + + private void parse_source + ( + final int id, + final Group.Type type, + final String url + ) + throws Exception + { + final XMLInputFactory input_factory; + final XMLStreamReader stream_reader; + final StringBuilder sb; + + if (type.uses_xml) + { + input_factory = XMLInputFactory.newInstance(); + stream_reader = + input_factory.createXMLStreamReader + ( + remove_fuckups(new InputStreamReader((new URL(url)).openStream(), "UTF-8")) + ); + sb = new StringBuilder(); + + sb.append(abbreviation); + sb.append("_s"); + sb.append(id); + sb.append("_event"); + } + else + { + stream_reader = null; + sb = null; + } + + switch (type) + { + case CELCAT: + CelcatParser.parse(stream_reader, this, sb.toString()); + break; + + case DHX_CAL: + DHXCalParser.parse(stream_reader, this, sb.toString()); + break; + + case ICS_NOUID: + ICSParser.parse(url, this, false, true); + break; + + case LAZY_ICS_NOUID: + ICSParser.parse(url, this, true, true); + break; + + case ICS: + ICSParser.parse(url, this, false, false); + break; + + case LAZY_ICS: + ICSParser.parse(url, this, true, false); + break; + + case CAMSI: + CAMSIParser.parse + ( + new BufferedReader + ( + new InputStreamReader + ( + (new URL(url)).openStream() + ) + ), + this, + (abbreviation + "_s" + id + "_event") + ); + break; + } + } + + @Override + public void run () + { + + if (!create_class_files()) + { + return; + } + + for (int i = 0; i < type.length; ++i) + { + try + { + parse_source(i, type[i], url[i]); + } + catch (final Exception e) + { + final StringBuilder sb; + + sb = new StringBuilder(); + + sb.append("An error occured while parsing source '"); + sb.append(url[i]); + sb.append("'"); + + Error.ERROR.from_thread + ( + abbreviation, + sb.toString(), + e.getMessage() + ); + } + } + + finalize_class_files(); + } + + public static void read_all () + { + BufferedReader br; + String input_line; + String[] data; + Group new_group; + + br = null; + + try + { + br = + new BufferedReader + ( + new InputStreamReader + ( + new FileInputStream(Parameters.get_groups_filename()) + ) + ); + + while ((input_line = br.readLine()) != null) + { + data = input_line.split("::"); + + if (data.length >= 4 && ((data.length % 2) == 0)) + { + new_group = + new Group + ( + data[0], + data[1], + Arrays.copyOfRange(data, 2, data.length) + ); + + try + { + new_group.register(); + } + catch (final Group.AlreadyRegisteredException e) + { + final StringBuilder sb; + + sb = new StringBuilder(); + + sb.append("Duplicate group entry for group \""); + sb.append(new_group.name); + sb.append("\"."); + + Error.ERROR.from_file + ( + Parameters.get_groups_filename(), + sb.toString() + ); + + continue; + } + } + else + { + final StringBuilder sb; + + sb = new StringBuilder(); + + sb.append("Invalid group entry: \""); + sb.append(input_line); + sb.append("\"."); + + Error.ERROR.from_file + ( + Parameters.get_groups_filename(), + sb.toString() + ); + + continue; + } + } + } + catch (final Exception e) + { + Error.FATAL.from_file + ( + Parameters.get_groups_filename(), + "Error while reading file:", + e.getMessage() + ); + + if (br != null) + { + try + { + br.close(); + } + catch (final Exception e2) + { + Error.WARNING.from_file + ( + Parameters.get_groups_filename(), + "Error while closing file:", + e2.getMessage() + ); + } + } + + return; + } + + try + { + br.close(); + } + catch (final Exception e) + { + Error.WARNING.from_file + ( + Parameters.get_groups_filename(), + "Error while closing file:", + e.getMessage() + ); + } + } + + /** + * Creates Group threads (one per group) to translate each XML file. + * For performance reasons, we limit the number of threads running + * concurrently at a give time (also, I'm on shared hosting and the task + * doesn't actually need to be very fast so I avoid being too greedy). + **/ + public static void run_all () + { + final ExecutorService exec; + final List<Callable<Object>> groups; + + groups = new ArrayList<Callable<Object>>(); + + exec = Executors.newFixedThreadPool(Parameters.get_max_threads()); + + for (final Group g: KNOWN_GROUPS.values()) + { + groups.add(Executors.callable(g)); + } + + /** This won't return until all is done. **/ + try + { + exec.invokeAll(groups); + } + catch (final InterruptedException ie) + { + Error.FATAL.from_thread("main", "Interrupted before the end."); + } + + exec.shutdown(); + } + + private static class AlreadyRegisteredException extends Exception {} +} diff --git a/src/ICSParser.java b/src/ICSParser.java new file mode 100644 index 0000000..ac4f96d --- /dev/null +++ b/src/ICSParser.java @@ -0,0 +1,99 @@ +import java.io.BufferedReader; +import java.io.InputStreamReader; + +import java.security.MessageDigest; + +import java.net.URL; + +public class ICSParser +{ + + public static void parse + ( + final String url, + final Group group, + final boolean lazy, + final boolean uid_override + ) + throws Exception + { + final BufferedReader reader; + final StringBuilder sb; + + boolean should_record, has_id, ignore_line; + String line; + String class_name; + String hash_seed; + int length; + sb = new StringBuilder(); + reader = + new BufferedReader(new InputStreamReader((new URL(url)).openStream())); + + class_name = "unknown"; + should_record = false; + ignore_line = false; + + hash_seed = ""; + has_id = false; + + while ((line = reader.readLine()) != null) + { + if (line.startsWith("END:VEVENT")) + { + if (!has_id) + { + sb.append("UID:noid_"); + sb.append(hash_seed.hashCode()); + sb.append("\r\n"); + } + + sb.append(line); + sb.append("\r\n"); + + should_record = false; + + group.add_ICS_fragment(sb.toString(), class_name, lazy); + sb.setLength(0); + } + else if (line.startsWith("BEGIN:VEVENT")) + { + should_record = true; + has_id = false; + hash_seed = ""; + } + else if (line.startsWith("DTSTART:")) + { + hash_seed += line; + } + else if (line.startsWith("SUMMARY:")) + { + class_name = line.substring(8, line.length()); + hash_seed += line; + } + else if (line.startsWith("UID")) + { + if (uid_override) + { + ignore_line = true; + } + else + { + has_id = true; + } + } + + if (line.matches("\\w+:.*") && should_record) + { + if (!ignore_line) + { + sb.append(line); + sb.append("\r\n"); + } + + ignore_line = false; + } + } + + reader.close(); + } +} diff --git a/src/Parameters.java b/src/Parameters.java new file mode 100644 index 0000000..d323908 --- /dev/null +++ b/src/Parameters.java @@ -0,0 +1,135 @@ +public class Parameters +{ + private static String output_dir; + private static String log_filename, known_classes_filename, groups_filename; + private static int threads; + + static + { + output_dir = "../output/"; + log_filename = "../last_log"; + known_classes_filename = "../data/KNOWN_CLASSES"; + groups_filename = "../data/GROUPS"; + threads = 8; + } + + private Parameters () {} /** utility class **/ + + public static boolean set_parameters (final String[] args) + { + int i; + + for (i = 0; i < args.length; i++) + { + if(args[i].equals("--outputs")) + { + i++; + output_dir = args[i]; + } + else if(args[i].equals("--log")) + { + i++; + log_filename = args[i]; + } + else if(args[i].equals("--classes")) + { + i++; + known_classes_filename = args[i]; + } + else if(args[i].equals("--groups")) + { + i++; + groups_filename = args[i]; + } + else if(args[i].equals("--threads")) + { + i++; + threads = Integer.parseInt(args[i]); + } + else if(args[i].equals("--help") || args[i].equals("-h")) + { + usage(); + + return false; + } + else + { + System.err.println("[W] Unknown parameter:" + args[i]); + } + } + + return true; + } + + private static void usage () + { + final StringBuilder sb; + + sb = new StringBuilder(); + + sb.append + ( + ").\n\"--outputs directory\": where the 'ICS' files are written " + + "(default: " + ); + sb.append(output_dir); + + sb.append + ( + ").\n\"--log filename\": where the errors are reported (default: " + ); + sb.append(log_filename); + + sb.append + ( + ").\n\"--classes filename\": file containing the known classes " + + "(default: " + ); + sb.append(known_classes_filename); + + sb.append + ( + ").\n\"--groups filename\": file containing the groups (default: " + ); + sb.append(groups_filename); + + sb.append + ( + ").\n\"--threads number\": maximum number of threads running at " + + "any time (default: " + ); + sb.append(threads); + + sb.append + ( + ").\n\"--help\": prints this instead of converting (alias: \"-h\")." + ); + + System.out.println(sb.toString()); + } + + public static String get_output_directory () + { + return output_dir; + } + + public static String get_log_filename () + { + return log_filename; + } + + public static String get_known_classes_filename () + { + return known_classes_filename; + } + + public static String get_groups_filename () + { + return groups_filename; + } + + public static int get_max_threads () + { + return threads; + } +} |