diff --git a/README.md b/README.md index 6a378e6..1fed8c7 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,23 @@ -Ceci est votre dépôt pour le projet PACT. - -Vous **DEVEZ** modifier ce fichier (`README.md`) et créer tous les -répertoires et fichiers dont vous aurez besoin pour votre projet. - -# Important, le rapport d'avancement - -Le répertoire `rapport` contient un squelette pour votre rapporte d'avancement. -Ce répertoire **ne doit pas être renommé** ni le fichier `README.adoc` qu'il contient. -Le fichier `README.adoc` est le point d'entrée du rapport. - -Il est rédigé en utilisant le langage [**AsciiDoc**](http://asciidoc.org/). -La syntaxe est supportée par GitLab qui le formatera correctement dans l'interface Web. - -Le document final sera généré en utilisant l'outil [Asciidoctor](http://asciidoctor.org/) qui supporte les mêmes extensions que GitLab (pour les équations par exemple). -Un résumé de la syntaxe supportée est accessible [ici](http://asciidoctor.org/docs/asciidoc-syntax-quick-reference/). - -Vous pouvez éditer les différents fichiers en utilisant *votre éditeur de texte favori*. -Si vous n'en avez pas, vous pouvez, par exemple utiliser: - -- [**Visual Studio Code**](https://code.visualstudio.com/) avec l'extension [AsciiDoc](https://marketplace.visualstudio.com/items?itemName=asciidoctor.asciidoctor-vscode) qui ajoute coloration syntaxique et rendu en temps réel. -- Ou bien sûr votre éditeur de text préféré **Sublim Text**, **Vim**, **Emacs**,… -- Une extension pour navigateur Web est aussi disponible pour visualiser le résultat ([**ici**](https://github.com/asciidoctor/asciidoctor-browser-extension)). +Ceci est votre dépôt pour le projet PACT. + +Vous **DEVEZ** modifier ce fichier (`README.md`) et créer tous les +répertoires et fichiers dont vous aurez besoin pour votre projet. + +# Important, le rapport d'avancement + +Le répertoire `rapport` contient un squelette pour votre rapporte d'avancement. +Ce répertoire **ne doit pas être renommé** ni le fichier `README.adoc` qu'il contient. +Le fichier `README.adoc` est le point d'entrée du rapport. + +Il est rédigé en utilisant le langage [**AsciiDoc**](http://asciidoc.org/). +La syntaxe est supportée par GitLab qui le formatera correctement dans l'interface Web. + +Le document final sera généré en utilisant l'outil [Asciidoctor](http://asciidoctor.org/) qui supporte les mêmes extensions que GitLab (pour les équations par exemple). +Un résumé de la syntaxe supportée est accessible [ici](http://asciidoctor.org/docs/asciidoc-syntax-quick-reference/). + +Vous pouvez éditer les différents fichiers en utilisant *votre éditeur de texte favori*. +Si vous n'en avez pas, vous pouvez, par exemple utiliser: + +- [**Visual Studio Code**](https://code.visualstudio.com/) avec l'extension [AsciiDoc](https://marketplace.visualstudio.com/items?itemName=asciidoctor.asciidoctor-vscode) qui ajoute coloration syntaxique et rendu en temps réel. +- Ou bien sûr votre éditeur de text préféré **Sublim Text**, **Vim**, **Emacs**,… +- Une extension pour navigateur Web est aussi disponible pour visualiser le résultat ([**ici**](https://github.com/asciidoctor/asciidoctor-browser-extension)). diff --git a/code/client/borne/assets/js/main.js b/code/client/borne/assets/js/main.js new file mode 100644 index 0000000..3570d6c --- /dev/null +++ b/code/client/borne/assets/js/main.js @@ -0,0 +1,52 @@ +let canvas = document.getElementById('camera'); +let video = document.getElementById('video'); + +const width = 320; // We will scale the photo width to this +let height = 0; // This will be computed based on the input stream +let streaming = false; + +function startup() { + video = document.getElementById("video"); + canvas = document.getElementById("canvas"); + + navigator.mediaDevices + .getUserMedia({ video: true, audio: false }) + .then((stream) => { + video.srcObject = stream; + video.play(); + }) + .catch((err) => { + console.error(`An error occurred: ${err}`); + }); + + video.addEventListener( + "canplay", + (ev) => { + if (!streaming) { + height = video.videoHeight / (video.videoWidth / width); + + // Firefox currently has a bug where the height can't be read from + // the video, so we will make assumptions if this happens. + + if (isNaN(height)) { + height = width / (4 / 3); + } + + video.setAttribute("width", width); + video.setAttribute("height", height); + canvas.setAttribute("width", width); + canvas.setAttribute("height", height); + streaming = true; + drawVideoOnCanvas(); + } + }, + false + ); +} + +window.addEventListener("load", startup, false); + +const drawVideoOnCanvas = () => { + canvas.getContext("2d").drawImage(video, 0, 0, width, height); + requestAnimationFrame(drawVideoOnCanvas); +} \ No newline at end of file diff --git a/code/client/borne/index.html b/code/client/borne/index.html new file mode 100644 index 0000000..8883aa3 --- /dev/null +++ b/code/client/borne/index.html @@ -0,0 +1,13 @@ + + + + + + + Téléreview + + + + + + \ No newline at end of file diff --git a/code/server/README.md b/code/server/README.md index 4caba7a..132dd36 100644 --- a/code/server/README.md +++ b/code/server/README.md @@ -1,31 +1,31 @@ -# Installation -* Pour faire fonctinoner le serveur sur vos machines il y a 3 choses a faire -1. Installer node js : https://nodejs.org/en/download/ -2. Ouvrir un terminal et aller dans ce dossier (code/server) et tapper `npm install` pour installer les pacakges nécessaires -3. copier le fichier `.env_template` et le nommer `.env` et remplir les variables (cela est fait pour le pas mettre les mots de passes sur le gitlab, faites attention de ne jamais commit le fichier .env !!) -4. pour lancer le serveur faire `node index.js` - -# Utilisation -## Avis laissés sur la borne (hors réseaux sociaux) -### Routes GET : -- `/borne/get_last_reviews?limit=LIM` : renvoie les LIM derniers avis sur la borne -- `/borne/get_review?id=ID` : renvoie les infos sur l'avis d'in ID -- `/borne/get_criteres` : renvoie les criteres de notations valide pour les notes autres -- `/borne/notes_autres?critere=CRIT&limit=LIM` : renvoie les LIM dernières notes sur le critère CRIT -- `/borne/notes_autres?id=ID&limit=LIM` : renvoie toutes les notes spécifiques liées à l'avis ID - -### Routes POST -- `/add_review` : Ajoute une review et un auteur, paramètres POST : - * [OBLIGATOIRE] `note` : note principale de la review entre 0 et 10 compris - * [OBLIGATOIRE] `source` : nom de la source de l'avis, doit être `borne` ou `website` pour resp la borne et le site - * `auteur_age` : age de l'auteur - * `auteur_sexe` : sexe de l'auteur (valeurs valide 'f', 'h', 'a') - * `commentaire` : Commentaire laissé avec l'avis - * `notes autres` : sous la forme - ```json - { - "critere1": 8, - "critere2": 2, - "critere3": 0 - } - ``` +# Installation +* Pour faire fonctinoner le serveur sur vos machines il y a 3 choses a faire +1. Installer node js : https://nodejs.org/en/download/ +2. Ouvrir un terminal et aller dans ce dossier (code/server) et tapper `npm install` pour installer les pacakges nécessaires +3. copier le fichier `.env_template` et le nommer `.env` et remplir les variables (cela est fait pour le pas mettre les mots de passes sur le gitlab, faites attention de ne jamais commit le fichier .env !!) +4. pour lancer le serveur faire `node index.js` + +# Utilisation +## Avis laissés sur la borne (hors réseaux sociaux) +### Routes GET : +- `/borne/get_last_reviews?limit=LIM` : renvoie les LIM derniers avis sur la borne +- `/borne/get_review?id=ID` : renvoie les infos sur l'avis d'in ID +- `/borne/get_criteres` : renvoie les criteres de notations valide pour les notes autres +- `/borne/notes_autres?critere=CRIT&limit=LIM` : renvoie les LIM dernières notes sur le critère CRIT +- `/borne/notes_autres?id=ID&limit=LIM` : renvoie toutes les notes spécifiques liées à l'avis ID + +### Routes POST +- `/add_review` : Ajoute une review et un auteur, paramètres POST : + * [OBLIGATOIRE] `note` : note principale de la review entre 0 et 10 compris + * [OBLIGATOIRE] `source` : nom de la source de l'avis, doit être `borne` ou `website` pour resp la borne et le site + * `auteur_age` : age de l'auteur + * `auteur_sexe` : sexe de l'auteur (valeurs valide 'f', 'h', 'a') + * `commentaire` : Commentaire laissé avec l'avis + * `notes autres` : sous la forme + ```json + { + "critere1": 8, + "critere2": 2, + "critere3": 0 + } + ``` diff --git a/code/server/borne/get_handler.js b/code/server/borne/get_handler.js index 72f7ca3..8f59ced 100644 --- a/code/server/borne/get_handler.js +++ b/code/server/borne/get_handler.js @@ -1,200 +1,200 @@ -import conn from '../database.js'; - -/** - * Renvoie les derniers avis laissés sur la borne trié par ordre chronologque décroissant - * @param {Number} limit Nombre d'avis a afficher - * @returns Une liste d'objets de la forme {id: id de l'avis, date: date de l'avis, note_principale: note sur 10, commentaire: avis textuel, nom_source, sexe_auteur, age_auteur} - */ -const getLastReviews = (limit=10) => { - return new Promise((resolve, reject) => { - let sql = `SELECT borne_avis.id,date,note_principale,commentaire,sources.nom as nom_source, borne_auteurs.sexe as sexe_auteur, borne_auteurs.age as age_auteur - FROM borne_avis - JOIN sources ON sources.id = source_id - JOIN borne_auteurs ON borne_auteurs.id = id_auteur - ORDER BY borne_avis.id DESC LIMIT ?`; - conn.query(sql, [limit], (err, res) => { - if(err) { - reject(err); - }else { - resolve(res) - } - }) - }) -} - -/** - * Renvoie les informations sur un avis avec un ID spécifique - * @param {Number} id Id de la review - * @returns Un objet de la forme des objets dans la table borne_avis ayant l'id id s'il existe, renvoie une erreur sinon - */ -const getReviewFromId = (id) => { - return new Promise((resolve, reject) => { - let sql = `SELECT * FROM borne_avis WHERE id = ? LIMIT 1`; - conn.query(sql, [id], (err, res) => { - if(err) { - reject(err); - }else { - if(res.length != 1) { - reject(new Error("Avis avec cet ID non trouvé")) - }else { - resolve(res[0]) - } - if(res.length != 1) { - reject(new Error("Avis avec cet ID non trouvé")) - }else { - resolve(res[0]) - } - } - }) - }) -} - -/** - * Renvoie tout les critères de notation valides - * @returns Une liste d'objets de la forme {id,nom} - */ -const getCriteres = () => { - return new Promise((resolve, reject) => { - let sql = `SELECT * FROM borne_criteres`; - conn.query(sql, [limit], (err, res) => { - if(err) { - reject(err); - }else { - resolve(res) - } - }) - }) -} - -/** - * Renvoie les "limit" notes les plus récentes laissées pour un critère spécifié - * @param {String} critere Nom de critère - * @param {Number} limit Nombre max de note a afficher - * @returns une liste d'objets de la forme {id,date,critere,note,avis_id:id de l'avis lié a cette note} - */ -const getNotesAutresFromCritere = (critere,limit=10) => { - return new Promise((resolve, reject) => { - let sql = `SELECT borne_notes_autre.id as id,date,borne_criteres.nom as critere, note, avis_id - FROM borne_notes_autre - JOIN borne_criteres ON borne_criteres.id = critere_id - WHERE borne_criteres.nom = ? - ORDER BY borne_notes_autre.id DESC LIMIT ? ;`; - conn.query(sql, [critere,limit], (err, res) => { - if(err) { - reject(err); - }else { - resolve(res) - } - }) - }) -} - -/** - * Renvoie toutes les notes sur des critères spécifiques laissée pour un avis spécifique - * @param {Number} reviewId Id de l'avis - * @returns une liste d'objets de la forme {id,critere:nom du critère, note:note sur 10} - */ -const getNotesAutresFromReview = (reviewId) => { - return new Promise((resolve, reject) => { - let sql = `SELECT borne_notes_autre.id as id,borne_criteres.nom as critere, note - FROM borne_notes_autre - JOIN borne_criteres on borne_criteres.id = critere_id - WHERE avis_id = ? - ORDER BY borne_notes_autre.id DESC`; - conn.query(sql, [reviewId], (err, res) => { - if(err) { - reject(err); - }else { - resolve(res) - } - }) - }) -} - -/** - * Renvoie les dernières statistiques - * @param {String} interval Interval de temps de la statistique, valeurs possibles : "jour","mois","semaine","annee" - * @param {Number} limit Nombre max de stats a renvoyer - * @returns Une liste d'objet ou chaque objet correspond a une stat sur une periode donnée (par ex une stat hebdo datée du 07/01 correspond a une stat sur la semaine du 01/01 au 07/01), ces objets sont de la forme - */ -const getStats = (interval, limit=10) => { - return new Promise((resolve, reject) => { - if(!["jour","mois","semaine","annee"].includes(interval)) { - reject(new Error("Invalid time interval")); - return; - } - let sql = `SELECT * FROM stats_general_${interval} ORDER BY id DESC LIMIT ?;`; - conn.query(sql, [limit], (err, res) => { - if(err) { - reject(err); - }else { - resolve(res) - } - }) - }) -} - -/* -Ces fonction sont des handlers pour les routes express, elles sont appelées par les routes et renvoient les données au format JSON -*/ -export const handleGetLastReviews = (req, res) => { - getLastReviews(req.query.limit) - .then((reviews) => { - res.send(reviews); - }) - .catch((err) => { - res.status(500).send("Error: " + err.message); - }); -} - -export const handleGetReview = (req, res) => { - getReviewFromId(req.query.id) - .then((review) => { - res.send(review); - }) - .catch((err) => { - res.status(500).send("Error: " + err.message); - }); -} - -export const handleGetCriteres = (req, res) => { - getCriteres() - .then((criteres) => { - res.send(criteres); - }) - .catch((err) => { - res.status(500).send("Error: " + err.message); - }); -} - -export const handleGetNotesAutres = (req, res) => { - if(req.query.critere) { - getNotesAutresFromCritere(req.query.critere, req.query.limit) - .then((notes) => { - res.send(notes); - }) - .catch((err) => { - res.status(500).send("Error: " + err.message); - }); - }else if(req.query.id) { - getNotesAutresFromReview(req.query.id) - .then((notes) => { - res.send(notes); - }) - .catch((err) => { - res.status(500).send("Error: " + err.message); - }); - }else { - res.status(500).send("Error: no critere or id specified"); - } -} - -export const handleGetStats = (req, res) => { - getStats(req.query.interval, req.query.limit) - .then((stats) => { - res.send(stats); - }) - .catch((err) => { - res.status(500).send("Error: " + err.message); - }); +import conn from '../database.js'; + +/** + * Renvoie les derniers avis laissés sur la borne trié par ordre chronologque décroissant + * @param {Number} limit Nombre d'avis a afficher + * @returns Une liste d'objets de la forme {id: id de l'avis, date: date de l'avis, note_principale: note sur 10, commentaire: avis textuel, nom_source, sexe_auteur, age_auteur} + */ +const getLastReviews = (limit=10) => { + return new Promise((resolve, reject) => { + let sql = `SELECT borne_avis.id,date,note_principale,commentaire,sources.nom as nom_source, borne_auteurs.sexe as sexe_auteur, borne_auteurs.age as age_auteur + FROM borne_avis + JOIN sources ON sources.id = source_id + JOIN borne_auteurs ON borne_auteurs.id = id_auteur + ORDER BY borne_avis.id DESC LIMIT ?`; + conn.query(sql, [limit], (err, res) => { + if(err) { + reject(err); + }else { + resolve(res) + } + }) + }) +} + +/** + * Renvoie les informations sur un avis avec un ID spécifique + * @param {Number} id Id de la review + * @returns Un objet de la forme des objets dans la table borne_avis ayant l'id id s'il existe, renvoie une erreur sinon + */ +const getReviewFromId = (id) => { + return new Promise((resolve, reject) => { + let sql = `SELECT * FROM borne_avis WHERE id = ? LIMIT 1`; + conn.query(sql, [id], (err, res) => { + if(err) { + reject(err); + }else { + if(res.length != 1) { + reject(new Error("Avis avec cet ID non trouvé")) + }else { + resolve(res[0]) + } + if(res.length != 1) { + reject(new Error("Avis avec cet ID non trouvé")) + }else { + resolve(res[0]) + } + } + }) + }) +} + +/** + * Renvoie tout les critères de notation valides + * @returns Une liste d'objets de la forme {id,nom} + */ +const getCriteres = () => { + return new Promise((resolve, reject) => { + let sql = `SELECT * FROM borne_criteres`; + conn.query(sql, [limit], (err, res) => { + if(err) { + reject(err); + }else { + resolve(res) + } + }) + }) +} + +/** + * Renvoie les "limit" notes les plus récentes laissées pour un critère spécifié + * @param {String} critere Nom de critère + * @param {Number} limit Nombre max de note a afficher + * @returns une liste d'objets de la forme {id,date,critere,note,avis_id:id de l'avis lié a cette note} + */ +const getNotesAutresFromCritere = (critere,limit=10) => { + return new Promise((resolve, reject) => { + let sql = `SELECT borne_notes_autre.id as id,date,borne_criteres.nom as critere, note, avis_id + FROM borne_notes_autre + JOIN borne_criteres ON borne_criteres.id = critere_id + WHERE borne_criteres.nom = ? + ORDER BY borne_notes_autre.id DESC LIMIT ? ;`; + conn.query(sql, [critere,limit], (err, res) => { + if(err) { + reject(err); + }else { + resolve(res) + } + }) + }) +} + +/** + * Renvoie toutes les notes sur des critères spécifiques laissée pour un avis spécifique + * @param {Number} reviewId Id de l'avis + * @returns une liste d'objets de la forme {id,critere:nom du critère, note:note sur 10} + */ +const getNotesAutresFromReview = (reviewId) => { + return new Promise((resolve, reject) => { + let sql = `SELECT borne_notes_autre.id as id,borne_criteres.nom as critere, note + FROM borne_notes_autre + JOIN borne_criteres on borne_criteres.id = critere_id + WHERE avis_id = ? + ORDER BY borne_notes_autre.id DESC`; + conn.query(sql, [reviewId], (err, res) => { + if(err) { + reject(err); + }else { + resolve(res) + } + }) + }) +} + +/** + * Renvoie les dernières statistiques + * @param {String} interval Interval de temps de la statistique, valeurs possibles : "jour","mois","semaine","annee" + * @param {Number} limit Nombre max de stats a renvoyer + * @returns Une liste d'objet ou chaque objet correspond a une stat sur une periode donnée (par ex une stat hebdo datée du 07/01 correspond a une stat sur la semaine du 01/01 au 07/01), ces objets sont de la forme + */ +const getStats = (interval, limit=10) => { + return new Promise((resolve, reject) => { + if(!["jour","mois","semaine","annee"].includes(interval)) { + reject(new Error("Invalid time interval")); + return; + } + let sql = `SELECT * FROM stats_general_${interval} ORDER BY id DESC LIMIT ?;`; + conn.query(sql, [limit], (err, res) => { + if(err) { + reject(err); + }else { + resolve(res) + } + }) + }) +} + +/* +Ces fonction sont des handlers pour les routes express, elles sont appelées par les routes et renvoient les données au format JSON +*/ +export const handleGetLastReviews = (req, res) => { + getLastReviews(req.query.limit) + .then((reviews) => { + res.send(reviews); + }) + .catch((err) => { + res.status(500).send("Error: " + err.message); + }); +} + +export const handleGetReview = (req, res) => { + getReviewFromId(req.query.id) + .then((review) => { + res.send(review); + }) + .catch((err) => { + res.status(500).send("Error: " + err.message); + }); +} + +export const handleGetCriteres = (req, res) => { + getCriteres() + .then((criteres) => { + res.send(criteres); + }) + .catch((err) => { + res.status(500).send("Error: " + err.message); + }); +} + +export const handleGetNotesAutres = (req, res) => { + if(req.query.critere) { + getNotesAutresFromCritere(req.query.critere, req.query.limit) + .then((notes) => { + res.send(notes); + }) + .catch((err) => { + res.status(500).send("Error: " + err.message); + }); + }else if(req.query.id) { + getNotesAutresFromReview(req.query.id) + .then((notes) => { + res.send(notes); + }) + .catch((err) => { + res.status(500).send("Error: " + err.message); + }); + }else { + res.status(500).send("Error: no critere or id specified"); + } +} + +export const handleGetStats = (req, res) => { + getStats(req.query.interval, req.query.limit) + .then((stats) => { + res.send(stats); + }) + .catch((err) => { + res.status(500).send("Error: " + err.message); + }); } \ No newline at end of file diff --git a/code/server/borne/post_handler.js b/code/server/borne/post_handler.js index 5469b51..545d745 100644 --- a/code/server/borne/post_handler.js +++ b/code/server/borne/post_handler.js @@ -1,84 +1,84 @@ -import { Auteur, Review } from './structures.js'; -import conn from '../database.js'; -import {getSourceId} from '../utils.js'; - - -/** - * Ajoute un nouvel auteur de commentaire a la BDD - * @param {Auteur} author L'auteur a ajouter - * @returns une Promise qui renvoie l'id de l'utilisateur - */ -const addAuteur = (author) => { - return new Promise((resolve,reject) => { - const sql = "INSERT INTO borne_auteurs (age, sexe) VALUES (?);" - conn.query(sql, [[author.age, author.sexe]], (err, res) => { - if(err) { - reject(err) - }else { - resolve(res.insertId); - } - }) - }) -} - -//Ajoute une note sur un critère spécifique dans la BDD -const addSpecificRating = (reviewId, label, value) => { - return new Promise((resolve, reject) => { - const sql = "INSERT INTO borne_notes_autre(critere_id, avis_id, note) VALUES ((SELECT id FROM borne_criteres WHERE borne_criteres.nom = ?), ?, ?)" - conn.query(sql, [label,reviewId, value], (err, res) => { - if(err) { - reject(err); - }else { - resolve(res.insertId); - } - }) - }) -} - - -/** - * Ajoute un avis a la base de donnée - * @param {Review} review la review a ajouter - * @param {Number} authorId l'ID de l'auteur de l'avis dans la BDD - * @param {Number} sourceId l'ID de la source de l'avis dans la BDD - * @returns une Promise qui renvoie l'id de l'avis - */ -const addReview = (review, authorId, sourceId) => { - return new Promise((resolve, reject) => { - const sql = "INSERT INTO borne_avis (id_auteur, note_principale, commentaire, source_id) VALUES (?);" - conn.query(sql, [[authorId, review.note, review.commentaire, sourceId]], (err, res) => { - if(err) { - reject(err) - }else { - resolve(res.insertId); - } - }) - }) -} - -/** - * Traite une requête POST qui contient les valeurs nécessaires pour ajouter un nouvel avis dans la BDD - * Essaie d'ajouter l'avis et l'auteur dans la BDD, sinon renvoie l'erreur avec un code 500 - * @param {*} req requete - * @param {*} res reponse - */ -export const addReviewFromRequest = async (req,res) => { - try { - let notes_autre = {} - try{ - notes_autre = JSON.parse(req.body.notes_autre); - }catch(err){}; - - const author = new Auteur(req.body.auteur_age,req.body.auteur_sexe); - const review = new Review(author, req.body.note, req.body.source, req.body.commentaire, notes_autre) - let authorId = await addAuteur(author); - let sourceId = await getSourceId(review.source); - let reviewId = await addReview(review, authorId, sourceId ); - for(let label in review.notesAutre) { - await addSpecificRating(reviewId, label, review.notesAutre[label]); - } - res.send("success") - }catch(err) { - res.status(500).send("Error : " + err.message) - } +import { Auteur, Review } from './structures.js'; +import conn from '../database.js'; +import {getSourceId} from '../utils.js'; + + +/** + * Ajoute un nouvel auteur de commentaire a la BDD + * @param {Auteur} author L'auteur a ajouter + * @returns une Promise qui renvoie l'id de l'utilisateur + */ +const addAuteur = (author) => { + return new Promise((resolve,reject) => { + const sql = "INSERT INTO borne_auteurs (age, sexe) VALUES (?);" + conn.query(sql, [[author.age, author.sexe]], (err, res) => { + if(err) { + reject(err) + }else { + resolve(res.insertId); + } + }) + }) +} + +//Ajoute une note sur un critère spécifique dans la BDD +const addSpecificRating = (reviewId, label, value) => { + return new Promise((resolve, reject) => { + const sql = "INSERT INTO borne_notes_autre(critere_id, avis_id, note) VALUES ((SELECT id FROM borne_criteres WHERE borne_criteres.nom = ?), ?, ?)" + conn.query(sql, [label,reviewId, value], (err, res) => { + if(err) { + reject(err); + }else { + resolve(res.insertId); + } + }) + }) +} + + +/** + * Ajoute un avis a la base de donnée + * @param {Review} review la review a ajouter + * @param {Number} authorId l'ID de l'auteur de l'avis dans la BDD + * @param {Number} sourceId l'ID de la source de l'avis dans la BDD + * @returns une Promise qui renvoie l'id de l'avis + */ +const addReview = (review, authorId, sourceId) => { + return new Promise((resolve, reject) => { + const sql = "INSERT INTO borne_avis (id_auteur, note_principale, commentaire, source_id) VALUES (?);" + conn.query(sql, [[authorId, review.note, review.commentaire, sourceId]], (err, res) => { + if(err) { + reject(err) + }else { + resolve(res.insertId); + } + }) + }) +} + +/** + * Traite une requête POST qui contient les valeurs nécessaires pour ajouter un nouvel avis dans la BDD + * Essaie d'ajouter l'avis et l'auteur dans la BDD, sinon renvoie l'erreur avec un code 500 + * @param {*} req requete + * @param {*} res reponse + */ +export const addReviewFromRequest = async (req,res) => { + try { + let notes_autre = {} + try{ + notes_autre = JSON.parse(req.body.notes_autre); + }catch(err){}; + + const author = new Auteur(req.body.auteur_age,req.body.auteur_sexe); + const review = new Review(author, req.body.note, req.body.source, req.body.commentaire, notes_autre) + let authorId = await addAuteur(author); + let sourceId = await getSourceId(review.source); + let reviewId = await addReview(review, authorId, sourceId ); + for(let label in review.notesAutre) { + await addSpecificRating(reviewId, label, review.notesAutre[label]); + } + res.send("success") + }catch(err) { + res.status(500).send("Error : " + err.message) + } } \ No newline at end of file diff --git a/code/server/borne/structures.js b/code/server/borne/structures.js index c8f7984..39af1b9 100644 --- a/code/server/borne/structures.js +++ b/code/server/borne/structures.js @@ -1,52 +1,52 @@ -//Liste des valeurs valides pour le sexe d'un utilisateur -const validSexes = ["h","f","a"]; - -//Classe pour représenter un avis laissé sur la borne que ce soit par l'interface web ou par un geste -export class Review { - /** - * Constructeur - * @param {Auteur} auteur L'auteur de l'avis - * @param {Number} note La note principale entre 0 et 10 compris - * @param {String} source La source de l'avis, doit être une entrée dans la table soruces de la bdd - * @param {String} commentaire Le commentaire lié a l'avis - * @param {Object} notesAutre Les notes secondaires laissées, sous la forme d'un object ou les clés sont les labels de chaque notes et les valeurs sont des notes entre 0 et 10 compris - */ - constructor(auteur, note, source, commentaire=null, notesAutre={}) { - this.auteur = auteur; - this.note = note; - this.source = source; - this.commentaire = commentaire; - this.notesAutre = notesAutre; - - //On vérifie si toutes les données sont correctes - if(note < 0 || note > 10) { - throw new Error("Note principale invalide"); - } - for(let nom in notesAutre) { - if(notesAutre[nom] < 0 || notesAutre[nom] > 10) { - throw new Error("Note " + notesAutre[nom] +"/10 invalide"); - } - } - } -} - -//Classe qui représente l'auteur d'un avis -export class Auteur { - /** - * Constructeur - * @param {Number} age L'age de l'auteur - * @param {String} sexe Le sexe de la personne (doit être dans l'array validSexes défini au début de ce fichier) - */ - constructor(age=null, sexe=null) { - this.age = age; - this.sexe = sexe; - - //Verification des données - if(sexe != undefined && !validSexes.includes(sexe) ) { - throw new Error("Sexe invalide"); - } - if(age != undefined && age <= 0) { - throw new Error("Age invalide"); - } - } +//Liste des valeurs valides pour le sexe d'un utilisateur +const validSexes = ["h","f","a"]; + +//Classe pour représenter un avis laissé sur la borne que ce soit par l'interface web ou par un geste +export class Review { + /** + * Constructeur + * @param {Auteur} auteur L'auteur de l'avis + * @param {Number} note La note principale entre 0 et 10 compris + * @param {String} source La source de l'avis, doit être une entrée dans la table soruces de la bdd + * @param {String} commentaire Le commentaire lié a l'avis + * @param {Object} notesAutre Les notes secondaires laissées, sous la forme d'un object ou les clés sont les labels de chaque notes et les valeurs sont des notes entre 0 et 10 compris + */ + constructor(auteur, note, source, commentaire=null, notesAutre={}) { + this.auteur = auteur; + this.note = note; + this.source = source; + this.commentaire = commentaire; + this.notesAutre = notesAutre; + + //On vérifie si toutes les données sont correctes + if(note < 0 || note > 10) { + throw new Error("Note principale invalide"); + } + for(let nom in notesAutre) { + if(notesAutre[nom] < 0 || notesAutre[nom] > 10) { + throw new Error("Note " + notesAutre[nom] +"/10 invalide"); + } + } + } +} + +//Classe qui représente l'auteur d'un avis +export class Auteur { + /** + * Constructeur + * @param {Number} age L'age de l'auteur + * @param {String} sexe Le sexe de la personne (doit être dans l'array validSexes défini au début de ce fichier) + */ + constructor(age=null, sexe=null) { + this.age = age; + this.sexe = sexe; + + //Verification des données + if(sexe != undefined && !validSexes.includes(sexe) ) { + throw new Error("Sexe invalide"); + } + if(age != undefined && age <= 0) { + throw new Error("Age invalide"); + } + } } \ No newline at end of file diff --git a/code/server/database.js b/code/server/database.js index 22d7b94..bce2607 100644 --- a/code/server/database.js +++ b/code/server/database.js @@ -1,15 +1,15 @@ -import * as dotenv from 'dotenv' -import mysql from 'mysql2'; -dotenv.config(); - -const conn = mysql.createConnection({ - host: process.env.DB_HOST, - user: process.env.DB_USER, - password: process.env.DB_PASSWORD, - database: process.env.DB_NAME, - multipleStatements: true, -}); - -conn.connect(); - +import * as dotenv from 'dotenv' +import mysql from 'mysql2'; +dotenv.config(); + +const conn = mysql.createConnection({ + host: process.env.DB_HOST, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.DB_NAME, + multipleStatements: true, +}); + +conn.connect(); + export default conn; \ No newline at end of file diff --git a/code/server/exemple_utilisation.py b/code/server/exemple_utilisation.py index 41ef34f..e81d3f5 100644 --- a/code/server/exemple_utilisation.py +++ b/code/server/exemple_utilisation.py @@ -1,29 +1,29 @@ -import requests -#Exemple ajout d'un commentaire depuis la borne (site ou geste) -avis = { - "note": 8, - "source": "borne", - #Optionel - "auteur_age": 20, - "notes_autre": '{"proprete":8,"calme":10}', - "auteur_sexe": 'f', - "commentaire": "Commentaire" -} - -# res = requests.post("http://localhost:8080/add_review", data=avis) -# print(res.text) - -#Exemple ajout d'un commentaire trouvé sur les réseaux sociaux -avis = { - "auteur_nom": "michel", - "source": "instagram", - "note": 8, - "date": "2022-12-24", - #Optionel - "commentaire": "J'ai beaucoup aimé !", - "lien": "https://instagram.com/si_insta_avait_des_liens_vers_des_commentaires_faudrait_le_mettre_ici", - "auteur_lien": "https://instagram.com/michel", -} - -res = requests.post("http://localhost:8080/add_social_review", data=avis) +import requests +#Exemple ajout d'un commentaire depuis la borne (site ou geste) +avis = { + "note": 8, + "source": "borne", + #Optionel + "auteur_age": 20, + "notes_autre": '{"proprete":8,"calme":10}', + "auteur_sexe": 'f', + "commentaire": "Commentaire" +} + +# res = requests.post("http://localhost:8080/add_review", data=avis) +# print(res.text) + +#Exemple ajout d'un commentaire trouvé sur les réseaux sociaux +avis = { + "auteur_nom": "michel", + "source": "instagram", + "note": 8, + "date": "2022-12-24", + #Optionel + "commentaire": "J'ai beaucoup aimé !", + "lien": "https://instagram.com/si_insta_avait_des_liens_vers_des_commentaires_faudrait_le_mettre_ici", + "auteur_lien": "https://instagram.com/michel", +} + +res = requests.post("http://localhost:8080/add_social_review", data=avis) print(res.text) \ No newline at end of file diff --git a/code/server/exemple_utilisation_Quentin-Laptop_Jan-04-193148-2023_Conflict.py b/code/server/exemple_utilisation_Quentin-Laptop_Jan-04-193148-2023_Conflict.py new file mode 100644 index 0000000..41ef34f --- /dev/null +++ b/code/server/exemple_utilisation_Quentin-Laptop_Jan-04-193148-2023_Conflict.py @@ -0,0 +1,29 @@ +import requests +#Exemple ajout d'un commentaire depuis la borne (site ou geste) +avis = { + "note": 8, + "source": "borne", + #Optionel + "auteur_age": 20, + "notes_autre": '{"proprete":8,"calme":10}', + "auteur_sexe": 'f', + "commentaire": "Commentaire" +} + +# res = requests.post("http://localhost:8080/add_review", data=avis) +# print(res.text) + +#Exemple ajout d'un commentaire trouvé sur les réseaux sociaux +avis = { + "auteur_nom": "michel", + "source": "instagram", + "note": 8, + "date": "2022-12-24", + #Optionel + "commentaire": "J'ai beaucoup aimé !", + "lien": "https://instagram.com/si_insta_avait_des_liens_vers_des_commentaires_faudrait_le_mettre_ici", + "auteur_lien": "https://instagram.com/michel", +} + +res = requests.post("http://localhost:8080/add_social_review", data=avis) +print(res.text) \ No newline at end of file diff --git a/code/server/index.js b/code/server/index.js index 7c423de..3fd05a8 100644 --- a/code/server/index.js +++ b/code/server/index.js @@ -1,28 +1,28 @@ -import * as dotenv from 'dotenv'; -import express from 'express'; -import bodyParser from 'body-parser'; -import { addReviewFromRequest } from './borne/post_handler.js'; -import { addSocialReviewFromRequest } from './reseaux_sociaux/post_handler.js'; -import { startCronJobs } from './stats/update_stats.js'; -import * as borneHandler from './borne/get_handler.js'; - -const app = express(); - -app.use(bodyParser.urlencoded({extended:true})) -dotenv.config() -app.post('/add_review', (req,res) => addReviewFromRequest(req,res)); -app.post('/add_social_review', (req,res) => addSocialReviewFromRequest(req,res)); - -app.get('/borne/get_last_reviews', borneHandler.handleGetLastReviews); -app.get('/borne/get_review', borneHandler.handleGetReview); -app.get('/borne/get_criteres', borneHandler.handleGetCriteres); -app.get('/borne/notes_autres', borneHandler.handleGetNotesAutres); -app.get('/borne/get_stats', borneHandler.handleGetStats); - - -startCronJobs(); - -app.listen(process.env.PORT, () => { - console.log("Server démaré sur le port " + process.env.PORT) -}) - +import * as dotenv from 'dotenv'; +import express from 'express'; +import bodyParser from 'body-parser'; +import { addReviewFromRequest } from './borne/post_handler.js'; +import { addSocialReviewFromRequest } from './reseaux_sociaux/post_handler.js'; +import { startCronJobs } from './stats/update_stats.js'; +import * as borneHandler from './borne/get_handler.js'; + +const app = express(); + +app.use(bodyParser.urlencoded({extended:true})) +dotenv.config() +app.post('/add_review', (req,res) => addReviewFromRequest(req,res)); +app.post('/add_social_review', (req,res) => addSocialReviewFromRequest(req,res)); + +app.get('/borne/get_last_reviews', borneHandler.handleGetLastReviews); +app.get('/borne/get_review', borneHandler.handleGetReview); +app.get('/borne/get_criteres', borneHandler.handleGetCriteres); +app.get('/borne/notes_autres', borneHandler.handleGetNotesAutres); +app.get('/borne/get_stats', borneHandler.handleGetStats); + + +startCronJobs(); + +app.listen(process.env.PORT, () => { + console.log("Server démaré sur le port " + process.env.PORT) +}) + diff --git a/code/server/package-lock.json b/code/server/package-lock.json index 0a56818..5cb9427 100644 --- a/code/server/package-lock.json +++ b/code/server/package-lock.json @@ -1,1278 +1,1278 @@ -{ - "name": "server", - "version": "1.0.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "server", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "body-parser": "^1.20.1", - "cron": "^2.1.0", - "dotenv": "^16.0.3", - "express": "^4.18.2", - "mysql2": "^2.3.3" - } - }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" - }, - "node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.1", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" - }, - "node_modules/cron": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cron/-/cron-2.1.0.tgz", - "integrity": "sha512-Hq7u3P8y7UWYvsZbSKHHJDVG0VO9O7tp2qljxzTScelcTODBfCme8AIhnZsFwmQ9NchZ3hr2uNr+s3DSms7q6w==", - "dependencies": { - "luxon": "^1.23.x" - } - }, - "node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/denque": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", - "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/dotenv": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", - "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", - "engines": { - "node": ">=12" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" - }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", - "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.1", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.11.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "node_modules/generate-function": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", - "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", - "dependencies": { - "is-property": "^1.0.2" - } - }, - "node_modules/get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-property": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==" - }, - "node_modules/long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/luxon": { - "version": "1.28.0", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.0.tgz", - "integrity": "sha512-TfTiyvZhwBYM/7QdAVDh+7dBTBA29v4ik0Ce9zda3Mnf8on1S5KJI8P2jKFZ8+5C0jhmr0KwJEO/Wdpm0VeWJQ==", - "engines": { - "node": "*" - } - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" - }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/mysql2": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-2.3.3.tgz", - "integrity": "sha512-wxJUev6LgMSgACDkb/InIFxDprRa6T95+VEoR+xPvtngtccNH2dGjEB/fVZ8yg1gWv1510c9CvXuJHi5zUm0ZA==", - "dependencies": { - "denque": "^2.0.1", - "generate-function": "^2.3.1", - "iconv-lite": "^0.6.3", - "long": "^4.0.0", - "lru-cache": "^6.0.0", - "named-placeholders": "^1.1.2", - "seq-queue": "^0.0.5", - "sqlstring": "^2.3.2" - }, - "engines": { - "node": ">= 8.0" - } - }, - "node_modules/mysql2/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/named-placeholders": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.2.tgz", - "integrity": "sha512-wiFWqxoLL3PGVReSZpjLVxyJ1bRqe+KKJVbr4hGs1KWfTZTQyezHFBbuKj9hsizHyGV2ne7EMjHdxEGAybD5SA==", - "dependencies": { - "lru-cache": "^4.1.3" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/named-placeholders/node_modules/lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dependencies": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "node_modules/named-placeholders/node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==" - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==" - }, - "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/seq-queue": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", - "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" - }, - "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/sqlstring": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", - "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - } - }, - "dependencies": { - "accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "requires": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - } - }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" - }, - "body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", - "requires": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.1", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - } - }, - "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "requires": { - "safe-buffer": "5.2.1" - } - }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" - }, - "cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" - }, - "cron": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cron/-/cron-2.1.0.tgz", - "integrity": "sha512-Hq7u3P8y7UWYvsZbSKHHJDVG0VO9O7tp2qljxzTScelcTODBfCme8AIhnZsFwmQ9NchZ3hr2uNr+s3DSms7q6w==", - "requires": { - "luxon": "^1.23.x" - } - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "denque": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", - "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==" - }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - }, - "destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" - }, - "dotenv": { - "version": "16.0.3", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", - "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==" - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" - }, - "express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", - "requires": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.1", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.11.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - } - }, - "finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - } - }, - "forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "generate-function": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", - "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", - "requires": { - "is-property": "^1.0.2" - } - }, - "get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" - }, - "http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "requires": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" - }, - "is-property": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==" - }, - "long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } - }, - "luxon": { - "version": "1.28.0", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.0.tgz", - "integrity": "sha512-TfTiyvZhwBYM/7QdAVDh+7dBTBA29v4ik0Ce9zda3Mnf8on1S5KJI8P2jKFZ8+5C0jhmr0KwJEO/Wdpm0VeWJQ==" - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "requires": { - "mime-db": "1.52.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "mysql2": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-2.3.3.tgz", - "integrity": "sha512-wxJUev6LgMSgACDkb/InIFxDprRa6T95+VEoR+xPvtngtccNH2dGjEB/fVZ8yg1gWv1510c9CvXuJHi5zUm0ZA==", - "requires": { - "denque": "^2.0.1", - "generate-function": "^2.3.1", - "iconv-lite": "^0.6.3", - "long": "^4.0.0", - "lru-cache": "^6.0.0", - "named-placeholders": "^1.1.2", - "seq-queue": "^0.0.5", - "sqlstring": "^2.3.2" - }, - "dependencies": { - "iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - } - } - }, - "named-placeholders": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.2.tgz", - "integrity": "sha512-wiFWqxoLL3PGVReSZpjLVxyJ1bRqe+KKJVbr4hGs1KWfTZTQyezHFBbuKj9hsizHyGV2ne7EMjHdxEGAybD5SA==", - "requires": { - "lru-cache": "^4.1.3" - }, - "dependencies": { - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==" - } - } - }, - "negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" - }, - "object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" - }, - "on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "requires": { - "ee-first": "1.1.1" - } - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" - }, - "proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "requires": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - } - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==" - }, - "qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "requires": { - "side-channel": "^1.0.4" - } - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" - }, - "raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "requires": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "requires": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "dependencies": { - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - } - } - }, - "seq-queue": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", - "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" - }, - "serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - } - }, - "setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "sqlstring": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", - "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==" - }, - "statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" - }, - "toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" - }, - "type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - } - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - } - } -} +{ + "name": "server", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "server", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "body-parser": "^1.20.1", + "cron": "^2.1.0", + "dotenv": "^16.0.3", + "express": "^4.18.2", + "mysql2": "^2.3.3" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/cron": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cron/-/cron-2.1.0.tgz", + "integrity": "sha512-Hq7u3P8y7UWYvsZbSKHHJDVG0VO9O7tp2qljxzTScelcTODBfCme8AIhnZsFwmQ9NchZ3hr2uNr+s3DSms7q6w==", + "dependencies": { + "luxon": "^1.23.x" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/dotenv": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", + "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "dependencies": { + "is-property": "^1.0.2" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==" + }, + "node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/luxon": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.0.tgz", + "integrity": "sha512-TfTiyvZhwBYM/7QdAVDh+7dBTBA29v4ik0Ce9zda3Mnf8on1S5KJI8P2jKFZ8+5C0jhmr0KwJEO/Wdpm0VeWJQ==", + "engines": { + "node": "*" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/mysql2": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-2.3.3.tgz", + "integrity": "sha512-wxJUev6LgMSgACDkb/InIFxDprRa6T95+VEoR+xPvtngtccNH2dGjEB/fVZ8yg1gWv1510c9CvXuJHi5zUm0ZA==", + "dependencies": { + "denque": "^2.0.1", + "generate-function": "^2.3.1", + "iconv-lite": "^0.6.3", + "long": "^4.0.0", + "lru-cache": "^6.0.0", + "named-placeholders": "^1.1.2", + "seq-queue": "^0.0.5", + "sqlstring": "^2.3.2" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/mysql2/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/named-placeholders": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.2.tgz", + "integrity": "sha512-wiFWqxoLL3PGVReSZpjLVxyJ1bRqe+KKJVbr4hGs1KWfTZTQyezHFBbuKj9hsizHyGV2ne7EMjHdxEGAybD5SA==", + "dependencies": { + "lru-cache": "^4.1.3" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/named-placeholders/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/named-placeholders/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==" + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/seq-queue": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", + "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sqlstring": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", + "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + }, + "dependencies": { + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + } + }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "requires": { + "safe-buffer": "5.2.1" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "cron": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cron/-/cron-2.1.0.tgz", + "integrity": "sha512-Hq7u3P8y7UWYvsZbSKHHJDVG0VO9O7tp2qljxzTScelcTODBfCme8AIhnZsFwmQ9NchZ3hr2uNr+s3DSms7q6w==", + "requires": { + "luxon": "^1.23.x" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==" + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" + }, + "dotenv": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", + "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" + }, + "express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "requires": { + "is-property": "^1.0.2" + } + }, + "get-intrinsic": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==" + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "luxon": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.0.tgz", + "integrity": "sha512-TfTiyvZhwBYM/7QdAVDh+7dBTBA29v4ik0Ce9zda3Mnf8on1S5KJI8P2jKFZ8+5C0jhmr0KwJEO/Wdpm0VeWJQ==" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "mysql2": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-2.3.3.tgz", + "integrity": "sha512-wxJUev6LgMSgACDkb/InIFxDprRa6T95+VEoR+xPvtngtccNH2dGjEB/fVZ8yg1gWv1510c9CvXuJHi5zUm0ZA==", + "requires": { + "denque": "^2.0.1", + "generate-function": "^2.3.1", + "iconv-lite": "^0.6.3", + "long": "^4.0.0", + "lru-cache": "^6.0.0", + "named-placeholders": "^1.1.2", + "seq-queue": "^0.0.5", + "sqlstring": "^2.3.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "named-placeholders": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.2.tgz", + "integrity": "sha512-wiFWqxoLL3PGVReSZpjLVxyJ1bRqe+KKJVbr4hGs1KWfTZTQyezHFBbuKj9hsizHyGV2ne7EMjHdxEGAybD5SA==", + "requires": { + "lru-cache": "^4.1.3" + }, + "dependencies": { + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==" + } + } + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + }, + "object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + } + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==" + }, + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "requires": { + "side-channel": "^1.0.4" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "seq-queue": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", + "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" + }, + "serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + } + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "sqlstring": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", + "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==" + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } +} diff --git a/code/server/package.json b/code/server/package.json index e83cbbd..708948d 100644 --- a/code/server/package.json +++ b/code/server/package.json @@ -1,19 +1,19 @@ -{ - "name": "server", - "version": "1.0.0", - "description": "", - "main": "index.js", - "type": "module", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "Telereview", - "license": "ISC", - "dependencies": { - "body-parser": "^1.20.1", - "cron": "^2.1.0", - "dotenv": "^16.0.3", - "express": "^4.18.2", - "mysql2": "^2.3.3" - } -} +{ + "name": "server", + "version": "1.0.0", + "description": "", + "main": "index.js", + "type": "module", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "Telereview", + "license": "ISC", + "dependencies": { + "body-parser": "^1.20.1", + "cron": "^2.1.0", + "dotenv": "^16.0.3", + "express": "^4.18.2", + "mysql2": "^2.3.3" + } +} diff --git a/code/server/reseaux_sociaux/post_handler.js b/code/server/reseaux_sociaux/post_handler.js index 79fb441..9b27aee 100644 --- a/code/server/reseaux_sociaux/post_handler.js +++ b/code/server/reseaux_sociaux/post_handler.js @@ -1,85 +1,85 @@ -import { ReseauxAuteur, ReseauxReview } from './structures.js'; -import conn from '../database.js'; -import {getSourceId} from '../utils.js'; - -/**Récupérer l'id d'un auteur particulier dans la base de donnée s'il existe - * @param {ReseauxAuteur} author L'auteur dont on veut l'id* - * @returns Une Promise qui donne l'id de l'utilisateur ou null si il n'existe pas - */ -const getAuteurId = (author) => { - return new Promise(async (resolve,reject) => { - const sql = "SELECT id FROM reseaux_sociaux_auteurs WHERE nom_utilisateur = ? AND source_id = ? AND lien = ?;" - let sourceId = await getSourceId(author.source); - let query = conn.query(sql, [author.nom, sourceId, author.lien], (err, res) => { - if(err) { - reject(new Error(err.message)) - }else { - if(res.length > 0) { - resolve(res[0].id); - }else { - resolve(null); - } - } - }) - }) -} - - -/** - * ajoute un auteur de commentaire sur les réseaux sociaux a la bdd - * @param {ReseauxAuteur} author - * @returns Une Promise qui donne l'id de l'utilisateur - */ -const addAuteur = (author, sourceId) => { - return new Promise((resolve,reject) => { - const sql = "INSERT INTO reseaux_sociaux_auteurs (nom_utilisateur, source_id, lien) VALUES (?);" - conn.query(sql, [[author.nom,sourceId, author.lien]], (err, res) => { - if(err) { - reject(new Error(err.message)) - }else { - resolve(res.insertId); - } - }) - }) -} - -/** - * Ajoute un avis dans la BDD - * @param {ReseauxReview} review L'avis a ajouter - * @param {Number} authorId ID de l'auteur dans la bdd - * @param {Number} sourceId ID Du réseau social source dans la bdd - * @returns une Promise qui renvoie l'ID de la review - */ -const addReview = (review, authorId, sourceId) => { - return new Promise((resolve, reject) => { - const sql = "INSERT INTO reseaux_sociaux_avis (source_id, note, commentaire, auteur_id, lien_source, date) VALUES (?);" - conn.query(sql, [[sourceId, review.note, review.commentaire, authorId, review.lien, review.date]], (err, res) => { - if(err) { - reject(new Error(err.message)) - }else { - resolve(res.insertId); - } - }) - }) -} - -/** - * Traite une requête POST pour ajouter un avis récupéré sur les réseaux sociaux - * @param {*} req - * @param {*} res - */ -export const addSocialReviewFromRequest = async (req,res) => { - try { - const author = new ReseauxAuteur(req.body.auteur_nom, req.body.source, req.body.auteur_lien); - const review = new ReseauxReview(author, req.body.source, req.body.date, req.body.note, req.body.commentaire, req.body.lien) - let sourceId = await getSourceId(review.source); - let authorId = await getAuteurId(author); - if(authorId == null) { - authorId = await addAuteur(author, sourceId); - } - await addReview(review, authorId, sourceId); - res.send("success") - }catch(err) { - res.status(500).send("Error : " + err.message) - } +import { ReseauxAuteur, ReseauxReview } from './structures.js'; +import conn from '../database.js'; +import {getSourceId} from '../utils.js'; + +/**Récupérer l'id d'un auteur particulier dans la base de donnée s'il existe + * @param {ReseauxAuteur} author L'auteur dont on veut l'id* + * @returns Une Promise qui donne l'id de l'utilisateur ou null si il n'existe pas + */ +const getAuteurId = (author) => { + return new Promise(async (resolve,reject) => { + const sql = "SELECT id FROM reseaux_sociaux_auteurs WHERE nom_utilisateur = ? AND source_id = ? AND lien = ?;" + let sourceId = await getSourceId(author.source); + let query = conn.query(sql, [author.nom, sourceId, author.lien], (err, res) => { + if(err) { + reject(new Error(err.message)) + }else { + if(res.length > 0) { + resolve(res[0].id); + }else { + resolve(null); + } + } + }) + }) +} + + +/** + * ajoute un auteur de commentaire sur les réseaux sociaux a la bdd + * @param {ReseauxAuteur} author + * @returns Une Promise qui donne l'id de l'utilisateur + */ +const addAuteur = (author, sourceId) => { + return new Promise((resolve,reject) => { + const sql = "INSERT INTO reseaux_sociaux_auteurs (nom_utilisateur, source_id, lien) VALUES (?);" + conn.query(sql, [[author.nom,sourceId, author.lien]], (err, res) => { + if(err) { + reject(new Error(err.message)) + }else { + resolve(res.insertId); + } + }) + }) +} + +/** + * Ajoute un avis dans la BDD + * @param {ReseauxReview} review L'avis a ajouter + * @param {Number} authorId ID de l'auteur dans la bdd + * @param {Number} sourceId ID Du réseau social source dans la bdd + * @returns une Promise qui renvoie l'ID de la review + */ +const addReview = (review, authorId, sourceId) => { + return new Promise((resolve, reject) => { + const sql = "INSERT INTO reseaux_sociaux_avis (source_id, note, commentaire, auteur_id, lien_source, date) VALUES (?);" + conn.query(sql, [[sourceId, review.note, review.commentaire, authorId, review.lien, review.date]], (err, res) => { + if(err) { + reject(new Error(err.message)) + }else { + resolve(res.insertId); + } + }) + }) +} + +/** + * Traite une requête POST pour ajouter un avis récupéré sur les réseaux sociaux + * @param {*} req + * @param {*} res + */ +export const addSocialReviewFromRequest = async (req,res) => { + try { + const author = new ReseauxAuteur(req.body.auteur_nom, req.body.source, req.body.auteur_lien); + const review = new ReseauxReview(author, req.body.source, req.body.date, req.body.note, req.body.commentaire, req.body.lien) + let sourceId = await getSourceId(review.source); + let authorId = await getAuteurId(author); + if(authorId == null) { + authorId = await addAuteur(author, sourceId); + } + await addReview(review, authorId, sourceId); + res.send("success") + }catch(err) { + res.status(500).send("Error : " + err.message) + } } \ No newline at end of file diff --git a/code/server/reseaux_sociaux/structures.js b/code/server/reseaux_sociaux/structures.js index b2761ac..63273ef 100644 --- a/code/server/reseaux_sociaux/structures.js +++ b/code/server/reseaux_sociaux/structures.js @@ -1,39 +1,39 @@ -import { Review } from "../borne/structures.js"; - -export class ReseauxReview extends Review{ - /** - * - * @param {ReseauxAuteur} auteur Auteur de l'avis - * @param {String} source La source de l'avis - * @param {String} date La date de l'avis au format YYYY-MM-DD - * @param {Number} note Nombre entre 0 et 10, la note attribuée - * @param {String} commentaire Le commentaire laissé par l'utilisateur - * @param {String} lien Lien vers le commentaire - */ - constructor(auteur, source, date, note=null, commentaire=null, lien=null,) { - super(auteur,note,source,commentaire); - this.lien = lien; - this.date = date; - if((typeof lien !== "string" && lien != null)) { - throw new Error("Lien invalide"); - } - } -} - -export class ReseauxAuteur { - /** - * - * @param {String} nom Nom de l'utilisateur - * @param {String} source Réseau social de provenance de l'utilisateur - * @param {String} lien Lien vers le profil de l'utilisateur - */ - constructor(nom, source, lien=null) { - this.nom = nom; - this.source = source; - this.lien = lien; - - if((typeof this.nom !== "string") || (typeof this.source !== "string")){ - throw new Error("Auteur invalide"); - } - } +import { Review } from "../borne/structures.js"; + +export class ReseauxReview extends Review{ + /** + * + * @param {ReseauxAuteur} auteur Auteur de l'avis + * @param {String} source La source de l'avis + * @param {String} date La date de l'avis au format YYYY-MM-DD + * @param {Number} note Nombre entre 0 et 10, la note attribuée + * @param {String} commentaire Le commentaire laissé par l'utilisateur + * @param {String} lien Lien vers le commentaire + */ + constructor(auteur, source, date, note=null, commentaire=null, lien=null,) { + super(auteur,note,source,commentaire); + this.lien = lien; + this.date = date; + if((typeof lien !== "string" && lien != null)) { + throw new Error("Lien invalide"); + } + } +} + +export class ReseauxAuteur { + /** + * + * @param {String} nom Nom de l'utilisateur + * @param {String} source Réseau social de provenance de l'utilisateur + * @param {String} lien Lien vers le profil de l'utilisateur + */ + constructor(nom, source, lien=null) { + this.nom = nom; + this.source = source; + this.lien = lien; + + if((typeof this.nom !== "string") || (typeof this.source !== "string")){ + throw new Error("Auteur invalide"); + } + } } \ No newline at end of file diff --git a/code/server/stats/update_request.sql b/code/server/stats/update_request.sql index 0dcd64e..bc728b5 100644 --- a/code/server/stats/update_request.sql +++ b/code/server/stats/update_request.sql @@ -1,50 +1,50 @@ -/* -Dans cette requête il faut replacer DAY_COUNT_DELAY par le nombre de jours sur lequel calculer les stats, STATS_GENERAL_TABLE_NAME par la table dans laquelle mettre les stats globales (par exemple stats_general_jour si les valeurs sont calculées sur 1 jour) et pareil pour STATS_AUTRES_TABLE_NAME -C'est un peu bizzare comme technique mais j'ai pas trouvé de meilleur solution -*/ -SET @date_limite = DATE_ADD(NOW(), INTERVAL -DAY_COUNT_DELAY DAY); - -/* -On récupère les notes notes moyennes sur la periode, en séparant global, borne et site -*/ - -SELECT @moyenne_globale:=AVG(note_principale) - FROM borne_avis - WHERE borne_avis.date > @date_limite; - -SELECT @moyenne_borne:=AVG(note_principale) - FROM borne_avis - JOIN sources ON sources.id = borne_avis.source_id - WHERE borne_avis.date > @date_limite AND sources.nom = "borne"; - -SELECT @moyenne_site:=AVG(note_principale) - FROM borne_avis - JOIN sources ON sources.id = borne_avis.source_id - WHERE borne_avis.date > @date_limite AND sources.nom = "website"; - -/* -On récupère la distribution de sexes -*/ - -SELECT @stats_f:=COUNT(*) FROM borne_avis - JOIN borne_auteurs ON borne_avis.id_auteur = borne_auteurs.id - WHERE sexe='f' AND date > @date_limite; -SELECT @stats_h:=COUNT(*) FROM borne_avis - JOIN borne_auteurs ON borne_avis.id_auteur = borne_auteurs.id - WHERE sexe='h' AND date > @date_limite; -SELECT @stats_a:=COUNT(*) FROM borne_avis - JOIN borne_auteurs ON borne_avis.id_auteur = borne_auteurs.id - WHERE sexe='a' AND date > @date_limite; - -SET @dist_sexe = CONCAT(@stats_f,",",@stats_h,",",@stats_a); - -INSERT INTO STATS_GENERAL_TABLE_NAME (moyenne_globale, moyenne_borne, moyenne_site, dist_sexe) VALUES (@moyenne_globale, @moyenne_borne, @moyenne_site, @dist_sexe); - -INSERT INTO STATS_AUTRES_TABLE_NAME (critere_id, note) - SELECT critere_id, AVG(note) as moyenne FROM borne_notes_autre - WHERE borne_notes_autre.date > @date_limite - GROUP BY critere_id - -/* -TODO : Calcul de la distribution d'age +/* +Dans cette requête il faut replacer DAY_COUNT_DELAY par le nombre de jours sur lequel calculer les stats, STATS_GENERAL_TABLE_NAME par la table dans laquelle mettre les stats globales (par exemple stats_general_jour si les valeurs sont calculées sur 1 jour) et pareil pour STATS_AUTRES_TABLE_NAME +C'est un peu bizzare comme technique mais j'ai pas trouvé de meilleur solution +*/ +SET @date_limite = DATE_ADD(NOW(), INTERVAL -DAY_COUNT_DELAY DAY); + +/* +On récupère les notes notes moyennes sur la periode, en séparant global, borne et site +*/ + +SELECT @moyenne_globale:=AVG(note_principale) + FROM borne_avis + WHERE borne_avis.date > @date_limite; + +SELECT @moyenne_borne:=AVG(note_principale) + FROM borne_avis + JOIN sources ON sources.id = borne_avis.source_id + WHERE borne_avis.date > @date_limite AND sources.nom = "borne"; + +SELECT @moyenne_site:=AVG(note_principale) + FROM borne_avis + JOIN sources ON sources.id = borne_avis.source_id + WHERE borne_avis.date > @date_limite AND sources.nom = "website"; + +/* +On récupère la distribution de sexes +*/ + +SELECT @stats_f:=COUNT(*) FROM borne_avis + JOIN borne_auteurs ON borne_avis.id_auteur = borne_auteurs.id + WHERE sexe='f' AND date > @date_limite; +SELECT @stats_h:=COUNT(*) FROM borne_avis + JOIN borne_auteurs ON borne_avis.id_auteur = borne_auteurs.id + WHERE sexe='h' AND date > @date_limite; +SELECT @stats_a:=COUNT(*) FROM borne_avis + JOIN borne_auteurs ON borne_avis.id_auteur = borne_auteurs.id + WHERE sexe='a' AND date > @date_limite; + +SET @dist_sexe = CONCAT(@stats_f,",",@stats_h,",",@stats_a); + +INSERT INTO STATS_GENERAL_TABLE_NAME (moyenne_globale, moyenne_borne, moyenne_site, dist_sexe) VALUES (@moyenne_globale, @moyenne_borne, @moyenne_site, @dist_sexe); + +INSERT INTO STATS_AUTRES_TABLE_NAME (critere_id, note) + SELECT critere_id, AVG(note) as moyenne FROM borne_notes_autre + WHERE borne_notes_autre.date > @date_limite + GROUP BY critere_id + +/* +TODO : Calcul de la distribution d'age */ \ No newline at end of file diff --git a/code/server/stats/update_stats.js b/code/server/stats/update_stats.js index 2f3c24e..6bcc30a 100644 --- a/code/server/stats/update_stats.js +++ b/code/server/stats/update_stats.js @@ -1,69 +1,69 @@ -import conn from '../database.js'; -import fs from "fs"; -import { CronJob } from 'cron'; - -/** - * Calcules les stats sur une periode donnée et les stocke dans la BDD - * @param {Number} timePeriod Periode de temps sur laquelle calculer les données. Par exemple 7 si on veut faire les stats des 7 derniers jours - * @param {String} generalTableName Nom de la table dans laquelle mettre les statistiques générales (tables valides : stats_general_jour stats_general_semaine stats_general_mois stats_general_annee) - * @param {*} otherTableName Nom de la table dans laquelle mettre les statistiques spécifiques (tables valides : stats_autres_jour stats_autres_autres_autres_mois stats_general_annee) - * @returns Une Promise qui résout si la requête a fonctionnée - */ -const computeStats = async (timePeriod, generalTableName, otherTableName) => { - return new Promise((resolve, reject) => { - let sql = fs.readFileSync("stats/update_request.sql").toString(); - sql = sql - .replace(new RegExp("DAY_COUNT_DELAY",'g'), timePeriod.toString()) - .replace(new RegExp("STATS_GENERAL_TABLE_NAME", 'g'), generalTableName) - .replace(new RegExp('STATS_AUTRES_TABLE_NAME', 'g'), otherTableName) - conn.query(sql, (err, res) => { - if(err) { - reject(err) - }else { - resolve(); - } - }); - }) -} -export const startCronJobs = () => { - //Update les stats journalières tout les jours a minuit - new CronJob( - '0 0 * * * * ', - () => { - computeStats(1,"stats_general_jour","stats_autres_jour"); - }, - null, - true - ) - - //update les stats de la semaine tous les lundis a minuit - new CronJob( - '0 0 * * 1 * ', - () => { - computeStats(7,"stats_general_semaine","stats_autres_jour"); - }, - null, - true - ) - - //update les stats mensuelles les 1er du mois a minuit - new CronJob( - '0 0 1 * * * ', - () => { - computeStats(30, "stats_general_mois","stats_autres_mois"); - }, - null, - true - ) - - //update les stats annuelles les premire de l'an a minuit - new CronJob( - '0 0 1 1 * * ', - () => { - computeStats(365, "stats_general_annee","stats_autres_annee"); - }, - null, - true - ) - console.log("All cronjobs initiated") +import conn from '../database.js'; +import fs from "fs"; +import { CronJob } from 'cron'; + +/** + * Calcules les stats sur une periode donnée et les stocke dans la BDD + * @param {Number} timePeriod Periode de temps sur laquelle calculer les données. Par exemple 7 si on veut faire les stats des 7 derniers jours + * @param {String} generalTableName Nom de la table dans laquelle mettre les statistiques générales (tables valides : stats_general_jour stats_general_semaine stats_general_mois stats_general_annee) + * @param {*} otherTableName Nom de la table dans laquelle mettre les statistiques spécifiques (tables valides : stats_autres_jour stats_autres_autres_autres_mois stats_general_annee) + * @returns Une Promise qui résout si la requête a fonctionnée + */ +const computeStats = async (timePeriod, generalTableName, otherTableName) => { + return new Promise((resolve, reject) => { + let sql = fs.readFileSync("stats/update_request.sql").toString(); + sql = sql + .replace(new RegExp("DAY_COUNT_DELAY",'g'), timePeriod.toString()) + .replace(new RegExp("STATS_GENERAL_TABLE_NAME", 'g'), generalTableName) + .replace(new RegExp('STATS_AUTRES_TABLE_NAME', 'g'), otherTableName) + conn.query(sql, (err, res) => { + if(err) { + reject(err) + }else { + resolve(); + } + }); + }) +} +export const startCronJobs = () => { + //Update les stats journalières tout les jours a minuit + new CronJob( + '0 0 * * * * ', + () => { + computeStats(1,"stats_general_jour","stats_autres_jour"); + }, + null, + true + ) + + //update les stats de la semaine tous les lundis a minuit + new CronJob( + '0 0 * * 1 * ', + () => { + computeStats(7,"stats_general_semaine","stats_autres_jour"); + }, + null, + true + ) + + //update les stats mensuelles les 1er du mois a minuit + new CronJob( + '0 0 1 * * * ', + () => { + computeStats(30, "stats_general_mois","stats_autres_mois"); + }, + null, + true + ) + + //update les stats annuelles les premire de l'an a minuit + new CronJob( + '0 0 1 1 * * ', + () => { + computeStats(365, "stats_general_annee","stats_autres_annee"); + }, + null, + true + ) + console.log("All cronjobs initiated") } \ No newline at end of file diff --git a/code/server/utils.js b/code/server/utils.js index 2a1930d..1c3f494 100644 --- a/code/server/utils.js +++ b/code/server/utils.js @@ -1,19 +1,19 @@ -import conn from './database.js'; - -/** - * Renvoie l'ID dans la BDD d'une source de donnée - * @param {String} source la source dont on veut récup l'id - * @returns une promise qui renvoie l'id de la source - */ -export const getSourceId = (source) => { - return new Promise((resolve, reject) => { - const sql = "SELECT id from sources WHERE nom = ?"; - conn.query(sql, [source], (err, res) => { - if(res.length == 0) { - reject(new Error("Invalid source")) - }else { - resolve(res[0].id); - } - }) - }) -} +import conn from './database.js'; + +/** + * Renvoie l'ID dans la BDD d'une source de donnée + * @param {String} source la source dont on veut récup l'id + * @returns une promise qui renvoie l'id de la source + */ +export const getSourceId = (source) => { + return new Promise((resolve, reject) => { + const sql = "SELECT id from sources WHERE nom = ?"; + conn.query(sql, [source], (err, res) => { + if(res.length == 0) { + reject(new Error("Invalid source")) + }else { + resolve(res[0].id); + } + }) + }) +} diff --git a/code/sql/telereview.sql b/code/sql/telereview.sql index 5524e98..962bcfe 100644 --- a/code/sql/telereview.sql +++ b/code/sql/telereview.sql @@ -1,444 +1,444 @@ --- phpMyAdmin SQL Dump --- version 4.9.5deb2 --- https://www.phpmyadmin.net/ --- --- Host: localhost:3306 --- Generation Time: Dec 26, 2022 at 10:31 AM --- Server version: 8.0.31-0ubuntu0.20.04.1 --- PHP Version: 7.4.3 - -SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; -SET AUTOCOMMIT = 0; -START TRANSACTION; -SET time_zone = "+00:00"; - - -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; -/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; -/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; -/*!40101 SET NAMES utf8mb4 */; - --- --- Database: `telereview` --- -CREATE DATABASE IF NOT EXISTS `telereview` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci; -USE `telereview`; - --- -------------------------------------------------------- - --- --- Table structure for table `borne_auteurs` --- - -CREATE TABLE `borne_auteurs` ( - `id` int NOT NULL, - `sexe` tinytext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci, - `age` tinyint DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; - --- -------------------------------------------------------- - --- --- Table structure for table `borne_avis` --- - -CREATE TABLE `borne_avis` ( - `id` int NOT NULL, - `id_auteur` int NOT NULL, - `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `note_principale` tinyint NOT NULL, - `commentaire` text NOT NULL, - `source_id` int NOT NULL -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; - --- -------------------------------------------------------- - --- --- Table structure for table `borne_criteres` --- - -CREATE TABLE `borne_criteres` ( - `id` int NOT NULL, - `nom` text NOT NULL -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; - --- --- Dumping data for table `borne_criteres` --- - -INSERT INTO `borne_criteres` (`id`, `nom`) VALUES -(1, 'proprete'), -(2, 'calme'), -(3, 'attente'); - --- -------------------------------------------------------- - --- --- Table structure for table `borne_notes_autre` --- - -CREATE TABLE `borne_notes_autre` ( - `id` int NOT NULL, - `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `critere_id` int NOT NULL, - `avis_id` int NOT NULL, - `note` int NOT NULL COMMENT 'Note sur 10' -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; - --- -------------------------------------------------------- - --- --- Table structure for table `reseaux_sociaux_auteurs` --- - -CREATE TABLE `reseaux_sociaux_auteurs` ( - `id` int NOT NULL, - `nom_utilisateur` text NOT NULL, - `source_id` int NOT NULL, - `lien` text NOT NULL -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; - --- -------------------------------------------------------- - --- --- Table structure for table `reseaux_sociaux_avis` --- - -CREATE TABLE `reseaux_sociaux_avis` ( - `id` int NOT NULL, - `date` date NOT NULL, - `source_id` int NOT NULL, - `note` tinyint DEFAULT NULL, - `commentaire` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci, - `auteur_id` int NOT NULL, - `lien_source` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; - --- -------------------------------------------------------- - --- --- Table structure for table `sources` --- - -CREATE TABLE `sources` ( - `id` int NOT NULL, - `nom` text NOT NULL -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; - --- --- Dumping data for table `sources` --- - -INSERT INTO `sources` (`id`, `nom`) VALUES -(1, 'website'), -(2, 'borne'), -(3, 'instagram'); - --- -------------------------------------------------------- - --- --- Table structure for table `stats_autres_annee` --- - -CREATE TABLE `stats_autres_annee` ( - `id` int NOT NULL, - `time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `critere_id` int NOT NULL, - `note` float NOT NULL -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; - --- -------------------------------------------------------- - --- --- Table structure for table `stats_autres_jour` --- - -CREATE TABLE `stats_autres_jour` ( - `id` int NOT NULL, - `time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `critere_id` int NOT NULL, - `note` float NOT NULL -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; - --- -------------------------------------------------------- - --- --- Table structure for table `stats_autres_mois` --- - -CREATE TABLE `stats_autres_mois` ( - `id` int NOT NULL, - `time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `critere_id` int NOT NULL, - `note` float NOT NULL -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; - --- -------------------------------------------------------- - --- --- Table structure for table `stats_autres_semaine` --- - -CREATE TABLE `stats_autres_semaine` ( - `id` int NOT NULL, - `time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `critere_id` int NOT NULL, - `note` float NOT NULL -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; - --- -------------------------------------------------------- - --- --- Table structure for table `stats_general_annee` --- - -CREATE TABLE `stats_general_annee` ( - `id` int NOT NULL, - `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `moyenne_globale` float NOT NULL, - `moyenne_site` float NOT NULL, - `moyenne_borne` float NOT NULL, - `dist_age` text NOT NULL COMMENT 'Distribution de l''age des auteurs', - `dist_sexe` text NOT NULL COMMENT 'Distribution du sexe des auteurs' -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; - --- -------------------------------------------------------- - --- --- Table structure for table `stats_general_jour` --- - -CREATE TABLE `stats_general_jour` ( - `id` int NOT NULL, - `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `moyenne_globale` float DEFAULT NULL, - `moyenne_site` float DEFAULT NULL, - `moyenne_borne` float DEFAULT NULL, - `dist_age` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci COMMENT 'Distribution de l''age des auteurs', - `dist_sexe` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci COMMENT 'Distribution du sexe des auteurs' -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; - --- -------------------------------------------------------- - --- --- Table structure for table `stats_general_mois` --- - -CREATE TABLE `stats_general_mois` ( - `id` int NOT NULL, - `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `moyenne_globale` float NOT NULL, - `moyenne_site` float NOT NULL, - `moyenne_borne` float NOT NULL, - `dist_age` text NOT NULL COMMENT 'Distribution de l''age des auteurs', - `dist_sexe` text NOT NULL COMMENT 'Distribution du sexe des auteurs' -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; - --- -------------------------------------------------------- - --- --- Table structure for table `stats_general_semaine` --- - -CREATE TABLE `stats_general_semaine` ( - `id` int NOT NULL, - `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, - `moyenne_globale` float NOT NULL, - `moyenne_site` float NOT NULL, - `moyenne_borne` float NOT NULL, - `dist_age` text NOT NULL COMMENT 'Distribution de l''age des auteurs', - `dist_sexe` text NOT NULL COMMENT 'Distribution du sexe des auteurs' -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; - --- --- Indexes for dumped tables --- - --- --- Indexes for table `borne_auteurs` --- -ALTER TABLE `borne_auteurs` - ADD PRIMARY KEY (`id`); - --- --- Indexes for table `borne_avis` --- -ALTER TABLE `borne_avis` - ADD PRIMARY KEY (`id`); - --- --- Indexes for table `borne_criteres` --- -ALTER TABLE `borne_criteres` - ADD PRIMARY KEY (`id`); - --- --- Indexes for table `borne_notes_autre` --- -ALTER TABLE `borne_notes_autre` - ADD PRIMARY KEY (`id`); - --- --- Indexes for table `reseaux_sociaux_auteurs` --- -ALTER TABLE `reseaux_sociaux_auteurs` - ADD PRIMARY KEY (`id`); - --- --- Indexes for table `reseaux_sociaux_avis` --- -ALTER TABLE `reseaux_sociaux_avis` - ADD PRIMARY KEY (`id`); - --- --- Indexes for table `sources` --- -ALTER TABLE `sources` - ADD PRIMARY KEY (`id`); - --- --- Indexes for table `stats_autres_annee` --- -ALTER TABLE `stats_autres_annee` - ADD PRIMARY KEY (`id`); - --- --- Indexes for table `stats_autres_jour` --- -ALTER TABLE `stats_autres_jour` - ADD PRIMARY KEY (`id`); - --- --- Indexes for table `stats_autres_mois` --- -ALTER TABLE `stats_autres_mois` - ADD PRIMARY KEY (`id`); - --- --- Indexes for table `stats_autres_semaine` --- -ALTER TABLE `stats_autres_semaine` - ADD PRIMARY KEY (`id`); - --- --- Indexes for table `stats_general_annee` --- -ALTER TABLE `stats_general_annee` - ADD PRIMARY KEY (`id`); - --- --- Indexes for table `stats_general_jour` --- -ALTER TABLE `stats_general_jour` - ADD PRIMARY KEY (`id`); - --- --- Indexes for table `stats_general_mois` --- -ALTER TABLE `stats_general_mois` - ADD PRIMARY KEY (`id`); - --- --- Indexes for table `stats_general_semaine` --- -ALTER TABLE `stats_general_semaine` - ADD PRIMARY KEY (`id`); - --- --- AUTO_INCREMENT for dumped tables --- - --- --- AUTO_INCREMENT for table `borne_auteurs` --- -ALTER TABLE `borne_auteurs` - MODIFY `id` int NOT NULL AUTO_INCREMENT; - --- --- AUTO_INCREMENT for table `borne_avis` --- -ALTER TABLE `borne_avis` - MODIFY `id` int NOT NULL AUTO_INCREMENT; - --- --- AUTO_INCREMENT for table `borne_criteres` --- -ALTER TABLE `borne_criteres` - MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4; - --- --- AUTO_INCREMENT for table `borne_notes_autre` --- -ALTER TABLE `borne_notes_autre` - MODIFY `id` int NOT NULL AUTO_INCREMENT; - --- --- AUTO_INCREMENT for table `reseaux_sociaux_auteurs` --- -ALTER TABLE `reseaux_sociaux_auteurs` - MODIFY `id` int NOT NULL AUTO_INCREMENT; - --- --- AUTO_INCREMENT for table `reseaux_sociaux_avis` --- -ALTER TABLE `reseaux_sociaux_avis` - MODIFY `id` int NOT NULL AUTO_INCREMENT; - --- --- AUTO_INCREMENT for table `sources` --- -ALTER TABLE `sources` - MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4; - --- --- AUTO_INCREMENT for table `stats_autres_annee` --- -ALTER TABLE `stats_autres_annee` - MODIFY `id` int NOT NULL AUTO_INCREMENT; - --- --- AUTO_INCREMENT for table `stats_autres_jour` --- -ALTER TABLE `stats_autres_jour` - MODIFY `id` int NOT NULL AUTO_INCREMENT; - --- --- AUTO_INCREMENT for table `stats_autres_mois` --- -ALTER TABLE `stats_autres_mois` - MODIFY `id` int NOT NULL AUTO_INCREMENT; - --- --- AUTO_INCREMENT for table `stats_autres_semaine` --- -ALTER TABLE `stats_autres_semaine` - MODIFY `id` int NOT NULL AUTO_INCREMENT; - --- --- AUTO_INCREMENT for table `stats_general_annee` --- -ALTER TABLE `stats_general_annee` - MODIFY `id` int NOT NULL AUTO_INCREMENT; - --- --- AUTO_INCREMENT for table `stats_general_jour` --- -ALTER TABLE `stats_general_jour` - MODIFY `id` int NOT NULL AUTO_INCREMENT; - --- --- AUTO_INCREMENT for table `stats_general_mois` --- -ALTER TABLE `stats_general_mois` - MODIFY `id` int NOT NULL AUTO_INCREMENT; - --- --- AUTO_INCREMENT for table `stats_general_semaine` --- -ALTER TABLE `stats_general_semaine` - MODIFY `id` int NOT NULL AUTO_INCREMENT; -COMMIT; - -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; -/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +-- phpMyAdmin SQL Dump +-- version 4.9.5deb2 +-- https://www.phpmyadmin.net/ +-- +-- Host: localhost:3306 +-- Generation Time: Dec 26, 2022 at 10:31 AM +-- Server version: 8.0.31-0ubuntu0.20.04.1 +-- PHP Version: 7.4.3 + +SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; +SET AUTOCOMMIT = 0; +START TRANSACTION; +SET time_zone = "+00:00"; + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8mb4 */; + +-- +-- Database: `telereview` +-- +CREATE DATABASE IF NOT EXISTS `telereview` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci; +USE `telereview`; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `borne_auteurs` +-- + +CREATE TABLE `borne_auteurs` ( + `id` int NOT NULL, + `sexe` tinytext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci, + `age` tinyint DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `borne_avis` +-- + +CREATE TABLE `borne_avis` ( + `id` int NOT NULL, + `id_auteur` int NOT NULL, + `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `note_principale` tinyint NOT NULL, + `commentaire` text NOT NULL, + `source_id` int NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `borne_criteres` +-- + +CREATE TABLE `borne_criteres` ( + `id` int NOT NULL, + `nom` text NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- +-- Dumping data for table `borne_criteres` +-- + +INSERT INTO `borne_criteres` (`id`, `nom`) VALUES +(1, 'proprete'), +(2, 'calme'), +(3, 'attente'); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `borne_notes_autre` +-- + +CREATE TABLE `borne_notes_autre` ( + `id` int NOT NULL, + `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `critere_id` int NOT NULL, + `avis_id` int NOT NULL, + `note` int NOT NULL COMMENT 'Note sur 10' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `reseaux_sociaux_auteurs` +-- + +CREATE TABLE `reseaux_sociaux_auteurs` ( + `id` int NOT NULL, + `nom_utilisateur` text NOT NULL, + `source_id` int NOT NULL, + `lien` text NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `reseaux_sociaux_avis` +-- + +CREATE TABLE `reseaux_sociaux_avis` ( + `id` int NOT NULL, + `date` date NOT NULL, + `source_id` int NOT NULL, + `note` tinyint DEFAULT NULL, + `commentaire` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci, + `auteur_id` int NOT NULL, + `lien_source` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `sources` +-- + +CREATE TABLE `sources` ( + `id` int NOT NULL, + `nom` text NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- +-- Dumping data for table `sources` +-- + +INSERT INTO `sources` (`id`, `nom`) VALUES +(1, 'website'), +(2, 'borne'), +(3, 'instagram'); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `stats_autres_annee` +-- + +CREATE TABLE `stats_autres_annee` ( + `id` int NOT NULL, + `time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `critere_id` int NOT NULL, + `note` float NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `stats_autres_jour` +-- + +CREATE TABLE `stats_autres_jour` ( + `id` int NOT NULL, + `time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `critere_id` int NOT NULL, + `note` float NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `stats_autres_mois` +-- + +CREATE TABLE `stats_autres_mois` ( + `id` int NOT NULL, + `time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `critere_id` int NOT NULL, + `note` float NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `stats_autres_semaine` +-- + +CREATE TABLE `stats_autres_semaine` ( + `id` int NOT NULL, + `time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `critere_id` int NOT NULL, + `note` float NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `stats_general_annee` +-- + +CREATE TABLE `stats_general_annee` ( + `id` int NOT NULL, + `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `moyenne_globale` float NOT NULL, + `moyenne_site` float NOT NULL, + `moyenne_borne` float NOT NULL, + `dist_age` text NOT NULL COMMENT 'Distribution de l''age des auteurs', + `dist_sexe` text NOT NULL COMMENT 'Distribution du sexe des auteurs' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `stats_general_jour` +-- + +CREATE TABLE `stats_general_jour` ( + `id` int NOT NULL, + `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `moyenne_globale` float DEFAULT NULL, + `moyenne_site` float DEFAULT NULL, + `moyenne_borne` float DEFAULT NULL, + `dist_age` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci COMMENT 'Distribution de l''age des auteurs', + `dist_sexe` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci COMMENT 'Distribution du sexe des auteurs' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `stats_general_mois` +-- + +CREATE TABLE `stats_general_mois` ( + `id` int NOT NULL, + `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `moyenne_globale` float NOT NULL, + `moyenne_site` float NOT NULL, + `moyenne_borne` float NOT NULL, + `dist_age` text NOT NULL COMMENT 'Distribution de l''age des auteurs', + `dist_sexe` text NOT NULL COMMENT 'Distribution du sexe des auteurs' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `stats_general_semaine` +-- + +CREATE TABLE `stats_general_semaine` ( + `id` int NOT NULL, + `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `moyenne_globale` float NOT NULL, + `moyenne_site` float NOT NULL, + `moyenne_borne` float NOT NULL, + `dist_age` text NOT NULL COMMENT 'Distribution de l''age des auteurs', + `dist_sexe` text NOT NULL COMMENT 'Distribution du sexe des auteurs' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; + +-- +-- Indexes for dumped tables +-- + +-- +-- Indexes for table `borne_auteurs` +-- +ALTER TABLE `borne_auteurs` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `borne_avis` +-- +ALTER TABLE `borne_avis` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `borne_criteres` +-- +ALTER TABLE `borne_criteres` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `borne_notes_autre` +-- +ALTER TABLE `borne_notes_autre` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `reseaux_sociaux_auteurs` +-- +ALTER TABLE `reseaux_sociaux_auteurs` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `reseaux_sociaux_avis` +-- +ALTER TABLE `reseaux_sociaux_avis` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `sources` +-- +ALTER TABLE `sources` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `stats_autres_annee` +-- +ALTER TABLE `stats_autres_annee` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `stats_autres_jour` +-- +ALTER TABLE `stats_autres_jour` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `stats_autres_mois` +-- +ALTER TABLE `stats_autres_mois` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `stats_autres_semaine` +-- +ALTER TABLE `stats_autres_semaine` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `stats_general_annee` +-- +ALTER TABLE `stats_general_annee` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `stats_general_jour` +-- +ALTER TABLE `stats_general_jour` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `stats_general_mois` +-- +ALTER TABLE `stats_general_mois` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `stats_general_semaine` +-- +ALTER TABLE `stats_general_semaine` + ADD PRIMARY KEY (`id`); + +-- +-- AUTO_INCREMENT for dumped tables +-- + +-- +-- AUTO_INCREMENT for table `borne_auteurs` +-- +ALTER TABLE `borne_auteurs` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `borne_avis` +-- +ALTER TABLE `borne_avis` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `borne_criteres` +-- +ALTER TABLE `borne_criteres` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4; + +-- +-- AUTO_INCREMENT for table `borne_notes_autre` +-- +ALTER TABLE `borne_notes_autre` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `reseaux_sociaux_auteurs` +-- +ALTER TABLE `reseaux_sociaux_auteurs` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `reseaux_sociaux_avis` +-- +ALTER TABLE `reseaux_sociaux_avis` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `sources` +-- +ALTER TABLE `sources` + MODIFY `id` int NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4; + +-- +-- AUTO_INCREMENT for table `stats_autres_annee` +-- +ALTER TABLE `stats_autres_annee` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `stats_autres_jour` +-- +ALTER TABLE `stats_autres_jour` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `stats_autres_mois` +-- +ALTER TABLE `stats_autres_mois` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `stats_autres_semaine` +-- +ALTER TABLE `stats_autres_semaine` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `stats_general_annee` +-- +ALTER TABLE `stats_general_annee` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `stats_general_jour` +-- +ALTER TABLE `stats_general_jour` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `stats_general_mois` +-- +ALTER TABLE `stats_general_mois` + MODIFY `id` int NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `stats_general_semaine` +-- +ALTER TABLE `stats_general_semaine` + MODIFY `id` int NOT NULL AUTO_INCREMENT; +COMMIT; + +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; \ No newline at end of file diff --git a/rapport/README.adoc b/rapport/README.adoc index 0632715..0c9723b 100644 --- a/rapport/README.adoc +++ b/rapport/README.adoc @@ -1,127 +1,127 @@ -= Rapport d’avancement: groupe 7.1 -PACT groupe 7.1 (Téléreview) -ifdef::env-gitlab,env-browser[:outfilesuffix: .adoc] -:doctype: book -:stem: latexmath -:source-highlighter: coderay -:toc-title: Table des matières -:toc: macro -:sectnums: -:imagesdir: images - - -// Partie non numérotée -:sectnums!: -== « Téléreview » - -=== Membres du groupe - -* DAS Keshav -* BELHORMA Wissal -* GRIVAUX Yannis -* HAMDAOUI Yasmine -* KOUACHE Lounes -* ROUSSEL Quentin -* SEMPÉRÉ Lucas -* MEZIANE Sara - -=== Tuteur - -* Enzo Tartaglione - -=== Encadrant génie logiciel - -* Marc Hulcelle - -<<< - -== Résumé du sujet choisi en français (PAN1) - -Le but de notre projet c’est de créer une borne interactive qui permet de récupérer les avis d’utilisateurs accompagné d’une interface qui donne au gérant des statistiques sur les avis de ces usagers. -La borne marche par reconnaissance d’image et de voix et comprend donc un micro et une caméra en plus d’un écran. La borne, placée à la sortie d’un lieu accueillant du public, renvoie aux visiteurs une image et les invite à donner leur avis par un signe de la main ou une expression faciale. Ceci permet déjà d’avoir un plus large panel d'émotions et d’avis qu’avec les boutons qu’on pouvait trouver en magasin avant la crise Covid. De plus, elle permet aux utilisateurs de laisser un commentaire construit en parlant à la borne qui ensuite traite le commentaire et en déduit les mots-clés et les sujets importants puis les confronte avec ce qui est dit sur les réseaux sociaux en faisant un scrapping de réseaux sociaux. Toutes ces informations sont traitées puis synthétisées et le gérant peut ainsi avoir accès à un compte-rendu simple et clair. - - -== English Summary (PAN1) - - -The goal of our project is to create an interactive terminal that allows us to retrieve users' opinions accompanied by an interface that gives the manager statistics on what was collected. -The terminal works by image and voice recognition and therefore includes a microphone and a camera in addition to a screen. The terminal, placed at the exit of a place open to the public, invites visitors to give their opinion by a wave of the hand or a facial expression. This already makes it possible to have a wider range of emotions and opinions than with the buttons that could be found in stores before the Covid crisis. In addition, it allows users to leave a comment by talking to the terminal, which then processes the comment and deduces the keywords and important subjects from it, then compares them with what is said on social networks . All this information is processed and then summarized and the manager can thus have access to a simple and clear report. - - -<<< -//// -*Notes concenant le rapport* - -Les différentes pages du document sont rédigées en utilisant le langage -AsciiDoc. Le squelette de rapport contient des exemples avec entre autres: - -* des images, -* des liens, -* des équations. - -La structure du rapport (parties, sections et la relation avec les -différents fichiers) se trouve dans le fichier courant. -**Prenez le temps** de supprimer le texte de remplissage et les sections non -utilisées pour l'instant. Vous pouvez par exemple commenter ces parties non -utilisées pour qu'elles n'apparaissent pas dans le document final. En Asciidoc, -il suffit de les précéder de deux slashs (`//`). -//// - -<<< -toc::[] -<<< - -// On numérote le reste des sections -:sectnums: - -== Étude d’antériorité et justification de la proposition (PAN1) - -include::proposition/proposition.adoc[Description de la proposition] - -include::proposition/etat-de-l-art.adoc[Description de l’état de l’art] - -<<< - -== Scénarios d’usage (PAN1) - -include::scenario/scenario.adoc[Scénarios d’usage] - -<<< - -== Architecture du projet (PAN1) - -include::architecture/schema.adoc[Schéma d’architecture] - -include::architecture/interfaces.adoc[Description des interfaces] - -include::architecture/sequence.adoc[Diagramme de séquence] - -include::architecture/ihm.adoc[Interface utilisateur graphique] - -<<< - -== Organisation du projet (PAN1) - -include::organisation/planification.adoc[Diagramme de planification temporel des tâches] - -//include::organisation/plan-tests.adoc[Plans de test (PAN2+)] - -//// -<<< - -[bibliography] -== Bibliographie (PAN1+) - -include::References.adoc[Bibliographie] - -<<< -== Annexes - -include::annexes/modifications.adoc[Modifications (PAN2+)] - -include::annexes/avancement.adoc[Avancement des modules] - -include::annexes/moduleX.adoc[Avancement module X] - -include::annexes/moduleY.adoc[Avancement module Y] += Rapport d’avancement: groupe 7.1 +PACT groupe 7.1 (Téléreview) +ifdef::env-gitlab,env-browser[:outfilesuffix: .adoc] +:doctype: book +:stem: latexmath +:source-highlighter: coderay +:toc-title: Table des matières +:toc: macro +:sectnums: +:imagesdir: images + + +// Partie non numérotée +:sectnums!: +== « Téléreview » + +=== Membres du groupe + +* DAS Keshav +* BELHORMA Wissal +* GRIVAUX Yannis +* HAMDAOUI Yasmine +* KOUACHE Lounes +* ROUSSEL Quentin +* SEMPÉRÉ Lucas +* MEZIANE Sara + +=== Tuteur + +* Enzo Tartaglione + +=== Encadrant génie logiciel + +* Marc Hulcelle + +<<< + +== Résumé du sujet choisi en français (PAN1) + +Le but de notre projet c’est de créer une borne interactive qui permet de récupérer les avis d’utilisateurs accompagné d’une interface qui donne au gérant des statistiques sur les avis de ces usagers. +La borne marche par reconnaissance d’image et de voix et comprend donc un micro et une caméra en plus d’un écran. La borne, placée à la sortie d’un lieu accueillant du public, renvoie aux visiteurs une image et les invite à donner leur avis par un signe de la main ou une expression faciale. Ceci permet déjà d’avoir un plus large panel d'émotions et d’avis qu’avec les boutons qu’on pouvait trouver en magasin avant la crise Covid. De plus, elle permet aux utilisateurs de laisser un commentaire construit en parlant à la borne qui ensuite traite le commentaire et en déduit les mots-clés et les sujets importants puis les confronte avec ce qui est dit sur les réseaux sociaux en faisant un scrapping de réseaux sociaux. Toutes ces informations sont traitées puis synthétisées et le gérant peut ainsi avoir accès à un compte-rendu simple et clair. + + +== English Summary (PAN1) + + +The goal of our project is to create an interactive terminal that allows us to retrieve users' opinions accompanied by an interface that gives the manager statistics on what was collected. +The terminal works by image and voice recognition and therefore includes a microphone and a camera in addition to a screen. The terminal, placed at the exit of a place open to the public, invites visitors to give their opinion by a wave of the hand or a facial expression. This already makes it possible to have a wider range of emotions and opinions than with the buttons that could be found in stores before the Covid crisis. In addition, it allows users to leave a comment by talking to the terminal, which then processes the comment and deduces the keywords and important subjects from it, then compares them with what is said on social networks . All this information is processed and then summarized and the manager can thus have access to a simple and clear report. + + +<<< +//// +*Notes concenant le rapport* + +Les différentes pages du document sont rédigées en utilisant le langage +AsciiDoc. Le squelette de rapport contient des exemples avec entre autres: + +* des images, +* des liens, +* des équations. + +La structure du rapport (parties, sections et la relation avec les +différents fichiers) se trouve dans le fichier courant. +**Prenez le temps** de supprimer le texte de remplissage et les sections non +utilisées pour l'instant. Vous pouvez par exemple commenter ces parties non +utilisées pour qu'elles n'apparaissent pas dans le document final. En Asciidoc, +il suffit de les précéder de deux slashs (`//`). +//// + +<<< +toc::[] +<<< + +// On numérote le reste des sections +:sectnums: + +== Étude d’antériorité et justification de la proposition (PAN1) + +include::proposition/proposition.adoc[Description de la proposition] + +include::proposition/etat-de-l-art.adoc[Description de l’état de l’art] + +<<< + +== Scénarios d’usage (PAN1) + +include::scenario/scenario.adoc[Scénarios d’usage] + +<<< + +== Architecture du projet (PAN1) + +include::architecture/schema.adoc[Schéma d’architecture] + +include::architecture/interfaces.adoc[Description des interfaces] + +include::architecture/sequence.adoc[Diagramme de séquence] + +include::architecture/ihm.adoc[Interface utilisateur graphique] + +<<< + +== Organisation du projet (PAN1) + +include::organisation/planification.adoc[Diagramme de planification temporel des tâches] + +//include::organisation/plan-tests.adoc[Plans de test (PAN2+)] + +//// +<<< + +[bibliography] +== Bibliographie (PAN1+) + +include::References.adoc[Bibliographie] + +<<< +== Annexes + +include::annexes/modifications.adoc[Modifications (PAN2+)] + +include::annexes/avancement.adoc[Avancement des modules] + +include::annexes/moduleX.adoc[Avancement module X] + +include::annexes/moduleY.adoc[Avancement module Y] //// \ No newline at end of file diff --git a/rapport/References.adoc b/rapport/References.adoc index bcc4c86..8700c98 100644 --- a/rapport/References.adoc +++ b/rapport/References.adoc @@ -1,14 +1,14 @@ - -*_Note : Liste des références exploitées. Une référence complète -donne titre, auteur(s), date, journal, revue, source de publication, -titre de conférence, numéro, pages. Une webographie est aussi -envisageable : titre, auteur, date, page web_* - -* [[RefShannon]]RefShannon : *C. E. SHANNON*, _A Mathematical Theory -of Communication_, Reprinted with corrections from The Bell System -Technical Journal, pages 379–423, 623–656, Vol. 27, 1948, -http://sites.google.com/site/parthochoudhury/aMToC_CShannon.pdf -* [[VitrinePACT]]VitrinePACT : _Vitrine des projets PACT_, -https://pact.wp.mines-telecom.fr/vitrine/ -* [[TOTO]]XXX : *M. S. Otor*, _Best paper ever_, Livre de la jungle, -Volume 2, pages 33-34, 1777 + +*_Note : Liste des références exploitées. Une référence complète +donne titre, auteur(s), date, journal, revue, source de publication, +titre de conférence, numéro, pages. Une webographie est aussi +envisageable : titre, auteur, date, page web_* + +* [[RefShannon]]RefShannon : *C. E. SHANNON*, _A Mathematical Theory +of Communication_, Reprinted with corrections from The Bell System +Technical Journal, pages 379–423, 623–656, Vol. 27, 1948, +http://sites.google.com/site/parthochoudhury/aMToC_CShannon.pdf +* [[VitrinePACT]]VitrinePACT : _Vitrine des projets PACT_, +https://pact.wp.mines-telecom.fr/vitrine/ +* [[TOTO]]XXX : *M. S. Otor*, _Best paper ever_, Livre de la jungle, +Volume 2, pages 33-34, 1777 diff --git a/rapport/annexes/avancement.adoc b/rapport/annexes/avancement.adoc index 05c67b7..80bab2e 100644 --- a/rapport/annexes/avancement.adoc +++ b/rapport/annexes/avancement.adoc @@ -1,6 +1,6 @@ -=== Suivis des modules (Après PAN1) - -Insérez ici votre biblio et vos avancées techniques par module (réunions -experts, pseudo-code d’algorithmes, description détaillée de vos réalisations, etc.). - - +=== Suivis des modules (Après PAN1) + +Insérez ici votre biblio et vos avancées techniques par module (réunions +experts, pseudo-code d’algorithmes, description détaillée de vos réalisations, etc.). + + diff --git a/rapport/annexes/code/test.c b/rapport/annexes/code/test.c index a5094f7..437d24a 100644 --- a/rapport/annexes/code/test.c +++ b/rapport/annexes/code/test.c @@ -1,7 +1,7 @@ -#include - -int main() -{ - puts("hello world!"); - return 0; -} +#include + +int main() +{ + puts("hello world!"); + return 0; +} diff --git a/rapport/annexes/modifications.adoc b/rapport/annexes/modifications.adoc index 9028515..4ab9726 100644 --- a/rapport/annexes/modifications.adoc +++ b/rapport/annexes/modifications.adoc @@ -1,47 +1,47 @@ -=== Modifications (PAN2+) - -==== Modifications de fond - -Tableau des modifications de fond apportées au projet avec validation -des experts et encadrant informatique - -[cols=",,",options="header",] -|==== -| libellé / date | Description brève | Validé par : -| | | -| | | -|==== - -==== Modifications du rapport - -Vous noterez dans cette section les modifications apportées au rapport -depuis le PAN précédent. Si votre planification temporelle a été -modifiée, vous laisserez l’ancienne planification dans cette annexe. - -===== Modifications du rapport au PAN2 - -Fusce ac nisi. Integer volutpat elementum metus. Vivamus luctus -ultricies diam. Curabitur euismod. Vivamus quam. Nunc ante. Nulla mi -nulla, vehicula nec, ultrices a, tincidunt vel, enim. - -Suspendisse potenti. Aenean sed velit. Nunc a urna quis turpis imperdiet -sollicitudin. Mauris aliquam mauris ut tortor. Pellentesque tincidunt -mattis nibh. In id lectus eu. - -===== Modifications du rapport au PAN3 - -Dolor aliquam elit, a commodo nisi felis nec nibh. Nulla facilisi. Etiam -at tortor. Vivamus quis sapien nec magna scelerisque lobortis. - -Curabitur tincidunt viverra justo. Cum sociis natoque penatibus et -magnis dis parturient montes, nascetur ridiculus mus. Sed eros ante, -mattis ullamcorper, posuere quis, tempor vel, metus. Maecenas cursus -cursus lacus. Sed. - -===== Modifications du rapport au PAN4 - -Hac habitasse platea dictumst. Cras quis lacus. Vestibulum rhoncus -congue lacus. Vivamus euismod, felis quis commodo viverra, dolor elit -dictum ante, et mollis eros augue at est. Class aptent taciti sociosqu -ad litora torquent per conubia nostra, per inceptos himenaeos. Nulla -lectus sem, tristique sed, semper in, hendrerit non, sem. Vivamus. +=== Modifications (PAN2+) + +==== Modifications de fond + +Tableau des modifications de fond apportées au projet avec validation +des experts et encadrant informatique + +[cols=",,",options="header",] +|==== +| libellé / date | Description brève | Validé par : +| | | +| | | +|==== + +==== Modifications du rapport + +Vous noterez dans cette section les modifications apportées au rapport +depuis le PAN précédent. Si votre planification temporelle a été +modifiée, vous laisserez l’ancienne planification dans cette annexe. + +===== Modifications du rapport au PAN2 + +Fusce ac nisi. Integer volutpat elementum metus. Vivamus luctus +ultricies diam. Curabitur euismod. Vivamus quam. Nunc ante. Nulla mi +nulla, vehicula nec, ultrices a, tincidunt vel, enim. + +Suspendisse potenti. Aenean sed velit. Nunc a urna quis turpis imperdiet +sollicitudin. Mauris aliquam mauris ut tortor. Pellentesque tincidunt +mattis nibh. In id lectus eu. + +===== Modifications du rapport au PAN3 + +Dolor aliquam elit, a commodo nisi felis nec nibh. Nulla facilisi. Etiam +at tortor. Vivamus quis sapien nec magna scelerisque lobortis. + +Curabitur tincidunt viverra justo. Cum sociis natoque penatibus et +magnis dis parturient montes, nascetur ridiculus mus. Sed eros ante, +mattis ullamcorper, posuere quis, tempor vel, metus. Maecenas cursus +cursus lacus. Sed. + +===== Modifications du rapport au PAN4 + +Hac habitasse platea dictumst. Cras quis lacus. Vestibulum rhoncus +congue lacus. Vivamus euismod, felis quis commodo viverra, dolor elit +dictum ante, et mollis eros augue at est. Class aptent taciti sociosqu +ad litora torquent per conubia nostra, per inceptos himenaeos. Nulla +lectus sem, tristique sed, semper in, hendrerit non, sem. Vivamus. diff --git a/rapport/annexes/moduleX.adoc b/rapport/annexes/moduleX.adoc index 63da0e3..9da36f2 100644 --- a/rapport/annexes/moduleX.adoc +++ b/rapport/annexes/moduleX.adoc @@ -1,43 +1,43 @@ -=== Module X - -==== Descriptions - -[source,cpp] ----- -#include - -using namespace std; - -class M -{ -public: - void hello() - { - cout << "hello" << endl; - } -}; - -int main() -{ - M m; - m.hello(); - return 0; -} ----- - - -[source,c] ----- -include::code/test.c[] ----- - -Et l'équation: - -[latexmath] -++++ -A \in \mathcal{M}_{u,k}(\mathbb{R}) et B \in \mathcal{M}_{k,f}(\mathbb{R}) -++++ - -==== Avancement - -==== Bibliographie spécifique +=== Module X + +==== Descriptions + +[source,cpp] +---- +#include + +using namespace std; + +class M +{ +public: + void hello() + { + cout << "hello" << endl; + } +}; + +int main() +{ + M m; + m.hello(); + return 0; +} +---- + + +[source,c] +---- +include::code/test.c[] +---- + +Et l'équation: + +[latexmath] +++++ +A \in \mathcal{M}_{u,k}(\mathbb{R}) et B \in \mathcal{M}_{k,f}(\mathbb{R}) +++++ + +==== Avancement + +==== Bibliographie spécifique diff --git a/rapport/annexes/moduleY.adoc b/rapport/annexes/moduleY.adoc index f5e1a2a..91c5ed3 100644 --- a/rapport/annexes/moduleY.adoc +++ b/rapport/annexes/moduleY.adoc @@ -1,7 +1,7 @@ -=== Module Y - -==== Descriptions - -==== Avancement - -==== Bibliographie spécifique +=== Module Y + +==== Descriptions + +==== Avancement + +==== Bibliographie spécifique diff --git a/rapport/annexes/reunions.adoc b/rapport/annexes/reunions.adoc index 815bc2c..0e6efde 100644 --- a/rapport/annexes/reunions.adoc +++ b/rapport/annexes/reunions.adoc @@ -1,21 +1,21 @@ -=== Comptes Rendus de réunions - -Insérez ici vos comptes rendus de réunions : date, durée, participants, -sujets abordés. - -==== Réunion du dd/mm/yyyy - -* Présents: -** AA -** BB -** CC -* Sujets abordés -** *xxx* : Nec, iaculis vel, mi. Nullam et augue vitae nunc tristique -vehicula. Suspendisse eget elit. Duis adipiscing dui non quam. -* Actions à entreprendre: -** Fusce sollicitudin molestie dui. Sed magna orci, accumsan nec, -viverra non, pharetra id, dui. Lorem ipsum dolor sit amet, consectetuer -adipiscing elit. -** Interdum arcu, at pellentesque diam metus ut nulla. Vestibulum eu -dolor sit amet lacus varius fermentum. Morbi dolor enim, pulvinar eget. - +=== Comptes Rendus de réunions + +Insérez ici vos comptes rendus de réunions : date, durée, participants, +sujets abordés. + +==== Réunion du dd/mm/yyyy + +* Présents: +** AA +** BB +** CC +* Sujets abordés +** *xxx* : Nec, iaculis vel, mi. Nullam et augue vitae nunc tristique +vehicula. Suspendisse eget elit. Duis adipiscing dui non quam. +* Actions à entreprendre: +** Fusce sollicitudin molestie dui. Sed magna orci, accumsan nec, +viverra non, pharetra id, dui. Lorem ipsum dolor sit amet, consectetuer +adipiscing elit. +** Interdum arcu, at pellentesque diam metus ut nulla. Vestibulum eu +dolor sit amet lacus varius fermentum. Morbi dolor enim, pulvinar eget. + diff --git a/rapport/architecture/ihm.adoc b/rapport/architecture/ihm.adoc index 03ca55c..15f4056 100644 --- a/rapport/architecture/ihm.adoc +++ b/rapport/architecture/ihm.adoc @@ -1,8 +1,8 @@ -=== Interface utilisateur graphique - - -.Interface graphique client -image::../images/Interface_PACT-1.png[Interface_PACT-1] - -.Interface graphique admin -image::../images/Interface_PACT-2.png[Interface_PACT-2] +=== Interface utilisateur graphique + + +.Interface graphique client +image::../images/Interface_PACT-1.png[Interface_PACT-1] + +.Interface graphique admin +image::../images/Interface_PACT-2.png[Interface_PACT-2] diff --git a/rapport/architecture/interfaces.adoc b/rapport/architecture/interfaces.adoc index 3876133..7417eee 100644 --- a/rapport/architecture/interfaces.adoc +++ b/rapport/architecture/interfaces.adoc @@ -1,38 +1,38 @@ -=== Description des interfaces (PAN1 / PAN2) - -//Pour le PAN1, il faut identifier et décrire sommairement toutes les -//interfaces entre modules. - -//Pour le PAN2, il faut une description complète des interfaces. - -SE et Image : le système transmet les données captées par la caméra embarquée au module d’image pour le traitement de celles-ci. - -SE et reconnaissance vocale : le système transmet le signal capté par le micro embarqué au module de reconnaissance vocale qui s’occupe de transformer ce signal en une chaine de caractère. - -Reconnaissance vocale et TAL : le module de reconnaissance vocal envoie la chaine de caractères qu’il a collectée au module de TAL pour l’analyse du texte. - -TAL et base de donnée : Dans ces deux cas, après analyse des données anonymisées, les modules TAL et image envoient les résultats à la base de donnée qui va les conserver. - -Base de donnée / Analyse des données : Le module d'analyse des données récupère les données brutes dans la base de données et calcules des statistiques sur celles-ci. - -Interface web / Analyse de donnée : L'interface web récupère les données analysées a l'aide d'une API pour les afficher. - -Design et SE/ design et interface web : Le module design doit évoluer avec le module SE et interface web dans la conception des modules. Il se complète avec le module SE pour donner la borne physique. Et il se complète avec le module d’interface web pour donner l’outil utilisable par le client. - - -//Il faut ici une description textuelle de chaque interface, c'est-à-dire chaque -//échange entre deux blocs. -//Si c’est une interface entre deux blocs informatiques, c’est une interface -//Java. -//S’il y a des échanges de données complexes, il faut en décrire le format avec -//précision. -//Si c’est une interface entre deux blocs électroniques, c’est une description -//des signaux électroniques ou protocoles utilisés. - -//==== InterfaceBloc1-2 - -//Description textuelle d’interface - -//==== InterfaceBloc2-4 - -//Description textuelle d’interface +=== Description des interfaces (PAN1 / PAN2) + +//Pour le PAN1, il faut identifier et décrire sommairement toutes les +//interfaces entre modules. + +//Pour le PAN2, il faut une description complète des interfaces. + +SE et Image : le système transmet les données captées par la caméra embarquée au module d’image pour le traitement de celles-ci. + +SE et reconnaissance vocale : le système transmet le signal capté par le micro embarqué au module de reconnaissance vocale qui s’occupe de transformer ce signal en une chaine de caractère. + +Reconnaissance vocale et TAL : le module de reconnaissance vocal envoie la chaine de caractères qu’il a collectée au module de TAL pour l’analyse du texte. + +TAL et base de donnée : Dans ces deux cas, après analyse des données anonymisées, les modules TAL et image envoient les résultats à la base de donnée qui va les conserver. + +Base de donnée / Analyse des données : Le module d'analyse des données récupère les données brutes dans la base de données et calcules des statistiques sur celles-ci. + +Interface web / Analyse de donnée : L'interface web récupère les données analysées a l'aide d'une API pour les afficher. + +Design et SE/ design et interface web : Le module design doit évoluer avec le module SE et interface web dans la conception des modules. Il se complète avec le module SE pour donner la borne physique. Et il se complète avec le module d’interface web pour donner l’outil utilisable par le client. + + +//Il faut ici une description textuelle de chaque interface, c'est-à-dire chaque +//échange entre deux blocs. +//Si c’est une interface entre deux blocs informatiques, c’est une interface +//Java. +//S’il y a des échanges de données complexes, il faut en décrire le format avec +//précision. +//Si c’est une interface entre deux blocs électroniques, c’est une description +//des signaux électroniques ou protocoles utilisés. + +//==== InterfaceBloc1-2 + +//Description textuelle d’interface + +//==== InterfaceBloc2-4 + +//Description textuelle d’interface diff --git a/rapport/architecture/schema.adoc b/rapport/architecture/schema.adoc index ecf6265..31c4e7f 100644 --- a/rapport/architecture/schema.adoc +++ b/rapport/architecture/schema.adoc @@ -1,84 +1,84 @@ -=== Schéma d’architecture - -[blockdiag] -.... -blockdiag{ - default_fontsize=16 - default_group_color = "#7777FF"; node_height=85 - node_width=130 - reseaux_sociaux[label="Réseaux \nsociaux" , color="#D05E3F", shape = "flowchart.input"] - interface_avis[label="Interface \nretours \nd'avis", color="#D05E3F",shape = "flowchart.input"] - group{ - reseaux_sociaux;interface_avis; - } - micro[label="Micro", color="#D07115",shape = "flowchart.input"] - cam[label="Caméra", color="#D07115",shape = "flowchart.input"] - group{ - cam;micro; - } - traitement_audio[label="Traitement du \nsignal audio", color="#83EBDC"] - ia_vocal[label="Reconnaissance \nvocale", color="#B3D04B"] - ia_image[label="Reconnaissance \nd'image", color="#B3D04B"] - traitement_language[label="Traitement \ndu language", color="#F787C8"] - droit[label="Droit", color="#CC0C30"] - bdd[label="Base de donnée", color="#FDFF85",shape = "flowchart.database"] - analyse[label="Analyse des \ndonnées", color="#F787C8"] - interface_admin[label="Interface \nadministrateur", color="#D05E3F"] - - reseaux_sociaux -> traitement_language[label='Avis textuel', fontsize=10]; - interface_avis -> traitement_language [label='Commentaire', fontsize=10]; - droit -> bdd; - micro -> traitement_audio [label='Son', fontsize=10] ; - traitement_audio -> ia_vocal [label='Son', fontsize=10]; - ia_vocal -> traitement_language; - traitement_language -> bdd [label='Avis', fontsize=10, folded]; - bdd -> analyse ; - analyse -> interface_admin [label='Données traitées', fontsize=10]; - cam -> ia_image; - ia_image -> bdd [label='Données interprétées', fontsize=10]; - droit -> bdd [label='Régulation des données', fontsize=10]; - -} -.... - -==== Description des blocs - -===== Droit - -Vérifier la conformité du projet, connaitre l'ensemble des restrictions auxquels est soumis notre projet afin de mieux se conformer à la loi sur le traitement des données personnelles. - -===== Système embarqué - -Choix du hardware, fabrication de la borne, installation des logiciels et mise en production des autres modules. - -===== Traitement du signal - -Préparer le signal audio sortant du microphone pour le convertir en un signal analysable par le module reconnaissance vocale. - -===== Reconnaissance d'image - -A l'aide des images récupérées par la caméra et de réseaux neuronaux réussir à reconnaitre des gestes, des émotions sur un visage, l'âge et le sexe de la personne. - -===== Reconnaissance vocale - -Récupere le signal audio traité afin d'intentifier des ou les mots prononcés par l'utilisateur. - -===== Traitement du language - -A partir du texte reçus l'objectif est de catégoriser les avis suivant s'il sont positifs ou négatifs. De manière plus générale ce module extrait des informations des avis qui pourront par la suite êtres analysées plus facilement. - -===== Base de donnée - -La fonction de ce bloc est de récupérées et stockées les données du traitement du language et de la reconnaissance d'image qui auront été anonymisées. - -===== Analyse des données - -Traiter, analyser et interpréter les données afin de générer les métriques importantes pour l'administrateur. - -===== Interface administrateur - -Présente à l'administrateur de manière élégante, claire, organisées et détaillé les résultats des analyses faites sur les différentes avis. - -===== Récupération de données de sources autres - -L'objectif de ce bloc est de récupérer des données textuelles autres que les données recueillies par le bloc reconnaissance vocale pour enrichir la base d'avis utilisés par le bloc d'analyse de données. Ces sources autres peuvent être les commentaires laissés sur les réseaux sociaux ou d'une interface permettant de donner son avis à l'aide d'un formulaire. +=== Schéma d’architecture + +[blockdiag] +.... +blockdiag{ + default_fontsize=16 + default_group_color = "#7777FF"; node_height=85 + node_width=130 + reseaux_sociaux[label="Réseaux \nsociaux" , color="#D05E3F", shape = "flowchart.input"] + interface_avis[label="Interface \nretours \nd'avis", color="#D05E3F",shape = "flowchart.input"] + group{ + reseaux_sociaux;interface_avis; + } + micro[label="Micro", color="#D07115",shape = "flowchart.input"] + cam[label="Caméra", color="#D07115",shape = "flowchart.input"] + group{ + cam;micro; + } + traitement_audio[label="Traitement du \nsignal audio", color="#83EBDC"] + ia_vocal[label="Reconnaissance \nvocale", color="#B3D04B"] + ia_image[label="Reconnaissance \nd'image", color="#B3D04B"] + traitement_language[label="Traitement \ndu language", color="#F787C8"] + droit[label="Droit", color="#CC0C30"] + bdd[label="Base de donnée", color="#FDFF85",shape = "flowchart.database"] + analyse[label="Analyse des \ndonnées", color="#F787C8"] + interface_admin[label="Interface \nadministrateur", color="#D05E3F"] + + reseaux_sociaux -> traitement_language[label='Avis textuel', fontsize=10]; + interface_avis -> traitement_language [label='Commentaire', fontsize=10]; + droit -> bdd; + micro -> traitement_audio [label='Son', fontsize=10] ; + traitement_audio -> ia_vocal [label='Son', fontsize=10]; + ia_vocal -> traitement_language; + traitement_language -> bdd [label='Avis', fontsize=10, folded]; + bdd -> analyse ; + analyse -> interface_admin [label='Données traitées', fontsize=10]; + cam -> ia_image; + ia_image -> bdd [label='Données interprétées', fontsize=10]; + droit -> bdd [label='Régulation des données', fontsize=10]; + +} +.... + +==== Description des blocs + +===== Droit + +Vérifier la conformité du projet, connaitre l'ensemble des restrictions auxquels est soumis notre projet afin de mieux se conformer à la loi sur le traitement des données personnelles. + +===== Système embarqué + +Choix du hardware, fabrication de la borne, installation des logiciels et mise en production des autres modules. + +===== Traitement du signal + +Préparer le signal audio sortant du microphone pour le convertir en un signal analysable par le module reconnaissance vocale. + +===== Reconnaissance d'image + +A l'aide des images récupérées par la caméra et de réseaux neuronaux réussir à reconnaitre des gestes, des émotions sur un visage, l'âge et le sexe de la personne. + +===== Reconnaissance vocale + +Récupere le signal audio traité afin d'intentifier des ou les mots prononcés par l'utilisateur. + +===== Traitement du language + +A partir du texte reçus l'objectif est de catégoriser les avis suivant s'il sont positifs ou négatifs. De manière plus générale ce module extrait des informations des avis qui pourront par la suite êtres analysées plus facilement. + +===== Base de donnée + +La fonction de ce bloc est de récupérées et stockées les données du traitement du language et de la reconnaissance d'image qui auront été anonymisées. + +===== Analyse des données + +Traiter, analyser et interpréter les données afin de générer les métriques importantes pour l'administrateur. + +===== Interface administrateur + +Présente à l'administrateur de manière élégante, claire, organisées et détaillé les résultats des analyses faites sur les différentes avis. + +===== Récupération de données de sources autres + +L'objectif de ce bloc est de récupérer des données textuelles autres que les données recueillies par le bloc reconnaissance vocale pour enrichir la base d'avis utilisés par le bloc d'analyse de données. Ces sources autres peuvent être les commentaires laissés sur les réseaux sociaux ou d'une interface permettant de donner son avis à l'aide d'un formulaire. diff --git a/rapport/architecture/sequence.adoc b/rapport/architecture/sequence.adoc index 9d88dde..145eaaf 100644 --- a/rapport/architecture/sequence.adoc +++ b/rapport/architecture/sequence.adoc @@ -1,51 +1,51 @@ -=== Diagramme de séquence (optionnel) - -==== Interaction entre l'utilisateur et la borne (Interaction gestuelle / vocale) -[plantuml, sequence-x] -.... - actor utilisateur #99FF99 - boundary frontend as "Interface utilisateur" #4da6ff - boundary Camera - boundary Micro - participant "Back end\nmachine learning" as backend #ff8680 - database database as "Base de donnée" - - utilisateur --> Camera : signe (main, visage) - Camera -> backend : flux vidéo - backend -> database : signe identifié - backend -> frontend : signe identifié - frontend --> utilisateur: indicateur de prise \nen compte de l'avis - utilisateur --> Micro : avis vocal - Micro -> backend : flux audio - backend -> database : mots clé ou \nphrases identifiés - backend -> frontend : phrase identifié - frontend --> utilisateur: indicateur de prise \nen compte de l'avis -.... - -==== Interaction entre l'utilisateur et la borne (QR Code) -[plantuml, sequence-x] -.... - actor utilisateur #99FF99 - participant qrcode as "QR Code" - boundary frontend as "Interface web" #4da6ff - participant "Back end" as backend #ff8680 - database database as "Base de donnée" - - utilisateur --> qrcode : flash - utilisateur --> frontend : retour utlisateur\n(sous forme textuelle) - frontend -> backend : retour utlisateur - backend -> database : retour utlisateur -.... - -==== Séquence d'analyse et affichange des données -[plantuml, sequence-x] -.... - actor utilisateur #99FF99 - boundary frontend as "Interface \nadministrateur" #4da6ff - participant "Back end\nanalyse de données" as backend #ff8680 - database database as "Base de donnée" - - database -> backend : Données brutes - backend -> frontend : Statistiques sur les données - utilisateur <-- frontend : données visualisées -.... +=== Diagramme de séquence (optionnel) + +==== Interaction entre l'utilisateur et la borne (Interaction gestuelle / vocale) +[plantuml, sequence-x] +.... + actor utilisateur #99FF99 + boundary frontend as "Interface utilisateur" #4da6ff + boundary Camera + boundary Micro + participant "Back end\nmachine learning" as backend #ff8680 + database database as "Base de donnée" + + utilisateur --> Camera : signe (main, visage) + Camera -> backend : flux vidéo + backend -> database : signe identifié + backend -> frontend : signe identifié + frontend --> utilisateur: indicateur de prise \nen compte de l'avis + utilisateur --> Micro : avis vocal + Micro -> backend : flux audio + backend -> database : mots clé ou \nphrases identifiés + backend -> frontend : phrase identifié + frontend --> utilisateur: indicateur de prise \nen compte de l'avis +.... + +==== Interaction entre l'utilisateur et la borne (QR Code) +[plantuml, sequence-x] +.... + actor utilisateur #99FF99 + participant qrcode as "QR Code" + boundary frontend as "Interface web" #4da6ff + participant "Back end" as backend #ff8680 + database database as "Base de donnée" + + utilisateur --> qrcode : flash + utilisateur --> frontend : retour utlisateur\n(sous forme textuelle) + frontend -> backend : retour utlisateur + backend -> database : retour utlisateur +.... + +==== Séquence d'analyse et affichange des données +[plantuml, sequence-x] +.... + actor utilisateur #99FF99 + boundary frontend as "Interface \nadministrateur" #4da6ff + participant "Back end\nanalyse de données" as backend #ff8680 + database database as "Base de donnée" + + database -> backend : Données brutes + backend -> frontend : Statistiques sur les données + utilisateur <-- frontend : données visualisées +.... diff --git a/rapport/architecture/taches.adoc b/rapport/architecture/taches.adoc index 4eaa092..79db95d 100644 --- a/rapport/architecture/taches.adoc +++ b/rapport/architecture/taches.adoc @@ -1,33 +1,33 @@ -=== Tableau détaillé des tâches - -****Note : 2 pages max - les fiches modules seront placées en annexe, -elles doivent être rédigées avec l’expert.**** - -Les différents aspects du projet sont découpés en tâches numérotées et -hiérarchisées (Tâches/sous-tâches, etc.). Chaque tâche est décrite précisément -et une équipe (typiquement un binôme) est affecté à sa réalisation. Un module -est typiquement constitué de plusieurs tâches et sous-tâches. - -Pour le PAN3, vous aurez à démontrer une version, *intégrée* et fonctionnelle de -votre projet. -Entre le PAN3 et le PAN4, vous pourrez améliorer les fonctionnalités intégrées -sans pour autant en ajouter de nouvelles. - -Reprenez et complétez le tableau suivant en précisant les différentes tâches et -sous-tâches ainsi que le (ou les) critères de réussite pour l'intégration au -PAN3. La définition des critères de réussite doit se faire en accord avec les -experts. - -[cols=",,^",options="header",] -|==== -| Tâche | Description | Critères de réussite pour l'intégration au PAN3 -| T1 | Classificateur d’image | interfaces logicielles finalisées -| T1.1 | Changement espace de couleur pour permettre … | au moins une transformation implémentée -| T1.2 | Extraction de l’histogramme à partir de l’espace XYZ… | … -| T1.3 | Extraction des caractéristiques … | … -| T1.4 | Comparaison des caractéristiques | … -| T2 | Détection de rythme (Module « Audio/Rythme ») | interfaces logicielles finalisées -| T2.1 | Découpage signal sonore en bande fréquentielle | la méthode X doit être implémentée -| T2.2 | Détection du tempo | … -| T2.3 | Changement de tempo | … -|==== +=== Tableau détaillé des tâches + +****Note : 2 pages max - les fiches modules seront placées en annexe, +elles doivent être rédigées avec l’expert.**** + +Les différents aspects du projet sont découpés en tâches numérotées et +hiérarchisées (Tâches/sous-tâches, etc.). Chaque tâche est décrite précisément +et une équipe (typiquement un binôme) est affecté à sa réalisation. Un module +est typiquement constitué de plusieurs tâches et sous-tâches. + +Pour le PAN3, vous aurez à démontrer une version, *intégrée* et fonctionnelle de +votre projet. +Entre le PAN3 et le PAN4, vous pourrez améliorer les fonctionnalités intégrées +sans pour autant en ajouter de nouvelles. + +Reprenez et complétez le tableau suivant en précisant les différentes tâches et +sous-tâches ainsi que le (ou les) critères de réussite pour l'intégration au +PAN3. La définition des critères de réussite doit se faire en accord avec les +experts. + +[cols=",,^",options="header",] +|==== +| Tâche | Description | Critères de réussite pour l'intégration au PAN3 +| T1 | Classificateur d’image | interfaces logicielles finalisées +| T1.1 | Changement espace de couleur pour permettre … | au moins une transformation implémentée +| T1.2 | Extraction de l’histogramme à partir de l’espace XYZ… | … +| T1.3 | Extraction des caractéristiques … | … +| T1.4 | Comparaison des caractéristiques | … +| T2 | Détection de rythme (Module « Audio/Rythme ») | interfaces logicielles finalisées +| T2.1 | Découpage signal sonore en bande fréquentielle | la méthode X doit être implémentée +| T2.2 | Détection du tempo | … +| T2.3 | Changement de tempo | … +|==== diff --git a/rapport/images/pact.svg b/rapport/images/pact.svg index 76485b9..b4dcfd2 100644 --- a/rapport/images/pact.svg +++ b/rapport/images/pact.svg @@ -1,126 +1,126 @@ - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/rapport/organisation/plan-tests.adoc b/rapport/organisation/plan-tests.adoc index b514ad9..7793f96 100644 --- a/rapport/organisation/plan-tests.adoc +++ b/rapport/organisation/plan-tests.adoc @@ -1,23 +1,23 @@ -=== Plans de test (PAN2+) - -Vous allez travailler sur chaque bloc de votre projet, et qu’il soit -informatique, électronique ou matériel, vous allez devoir faire du -test : - -* tester que le bloc que vous venez de finir fait ce qu’il faut ; -* tester que le bloc fonctionne avec les blocs en amont ou en aval dans -l’architecture ; -* tester que les performances sont acceptables… -* et plus globalement, tester que le projet « marche ». - -Vous allez devoir faire ce travail sur le prototype allégé, puis sur le -prototype final. C’est un travail dans le module « intégration et -tests ». - -Cette section rassemble les plans de test du proto allégé et du proto -final. C’est une liste des tests à effectuer, sous la forme, pour chaque -test : - -* situation/contexte -* action ou entrée à appliquer -* réaction ou sortie attendue. +=== Plans de test (PAN2+) + +Vous allez travailler sur chaque bloc de votre projet, et qu’il soit +informatique, électronique ou matériel, vous allez devoir faire du +test : + +* tester que le bloc que vous venez de finir fait ce qu’il faut ; +* tester que le bloc fonctionne avec les blocs en amont ou en aval dans +l’architecture ; +* tester que les performances sont acceptables… +* et plus globalement, tester que le projet « marche ». + +Vous allez devoir faire ce travail sur le prototype allégé, puis sur le +prototype final. C’est un travail dans le module « intégration et +tests ». + +Cette section rassemble les plans de test du proto allégé et du proto +final. C’est une liste des tests à effectuer, sous la forme, pour chaque +test : + +* situation/contexte +* action ou entrée à appliquer +* réaction ou sortie attendue. diff --git a/rapport/organisation/planification.adoc b/rapport/organisation/planification.adoc index 10d18a7..5a511fb 100644 --- a/rapport/organisation/planification.adoc +++ b/rapport/organisation/planification.adoc @@ -1,67 +1,67 @@ -=== Planning Prévisionnel PACT - -==== Rappel des dates -Les dates importantes de PACT sont: - -* PAN1: 22/11/2022 -* PAN2: fin janvier 2023 -* PAN3: 04/04/2023 -* PAN4: 30/05/2023 - -Les deux tableaux ci-dessous doivent vous aider à évaluer votre avancement/retard dans le développement de votre projet. -Vous pouvez aussi vous aider de ces tableaux pour: - -* identifier les périodes de fortes charge de travail -* analyser les dépendances entre modules -* les retards bloquant pour l'avancée de l'ensemble du projet (ce n'est pas forcément le cas pour tous les modules) - -==== Planning Groupe - -Pour PAN1, remplissez dans ce tableau les dates prévues. Vous mettrez à jour les dates finales en cours d'année. - -[cols=",^,,",options="header",] -|==== -|Tâche | Responsable(s) | Quand Prévisionnel | Quand effectif -|Intégration Initale | Keshav Das |15/02/23| ... -|Intégration PAN3 finalisée | Lounes Kouache |26/03/23| ... -|Préparation / répétition PAN3 | Yasmine Hamadoui |30/03/23| ... -|Démo PAN4 finalisée | Sara Meziane |31/04/23| ... -|Préparation Poster PAN4 | Lucas Sempéré |15/05/23| ... -|Présentation "Pitch" PAN4 | Quentin Roussel |24/05/23| ... -|Vidéo PAN4 | Grivaux Yannis |20/05/23| ... -|==== - -Note: - -* l'intégration initiale correspond à l'étape où tous les modules communiquent ensemble même si les informations échangées sont fausses ou incomplètes. Pour rappel vous aurez trois journées complètes la semaine du 20/03 pour finaliser l'intégration -* Le poster PAN4 devra être envoyé au plus tard le 18 mai 2023 -* Le support de présentation PAN4 devra être envoyé pour le 26/05/2023 -* La vidéo est une vidéo promotionnelle de 2 minutes maximum, et devra être envoyée pour le 26/05/2023 - -Vous mettrez par ailleurs à jour l'annexe "avancement" avec les compte-rendus de vos réunions de groupe. - - -==== Planning Modules - -Nous vous demandons de prévoir les dates des étapes de développement de vos modules. -Pour PAN1, vous remplirez les dates prévues. Vous mettrez à jour les dates finales en cours d'année. - -* Travail Initial: bibliographie sur le module -* Version initiale: le module tourne en mode isolé -* Version intégrable: le module est prêt à être intégré, il manquera vraisemblablement des fonctionnalités. Cela correspond à une version "squelette" du projet. -* Version intégrée: le module est complet et intégré - - -[cols=",^,^,,,",options="header",] -|==== -|Module | Responsables | Travail Initial | Version initiale | Version intégrable | Version intégrée -|Reconnaissance image | Keshav Das | prévu: 25/11/22 fait:... | prévu: 31/01/23 fait:... | prévu: 10/02/23 fait:... | prévu: 25/02/23 fait:... -|Reconnaissance vocale | Yasmine Hamadoui | prévu: 25/11/22 fait:... | prévu: 31/01/23 fait:... | prévu: 10/02/23 fait:... | prévu: 25/02/23 fait:... -|Traitement du langage| Sara Meziane | prévu: 25/11/22 fait:... | prévu: 31/01/23 fait:... | prévu: 10/02/23 fait:... | prévu: 25/02/23 fait:... -|Système embarqué| Yannis Grivaux | prévu: 25/11/22 fait:... | prévu: 31/01/23 fait:... | prévu: 05/02/23 fait:... | prévu: 15/02/23 fait:... -|Ergonomie/Design| Wissal Belhorma | prévu: 25/11/22 fait:... | prévu: 31/01/23 fait:... | prévu: 10/02/23 fait:... | prévu: 25/02/23 fait:... -|Droit| Lounes Kouache | prévu: 25/11/22 fait:... | prévu: 31/01/23 fait:... | prévu: 10/02/23 fait:... | prévu: 25/02/23 fait:... -|Interface utilisateur / BDD| Quentin Roussel | prévu: 25/11/22 fait:... | prévu: 31/01/23 fait:... | prévu: 10/02/23 fait:... | prévu: 25/02/23 fait:... -|==== - - +=== Planning Prévisionnel PACT + +==== Rappel des dates +Les dates importantes de PACT sont: + +* PAN1: 22/11/2022 +* PAN2: fin janvier 2023 +* PAN3: 04/04/2023 +* PAN4: 30/05/2023 + +Les deux tableaux ci-dessous doivent vous aider à évaluer votre avancement/retard dans le développement de votre projet. +Vous pouvez aussi vous aider de ces tableaux pour: + +* identifier les périodes de fortes charge de travail +* analyser les dépendances entre modules +* les retards bloquant pour l'avancée de l'ensemble du projet (ce n'est pas forcément le cas pour tous les modules) + +==== Planning Groupe + +Pour PAN1, remplissez dans ce tableau les dates prévues. Vous mettrez à jour les dates finales en cours d'année. + +[cols=",^,,",options="header",] +|==== +|Tâche | Responsable(s) | Quand Prévisionnel | Quand effectif +|Intégration Initale | Keshav Das |15/02/23| ... +|Intégration PAN3 finalisée | Lounes Kouache |26/03/23| ... +|Préparation / répétition PAN3 | Yasmine Hamadoui |30/03/23| ... +|Démo PAN4 finalisée | Sara Meziane |31/04/23| ... +|Préparation Poster PAN4 | Lucas Sempéré |15/05/23| ... +|Présentation "Pitch" PAN4 | Quentin Roussel |24/05/23| ... +|Vidéo PAN4 | Grivaux Yannis |20/05/23| ... +|==== + +Note: + +* l'intégration initiale correspond à l'étape où tous les modules communiquent ensemble même si les informations échangées sont fausses ou incomplètes. Pour rappel vous aurez trois journées complètes la semaine du 20/03 pour finaliser l'intégration +* Le poster PAN4 devra être envoyé au plus tard le 18 mai 2023 +* Le support de présentation PAN4 devra être envoyé pour le 26/05/2023 +* La vidéo est une vidéo promotionnelle de 2 minutes maximum, et devra être envoyée pour le 26/05/2023 + +Vous mettrez par ailleurs à jour l'annexe "avancement" avec les compte-rendus de vos réunions de groupe. + + +==== Planning Modules + +Nous vous demandons de prévoir les dates des étapes de développement de vos modules. +Pour PAN1, vous remplirez les dates prévues. Vous mettrez à jour les dates finales en cours d'année. + +* Travail Initial: bibliographie sur le module +* Version initiale: le module tourne en mode isolé +* Version intégrable: le module est prêt à être intégré, il manquera vraisemblablement des fonctionnalités. Cela correspond à une version "squelette" du projet. +* Version intégrée: le module est complet et intégré + + +[cols=",^,^,,,",options="header",] +|==== +|Module | Responsables | Travail Initial | Version initiale | Version intégrable | Version intégrée +|Reconnaissance image | Keshav Das | prévu: 25/11/22 fait:... | prévu: 31/01/23 fait:... | prévu: 10/02/23 fait:... | prévu: 25/02/23 fait:... +|Reconnaissance vocale | Yasmine Hamadoui | prévu: 25/11/22 fait:... | prévu: 31/01/23 fait:... | prévu: 10/02/23 fait:... | prévu: 25/02/23 fait:... +|Traitement du langage| Sara Meziane | prévu: 25/11/22 fait:... | prévu: 31/01/23 fait:... | prévu: 10/02/23 fait:... | prévu: 25/02/23 fait:... +|Système embarqué| Yannis Grivaux | prévu: 25/11/22 fait:... | prévu: 31/01/23 fait:... | prévu: 05/02/23 fait:... | prévu: 15/02/23 fait:... +|Ergonomie/Design| Wissal Belhorma | prévu: 25/11/22 fait:... | prévu: 31/01/23 fait:... | prévu: 10/02/23 fait:... | prévu: 25/02/23 fait:... +|Droit| Lounes Kouache | prévu: 25/11/22 fait:... | prévu: 31/01/23 fait:... | prévu: 10/02/23 fait:... | prévu: 25/02/23 fait:... +|Interface utilisateur / BDD| Quentin Roussel | prévu: 25/11/22 fait:... | prévu: 31/01/23 fait:... | prévu: 10/02/23 fait:... | prévu: 25/02/23 fait:... +|==== + + diff --git a/rapport/pdf-theme.yml b/rapport/pdf-theme.yml index 4037da8..df114cf 100644 --- a/rapport/pdf-theme.yml +++ b/rapport/pdf-theme.yml @@ -1,21 +1,21 @@ -extends: -- default-with-font-fallbacks -- default-sans - -page: - size: A4 - margin: 2.5cm -title-page: - background-image: image:images/pact.svg[] - logo: - image: image:images/pact.svg[] - top: 0% - title: - font-size: 32 - font-style: bold - font-color: #000000 - sub-title: - font-size: 24 - authors: - font-size: 22 - +extends: +- default-with-font-fallbacks +- default-sans + +page: + size: A4 + margin: 2.5cm +title-page: + background-image: image:images/pact.svg[] + logo: + image: image:images/pact.svg[] + top: 0% + title: + font-size: 32 + font-style: bold + font-color: #000000 + sub-title: + font-size: 24 + authors: + font-size: 22 + diff --git a/rapport/proposition/etat-de-l-art.adoc b/rapport/proposition/etat-de-l-art.adoc index 18f1f88..3c03f92 100644 --- a/rapport/proposition/etat-de-l-art.adoc +++ b/rapport/proposition/etat-de-l-art.adoc @@ -1,44 +1,44 @@ -=== Description de l’état de l’art -ifdef::env-gitlab,env-browser[:outfilesuffix: .adoc] - -==== Borne à smiley - -La borne à smiley est une solution très populaire et utilisée par de nombreuses entreprises pour recueillir les avis utilisateurs par appui sur un émoticône représentant une émotion. La popularité de ce produit montre le besoin de dispositifs de recueil d’avis automatisé. Cependant, l'utilisation de ce type de borne a rapidement décru après la pandémie pour des raisons d'hygiène. De plus, ces bornes présentent d'autres inconvénients: incapabilité de poser plus qu'une question et absence de justification derrière les réponses. - -.Exemple de borne à smiley -image::../images/borne.png[logo borne, 100, 300] - -==== Données annotées https://github.com/aesuli/SentiWordNet[SentiWordNet] et https://archive.illc.uva.nl//EuroWordNet/[EuroWordNet] - -SentiWordNet est un ensemble de groupes de synonymes en Anglais (appelés synsets) auxquels ont été affectés trois scores quantifiant leur positivité, leur négativité et leur objectivité. L'ensemble est disponible en libre accès à des fins de recherche sur la classification d'émotion, un domaine récemment créé. EuroWordNet est aussi un réseau sémantique, à la différence qu'il a été développé pour des langues européennes et donc nous est utile pour analyser des avis en Français. Le coeur de notre projet étant la classification d'avis utilisateurs pour permettre au gérant d'améliorer au mieux l'expérience utilisateur, ces bases de données sont extrêmement pertinentes. - -image::../images/Sentiwordnet.jpg[logo Sentiwordnet, 300, 66] -image::../images/eurowordnet.jpeg[logo eurowordnet] - -==== Outil https://github.com/cjhutto/vaderSentiment[VADER] - -VADER est un outil développé par le MIT pour un usage dans le traitement du langage naturel en Anglais. Il faut mentionner qu'il peut être utilisé sur du Français en s'appuyant sur un outil de traduction externe. À un avis utilisateur donné, il associe trois scores: positivité, négativité et neutralité, puis en déduit un score global, en fonction d'une pondération définie par le programmeur (nous dans ce cas), (entre 1 (avis le plus positif possible) et -1 (avis le plus négatif possible). Il peut, entre autres, prendre en compte les émoticônes, la présence de majuscules, la disposition de la ponctuation, des abbréviations usuelles. Il a l'avantage d'être particulièrement efficace pour analyser les sentiments des avis postés sur les réseaux sociaux, or nous voulons pratiquer le scraping d'avis sur ces plateformes pour que le gérant puisse avoir un maximum de retours. - -==== Algorithme https://github.com/HSE-asavchenko/face-emotion-recognition[HSEmotion] (High-Speed face Emotion recognition) - -Cet algorithme a été développé à l'université HSE dans le but de reconnaître des émotions à partir de photos ou de vidéos. Il a notamment permis à son auteur Andrey Savchenko d'avoir de très bons résultats aux concours de reconnaissance d'émotion organisés par https://ibug.doc.ic.ac.uk[ibug], un groupe d'experts spécialisés dans l'analyse du comportement humain. Cela montre que ce domaine est en plein essor. - -==== https://google.github.io/mediapipe/solutions/hands.html[MediaPipe Hands] - -Cette interface de programmation permet au programmeur d'avoir un traçage de la main. Le processus se décompose en deux parties: dans un premier temps, un modèle de machine learning délimite la main dans l'image entière, puis un deuxième modèle se charge de placer des points critiques de la main à partir de cette image bornée. L'ensemble peut permettre de reconnaître des signes de la main par exemple. Nous avons pour projet de reconnaître de tels signes pour permettre une interaction à distance entre l'utilisateur et la borne. - -.Exemples de placement de points sur des mains réelles (en haut) et issues d'images de synthèse (en bas) (source: https://google.github.io/mediapipe/solutions/hands.html) -image::../images/hand.png[logo hand, 480, 254] - - -==== Interface Google My Business - -Cette interface de programmation permet, entre autres, de https://developers.google.com/my-business/reference/rest/v4/accounts.locations.reviews[récupérer] des avis laissés sur Google Maps concernant un lieu. Elle peut s'avérer utile pour recueillir des avis pour notre projet. - -image::../images/googlebusiness.jpg[logo googlebusiness, 125, 125] - -==== https://developers.facebook.com/docs/instagram-api/[API GraphQL d'instagram] - -Cette interface de programmation permet de récupérer automatiquement des avis laissés sur des publications Instagram ainsi que le nombre de "j'aime". Cette solution peut être utile comme source annexe d'avis. - -image::../images/graphql.png[logo graphql, 125, 125] +=== Description de l’état de l’art +ifdef::env-gitlab,env-browser[:outfilesuffix: .adoc] + +==== Borne à smiley + +La borne à smiley est une solution très populaire et utilisée par de nombreuses entreprises pour recueillir les avis utilisateurs par appui sur un émoticône représentant une émotion. La popularité de ce produit montre le besoin de dispositifs de recueil d’avis automatisé. Cependant, l'utilisation de ce type de borne a rapidement décru après la pandémie pour des raisons d'hygiène. De plus, ces bornes présentent d'autres inconvénients: incapabilité de poser plus qu'une question et absence de justification derrière les réponses. + +.Exemple de borne à smiley +image::../images/borne.png[logo borne, 100, 300] + +==== Données annotées https://github.com/aesuli/SentiWordNet[SentiWordNet] et https://archive.illc.uva.nl//EuroWordNet/[EuroWordNet] + +SentiWordNet est un ensemble de groupes de synonymes en Anglais (appelés synsets) auxquels ont été affectés trois scores quantifiant leur positivité, leur négativité et leur objectivité. L'ensemble est disponible en libre accès à des fins de recherche sur la classification d'émotion, un domaine récemment créé. EuroWordNet est aussi un réseau sémantique, à la différence qu'il a été développé pour des langues européennes et donc nous est utile pour analyser des avis en Français. Le coeur de notre projet étant la classification d'avis utilisateurs pour permettre au gérant d'améliorer au mieux l'expérience utilisateur, ces bases de données sont extrêmement pertinentes. + +image::../images/Sentiwordnet.jpg[logo Sentiwordnet, 300, 66] +image::../images/eurowordnet.jpeg[logo eurowordnet] + +==== Outil https://github.com/cjhutto/vaderSentiment[VADER] + +VADER est un outil développé par le MIT pour un usage dans le traitement du langage naturel en Anglais. Il faut mentionner qu'il peut être utilisé sur du Français en s'appuyant sur un outil de traduction externe. À un avis utilisateur donné, il associe trois scores: positivité, négativité et neutralité, puis en déduit un score global, en fonction d'une pondération définie par le programmeur (nous dans ce cas), (entre 1 (avis le plus positif possible) et -1 (avis le plus négatif possible). Il peut, entre autres, prendre en compte les émoticônes, la présence de majuscules, la disposition de la ponctuation, des abbréviations usuelles. Il a l'avantage d'être particulièrement efficace pour analyser les sentiments des avis postés sur les réseaux sociaux, or nous voulons pratiquer le scraping d'avis sur ces plateformes pour que le gérant puisse avoir un maximum de retours. + +==== Algorithme https://github.com/HSE-asavchenko/face-emotion-recognition[HSEmotion] (High-Speed face Emotion recognition) + +Cet algorithme a été développé à l'université HSE dans le but de reconnaître des émotions à partir de photos ou de vidéos. Il a notamment permis à son auteur Andrey Savchenko d'avoir de très bons résultats aux concours de reconnaissance d'émotion organisés par https://ibug.doc.ic.ac.uk[ibug], un groupe d'experts spécialisés dans l'analyse du comportement humain. Cela montre que ce domaine est en plein essor. + +==== https://google.github.io/mediapipe/solutions/hands.html[MediaPipe Hands] + +Cette interface de programmation permet au programmeur d'avoir un traçage de la main. Le processus se décompose en deux parties: dans un premier temps, un modèle de machine learning délimite la main dans l'image entière, puis un deuxième modèle se charge de placer des points critiques de la main à partir de cette image bornée. L'ensemble peut permettre de reconnaître des signes de la main par exemple. Nous avons pour projet de reconnaître de tels signes pour permettre une interaction à distance entre l'utilisateur et la borne. + +.Exemples de placement de points sur des mains réelles (en haut) et issues d'images de synthèse (en bas) (source: https://google.github.io/mediapipe/solutions/hands.html) +image::../images/hand.png[logo hand, 480, 254] + + +==== Interface Google My Business + +Cette interface de programmation permet, entre autres, de https://developers.google.com/my-business/reference/rest/v4/accounts.locations.reviews[récupérer] des avis laissés sur Google Maps concernant un lieu. Elle peut s'avérer utile pour recueillir des avis pour notre projet. + +image::../images/googlebusiness.jpg[logo googlebusiness, 125, 125] + +==== https://developers.facebook.com/docs/instagram-api/[API GraphQL d'instagram] + +Cette interface de programmation permet de récupérer automatiquement des avis laissés sur des publications Instagram ainsi que le nombre de "j'aime". Cette solution peut être utile comme source annexe d'avis. + +image::../images/graphql.png[logo graphql, 125, 125] diff --git a/rapport/proposition/proposition.adoc b/rapport/proposition/proposition.adoc index c62410d..95d430f 100644 --- a/rapport/proposition/proposition.adoc +++ b/rapport/proposition/proposition.adoc @@ -1,16 +1,16 @@ -=== Description de la proposition - -De nombreux moyens sont mis en place pour donner un avis sur un achat, une visite… Mais ces moyens ne sont pas toujours optimaux. En effet, les réseaux sociaux sont un moyen de le faire cependant comme attendu, après avoir interrogé les gens autour de nous, on a réalisé que beaucoup de personnes ne faisaient pas l’effort de se connecter, écrire un commentaire… En revanche, ce sont les expériences particulièrement négatives et positives qui reviennent car les gens ont bien plus envie de le partager. Ainsi cela ne représente pas une source d’avis nuancé et représentatif pour le gérant. - -Les boutons sur lesquels on pouvait appuyer pour donner un avis étaient certes un moyen d’exprimer son sentiment sans faire d’effort. Cependant, depuis le début de la crise covid, ces bornes ont disparu pour des raisons d’hygiène. - -On a donc pensé à une manière de donner son avis efficace qui serait donc à la fois ludique et attractif mais surtout rapide et facile d’utilisation, qui demanderait le moins d’effort aux usagers. Notre dispositif ne demande aux usagers que de faire un signe de la main ou une expression faciale traduisant leur avis. Cette borne permettra, en plus des QR code placés un peu partout, de donner un commentaire plus long et construit à ceux qui le souhaite. - -Cette borne permettra à tous de donner leur avis ce qu’aujourd’hui n’est pas possible sur le même dispositif. Après avoir interrogé des clients potentiels, on a remarqué que les personnes âgés n’utilisaient pas internet pour donner leur avis, de même pour de nombreux jeunes, les réseaux sociaux ne leur servaient pas à écrire des commentaires en revanche, il donne de l’importance aux avis et notes sur internet avant d’acheter quelque chose ou de visiter un endroit, un restaurant… De même, les professionnels donnent beaucoup d’importance aux retours de leur usagers pour améliorer leur services. Tout le monde s’accorde sur le fait que les dispositifs pour donner leur avis sont importants bien qu’ils ne soient pas très efficaces. - -Notre borne a pour objectif d’une part donner une voix à tous les usagers quelque soit leur âge, leur rapport aux technologies… et d’autre part de faire le lien entre fournisseur de service et usagers. Ainsi une grosse partie de notre projet reste l’interface accessible au gérant. En effet, les données récoltées par la borne seront complétés par les commentaires laissés sur les réseaux sociaux. Ainsi, on pourra offrir au gérant un rapport complet et nuancé. Le gérant aura accès à une synthèse de tous les avis ainsi qu’un rapport sur les points récurrents par mot-clés et la totalité des commentaires. - - -.Formes possibles pour la borne -image::../images/borne2.png[borne2] - +=== Description de la proposition + +De nombreux moyens sont mis en place pour donner un avis sur un achat, une visite… Mais ces moyens ne sont pas toujours optimaux. En effet, les réseaux sociaux sont un moyen de le faire cependant comme attendu, après avoir interrogé les gens autour de nous, on a réalisé que beaucoup de personnes ne faisaient pas l’effort de se connecter, écrire un commentaire… En revanche, ce sont les expériences particulièrement négatives et positives qui reviennent car les gens ont bien plus envie de le partager. Ainsi cela ne représente pas une source d’avis nuancé et représentatif pour le gérant. + +Les boutons sur lesquels on pouvait appuyer pour donner un avis étaient certes un moyen d’exprimer son sentiment sans faire d’effort. Cependant, depuis le début de la crise covid, ces bornes ont disparu pour des raisons d’hygiène. + +On a donc pensé à une manière de donner son avis efficace qui serait donc à la fois ludique et attractif mais surtout rapide et facile d’utilisation, qui demanderait le moins d’effort aux usagers. Notre dispositif ne demande aux usagers que de faire un signe de la main ou une expression faciale traduisant leur avis. Cette borne permettra, en plus des QR code placés un peu partout, de donner un commentaire plus long et construit à ceux qui le souhaite. + +Cette borne permettra à tous de donner leur avis ce qu’aujourd’hui n’est pas possible sur le même dispositif. Après avoir interrogé des clients potentiels, on a remarqué que les personnes âgés n’utilisaient pas internet pour donner leur avis, de même pour de nombreux jeunes, les réseaux sociaux ne leur servaient pas à écrire des commentaires en revanche, il donne de l’importance aux avis et notes sur internet avant d’acheter quelque chose ou de visiter un endroit, un restaurant… De même, les professionnels donnent beaucoup d’importance aux retours de leur usagers pour améliorer leur services. Tout le monde s’accorde sur le fait que les dispositifs pour donner leur avis sont importants bien qu’ils ne soient pas très efficaces. + +Notre borne a pour objectif d’une part donner une voix à tous les usagers quelque soit leur âge, leur rapport aux technologies… et d’autre part de faire le lien entre fournisseur de service et usagers. Ainsi une grosse partie de notre projet reste l’interface accessible au gérant. En effet, les données récoltées par la borne seront complétés par les commentaires laissés sur les réseaux sociaux. Ainsi, on pourra offrir au gérant un rapport complet et nuancé. Le gérant aura accès à une synthèse de tous les avis ainsi qu’un rapport sur les points récurrents par mot-clés et la totalité des commentaires. + + +.Formes possibles pour la borne +image::../images/borne2.png[borne2] + diff --git a/rapport/scenario/scenario.adoc b/rapport/scenario/scenario.adoc index 2342c4f..0e734fc 100644 --- a/rapport/scenario/scenario.adoc +++ b/rapport/scenario/scenario.adoc @@ -1,23 +1,23 @@ -=== Scénarios d’usage - -==== Scénario Client - -Voilà déjà quatre heures que j’étais dans le parc d'attraction avec mon fils, on s'est beaucoup amusé, et le temps est passé si vite, mais il était temps de rentrer. J'étais plongé dans mes pensées lorsque mon fils s’écria : "Papa ! Papa ! C’est pas encore fini. il y a quelque chose là-bas qui semble amusant. C’est peut être un jeu ! là où il y a un visage souriant, il nous fait signe de venir !!!" En effet, au bout de l’allée se tenait une sorte de machine qui jouait une petite musique. Je m'approche calmement contrairement à lui qui se précipite dessus. C'était une borne, le visage souriant qui apparaissait sur l'écran me demandait mon avis … Qu’est ce que j’étais supposé faire? Elle nous filmait en me demandant de faire un signe de la main pour savoir si j’avais apprécié mon séjour dans le parc. C'était un peu effrayant tout de même… Le message suivant s’affichait sur l'écran : "vous êtes filmés mais non enregistrés ". Avec retenu, je fis alors un geste avec la main pour signifier ma satisfaction. Mon fils, beaucoup plus à l’aise que moi, fit un cœur avec ses mains. Il était assez clair qu’il ne se souciait pas du tout de la caméra. Après cela, la borne produisit un éclat de sons, et afficha pleins de visages souriants sur son écran. Je m'apprêtais à partir lorsque la borne me demanda d’ajouter un commentaire vocal si j’en avais envie. Bien que j’étais réticent à l’idée de me faire filmer, j’ai quand même exprimé mon avis sur le parc en général, la diversité des attractions, la bienveillance de l’accueil, la disponibilité des employés. J’ai également fait remarquer qu’une des attractions devrait être rénovée car la devanture était assez vieille. La borne m'a remercié et nous sommes partis. - -Il faut avouer que c'était simple, ludique et assez attractif pour le coup. Cela me rappelle une borne qui existait dans mon enfance qui utilisait des boutons, qui s'avèrent être une méthode désuète, cela m'a incité alors à donner mon avis . - - -==== Scénario administrateur - -Gérante d’un parc d'attractions assez populaire dans le Nord de la France, Amélie est de plus en plus inquiète de sa situation. Son chiffre d'affaires ne fait que baisser depuis un an et elle craint de devoir mettre la clef sous la porte dans les prochains mois si elle ne trouve pas vite une solution. Elle a eu vent du récent succès de son concurrent de la ville d’à côté, un parc innovant et attractif qui ne fait que de s’étendre. Mais d’où peut bien venir un tel enclin des clients se demandait elle. Pour elle, son parc est pour le moins aussi bien que celui d’en face mais pourtant, certaines personnes seraient prêtes à faire des kilomètres en plus pour aller chez la concurrence. - -Un soir dans la semaine, elle en parle à son ami directeur d’un musée à Paris. Il lui conseille alors de savoir ce que pensent les clients de son parc en allant leur demander directement. Il lui parle d’un dispositif révolutionnaire qui recueille et analyse les commentaires laissés par les utilisateurs. C’est ce même système qui est disposé à l’accueil du musée et qui aide le pôle relation client à cibler les problèmes relevés par les visiteurs afin de les corriger et ainsi améliorer la visite. A première vue elle ne semble pas réellement emballée par ce système : les personnes accepteront elles de se faire filmer ? Son ami reconnaît que tous les visiteurs ne l’utilisent pas mais en les plaçant dans les lieux d’affluence, assez d’avis sont recueillis pour que le dispositif soit pertinent. - -Amélie décide alors d’utiliser ce dispositif et donc elle fait installer plusieurs bornes réparties un peu partout dans le parc, à certains endroits stratégiques, où l’affluence est assez importante pour maximiser le nombre de clients qui utiliseraient la machine. Elle met également en place tout un environnement attrayant autour de chacune d'entre elles pour favoriser la venue du client. Une bande sonore est également implémentée au sein de la borne pour qu’elle paraisse ludique et qu’elle attire l’attention du client. -Une semaine après la mise en place des dispositifs, les résultats sont impressionnants. Tout d’abord, le dispositif est assez utilisé par les usagers du parc pour pouvoir faire des statistiques. Le système traite par lui-même les informations qu’il collecte. Une analyse des enregistrements vocaux et vidéos permet de déterminer l’humeur du client. A l’issue de cette étape, seule la transcription écrite des enregistrements et les émotions sont récupérées, les autres données sont supprimées. Les avis collectées sont regroupés avec ceux laissés sur les réseaux sociaux pour former une base de commentaires. Une analyse sémantique est ensuite effectuée sur toutes les remarques pour repérer les mots clefs. Ceux recueillis par les bornes sont plus complets et plus pertinents car ils sont associés à une émotion ce qui va pouvoir séparer les avis profonds et construits des remarques véhémentes sans fondement par exemple. Les avis sont ensuite triés et organisés par thème et selon leur récurrence. Le système renvoie alors un classement des plaintes (la priorité des remarques est déduite de leur répétition et de l’émotion auxquelles elles sont associées : si un avis est associé à la colère par exemple, il doit être traité au plus vite). Sur l’interface, elle voit tout d’abord sur le côté gauche de son écran une jauge du bonheur lui indiquant l’émotion globale de ces usagers. A gauche de l’écran se trouve des nuages de mots clés dans des bulles de couleurs plus ou moins grosses selon leur importance (la couleur étant déterminée par l’émotion liée aux mots). Quand elle clique sur une des bulles, elle peut avoir accès à un commentaire global lui indiquant si le retour est positif ou négatif, et la liste des commentaires sur le sujet. - - - - - - +=== Scénarios d’usage + +==== Scénario Client + +Voilà déjà quatre heures que j’étais dans le parc d'attraction avec mon fils, on s'est beaucoup amusé, et le temps est passé si vite, mais il était temps de rentrer. J'étais plongé dans mes pensées lorsque mon fils s’écria : "Papa ! Papa ! C’est pas encore fini. il y a quelque chose là-bas qui semble amusant. C’est peut être un jeu ! là où il y a un visage souriant, il nous fait signe de venir !!!" En effet, au bout de l’allée se tenait une sorte de machine qui jouait une petite musique. Je m'approche calmement contrairement à lui qui se précipite dessus. C'était une borne, le visage souriant qui apparaissait sur l'écran me demandait mon avis … Qu’est ce que j’étais supposé faire? Elle nous filmait en me demandant de faire un signe de la main pour savoir si j’avais apprécié mon séjour dans le parc. C'était un peu effrayant tout de même… Le message suivant s’affichait sur l'écran : "vous êtes filmés mais non enregistrés ". Avec retenu, je fis alors un geste avec la main pour signifier ma satisfaction. Mon fils, beaucoup plus à l’aise que moi, fit un cœur avec ses mains. Il était assez clair qu’il ne se souciait pas du tout de la caméra. Après cela, la borne produisit un éclat de sons, et afficha pleins de visages souriants sur son écran. Je m'apprêtais à partir lorsque la borne me demanda d’ajouter un commentaire vocal si j’en avais envie. Bien que j’étais réticent à l’idée de me faire filmer, j’ai quand même exprimé mon avis sur le parc en général, la diversité des attractions, la bienveillance de l’accueil, la disponibilité des employés. J’ai également fait remarquer qu’une des attractions devrait être rénovée car la devanture était assez vieille. La borne m'a remercié et nous sommes partis. + +Il faut avouer que c'était simple, ludique et assez attractif pour le coup. Cela me rappelle une borne qui existait dans mon enfance qui utilisait des boutons, qui s'avèrent être une méthode désuète, cela m'a incité alors à donner mon avis . + + +==== Scénario administrateur + +Gérante d’un parc d'attractions assez populaire dans le Nord de la France, Amélie est de plus en plus inquiète de sa situation. Son chiffre d'affaires ne fait que baisser depuis un an et elle craint de devoir mettre la clef sous la porte dans les prochains mois si elle ne trouve pas vite une solution. Elle a eu vent du récent succès de son concurrent de la ville d’à côté, un parc innovant et attractif qui ne fait que de s’étendre. Mais d’où peut bien venir un tel enclin des clients se demandait elle. Pour elle, son parc est pour le moins aussi bien que celui d’en face mais pourtant, certaines personnes seraient prêtes à faire des kilomètres en plus pour aller chez la concurrence. + +Un soir dans la semaine, elle en parle à son ami directeur d’un musée à Paris. Il lui conseille alors de savoir ce que pensent les clients de son parc en allant leur demander directement. Il lui parle d’un dispositif révolutionnaire qui recueille et analyse les commentaires laissés par les utilisateurs. C’est ce même système qui est disposé à l’accueil du musée et qui aide le pôle relation client à cibler les problèmes relevés par les visiteurs afin de les corriger et ainsi améliorer la visite. A première vue elle ne semble pas réellement emballée par ce système : les personnes accepteront elles de se faire filmer ? Son ami reconnaît que tous les visiteurs ne l’utilisent pas mais en les plaçant dans les lieux d’affluence, assez d’avis sont recueillis pour que le dispositif soit pertinent. + +Amélie décide alors d’utiliser ce dispositif et donc elle fait installer plusieurs bornes réparties un peu partout dans le parc, à certains endroits stratégiques, où l’affluence est assez importante pour maximiser le nombre de clients qui utiliseraient la machine. Elle met également en place tout un environnement attrayant autour de chacune d'entre elles pour favoriser la venue du client. Une bande sonore est également implémentée au sein de la borne pour qu’elle paraisse ludique et qu’elle attire l’attention du client. +Une semaine après la mise en place des dispositifs, les résultats sont impressionnants. Tout d’abord, le dispositif est assez utilisé par les usagers du parc pour pouvoir faire des statistiques. Le système traite par lui-même les informations qu’il collecte. Une analyse des enregistrements vocaux et vidéos permet de déterminer l’humeur du client. A l’issue de cette étape, seule la transcription écrite des enregistrements et les émotions sont récupérées, les autres données sont supprimées. Les avis collectées sont regroupés avec ceux laissés sur les réseaux sociaux pour former une base de commentaires. Une analyse sémantique est ensuite effectuée sur toutes les remarques pour repérer les mots clefs. Ceux recueillis par les bornes sont plus complets et plus pertinents car ils sont associés à une émotion ce qui va pouvoir séparer les avis profonds et construits des remarques véhémentes sans fondement par exemple. Les avis sont ensuite triés et organisés par thème et selon leur récurrence. Le système renvoie alors un classement des plaintes (la priorité des remarques est déduite de leur répétition et de l’émotion auxquelles elles sont associées : si un avis est associé à la colère par exemple, il doit être traité au plus vite). Sur l’interface, elle voit tout d’abord sur le côté gauche de son écran une jauge du bonheur lui indiquant l’émotion globale de ces usagers. A gauche de l’écran se trouve des nuages de mots clés dans des bulles de couleurs plus ou moins grosses selon leur importance (la couleur étant déterminée par l’émotion liée aux mots). Quand elle clique sur une des bulles, elle peut avoir accès à un commentaire global lui indiquant si le retour est positif ou négatif, et la liste des commentaires sur le sujet. + + + + + +