Cumuler plusieurs compteurs
Fermé
corentin.bc
Messages postés
383
Date d'inscription
dimanche 8 février 2015
Statut
Membre
Dernière intervention
4 novembre 2022
-
Modifié par baladur13 le 27/01/2017 à 23:00
Flachy Joe Messages postés 2103 Date d'inscription jeudi 16 septembre 2004 Statut Membre Dernière intervention 21 novembre 2023 - 30 janv. 2017 à 22:22
Flachy Joe Messages postés 2103 Date d'inscription jeudi 16 septembre 2004 Statut Membre Dernière intervention 21 novembre 2023 - 30 janv. 2017 à 22:22
A voir également:
- Cumuler plusieurs compteurs
- Cumuler pdf - Guide
- Cumuler astra et fransat ? - Forum TNT / Satellite / Réception
- Compteurs d'abonnés bloqués sur youtube - Forum YouTube
- Les compteurs de pas du genre WeWard - Forum Téléphones & tablettes Android
- Comment bloquer les nouveaux compteurs d'eau - Forum Programmation
11 réponses
yg_be
Messages postés
23406
Date d'inscription
lundi 9 juin 2008
Statut
Contributeur
Dernière intervention
25 décembre 2024
Ambassadeur
1 557
25 janv. 2017 à 23:26
25 janv. 2017 à 23:26
bonsoir, ton code est particulièrement illisible.
tu souhaites "cumuler" les différents fichiers, ou bien les lire un par un et afficher le nombre total de visiteurs?
tu as un soucis particulier, qu'est-ce qui te bloque?
es-tu certain de ne pas vouloir utiliser une base de données pour stocher toutes ces information?
tu souhaites "cumuler" les différents fichiers, ou bien les lire un par un et afficher le nombre total de visiteurs?
tu as un soucis particulier, qu'est-ce qui te bloque?
es-tu certain de ne pas vouloir utiliser une base de données pour stocher toutes ces information?
corentin.bc
Messages postés
383
Date d'inscription
dimanche 8 février 2015
Statut
Membre
Dernière intervention
4 novembre 2022
8
27 janv. 2017 à 07:11
27 janv. 2017 à 07:11
Salut,
euh oui pour la BDD, je préfère continuer avec les fichiers.
Je veux lire les fichiers un par un puis afficher le nombre total de visiteurs.
euh oui pour la BDD, je préfère continuer avec les fichiers.
Je veux lire les fichiers un par un puis afficher le nombre total de visiteurs.
yg_be
Messages postés
23406
Date d'inscription
lundi 9 juin 2008
Statut
Contributeur
Dernière intervention
25 décembre 2024
1 557
27 janv. 2017 à 09:26
27 janv. 2017 à 09:26
bonjour, tu as un soucis particulier, qu'est-ce qui te bloque?
tu cherches comment parcourir tous les fichiers, comment en lire un, ...?
tu cherches comment parcourir tous les fichiers, comment en lire un, ...?
corentin.bc
Messages postés
383
Date d'inscription
dimanche 8 février 2015
Statut
Membre
Dernière intervention
4 novembre 2022
8
27 janv. 2017 à 12:50
27 janv. 2017 à 12:50
Comment récupérer dans chaque ficheirs le nombre de visiteurs y compris cleui de cette année et créer la variable correspondante.
En gros je sais rien faire sauf l'affichage de la variable.
En gros je sais rien faire sauf l'affichage de la variable.
yg_be
Messages postés
23406
Date d'inscription
lundi 9 juin 2008
Statut
Contributeur
Dernière intervention
25 décembre 2024
1 557
27 janv. 2017 à 13:49
27 janv. 2017 à 13:49
c'est toi qui a écrit le code que tu as montré?
corentin.bc
Messages postés
383
Date d'inscription
dimanche 8 février 2015
Statut
Membre
Dernière intervention
4 novembre 2022
8
27 janv. 2017 à 14:16
27 janv. 2017 à 14:16
Non, on me l'a passé.
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre question
Utilisateur anonyme
Modifié par baladur13 le 27/01/2017 à 22:59
Modifié par baladur13 le 27/01/2017 à 22:59
Afin que ça soit lisible pour les autres:
/* Si le fichier où l'on stock, les données n'existe pas encore on le crée.*/ $year = date("y"); $fichier = '.htcompteur'; $fichier = $fichier . $year; if( !file_exists($fichier) ) { $fp = fopen($fichier, "w"); fwrite($fp, serialize(array())); fclose($fp); } /* Définition de variables nécessaire au compteur : - deux termes constants, - l'ip du visiteur, - la date et l'heure. */ $argument_visites = 'visites'; $argument_requêtes = 'requêtes'; $ip = $_SERVER['REMOTE_ADDR']; $time = date('YmdGis'); /* Récupération des données du compteur précédemment stockées. */ $lignes = file($fichier) or die('Un problème est survenu, le compteur ne peut pas s\'afficher'); $donnees = unserialize($lignes[0]); /* Pour chaque clé du tableau de données qui ne soit pas attribuée aux visites et aux requêtes si la valeur correspond à une date antérieure au même jour, on supprime l'ip du visiteur. */ foreach( $donnees as $cle => $valeur ){ if( substr($valeur, 0, 8) != substr($time, 0, 8) && $cle != $argument_visites && $cle != $argument_requêtes ) { unset($donnees[$cle]); } } /** On incrémente ( ajoute +1 ) la valeur* du nombre de requêtes. Si l'ip n'est pas encore enregistrée, on incrémente la valeur du nombre de visites et on ajoute l'ip dans le tableau accompagné de la date et de l'heure de l'exécution. */ $donnees[$argument_requêtes]++; if( !$donnees[$ip] ) { $donnees[$argument_visites]++; $donnees[$ip] = $time; } /** On effectue un petit report de variable* pour une utilisation ultérieur plus aisée.*/ $nb_visiteurs = $donnees[$argument_visites]; $nb_aujourdhui = count($donnees)-2; $nb_requêtes = $donnees[$argument_requêtes]; /** On stock le tableau dans le fichier de données* en écrasant sa valeur précédente.*/ $fp = fopen($fichier,"wb"); fwrite($fp, serialize($donnees)); fclose($fp); /* On affiche les résultats du compteur.*/ if ($nb_visiteurs == '1') { print $nb_visiteurs. " visiteur depuis le 01/01/20"; } else { print $nb_visiteurs. " visiteurs depuis le 01/01/20"; } print $year." dont "; print $nb_aujourdhui. " aujourd'hui, "; if ($nb_requêtes == '1') { print $nb_requêtes. " page chargée.<br />"; } else { print $nb_requêtes. " pages chargées.<br />"; } if($bdd = mysqli_connect('localhost', 'xxxx', 'yyyyy', 'zzzz')) { } else { echo 'Erreur'; } $donnees = $bdd->query('SELECT COUNT(*) AS nbre_entrees FROM connectes WHERE ip=\'' . $_SERVER['REMOTE_ADDR'] . '\'')->fetch_array(); if ($donnees['nbre_entrees'] == 0) { $bdd->query('INSERT INTO connectes VALUES(\'' . $_SERVER['REMOTE_ADDR'] . '\', ' . time() . ')'); } else { $bdd->query('UPDATE connectes SET timestamp=' . time() . ' WHERE ip=\'' . $_SERVER['REMOTE_ADDR'] . '\''); } $timestamp_5min = time() - (60 * 5); $bdd->query('DELETE FROM connectes WHERE timestamp < ' . $timestamp_5min); $donnees = $bdd->query('SELECT COUNT(*) AS nbre_entrees FROM connectes')->fetch_array(); if ($donnees["nbre_entrees"] == '1') { print $donnees["nbre_entrees"]. " connecté en ce moment !"; } else { print $donnees["nbre_entrees"]. " connectés en ce moment !"; }
Déjà ton code peut-être largement optimisé, comme quand tu veux mettre au pluriel ou éviter les if vide et mettre un else pour faire la condition contraire alors qu'un ! suffit.
Et aussi évite les accents pour les noms de variable car il suffit d'un mauvais encodage pour faire planter le script.
Sinon il faut que tu englobes ton scripts dans une fonction, utiliser la fonction glob pour récupérer tes fichiers et une boucle foreach pour exécuter le code sur chaque fichier.
Et aussi évite les accents pour les noms de variable car il suffit d'un mauvais encodage pour faire planter le script.
Sinon il faut que tu englobes ton scripts dans une fonction, utiliser la fonction glob pour récupérer tes fichiers et une boucle foreach pour exécuter le code sur chaque fichier.
corentin.bc
Messages postés
383
Date d'inscription
dimanche 8 février 2015
Statut
Membre
Dernière intervention
4 novembre 2022
8
29 janv. 2017 à 15:52
29 janv. 2017 à 15:52
Salut,
wow, ok, mais je ne sais pas du tout faire tout ça !
COmme je l'ai dis je ne suis pas l'auteur de ce code, je m'y connais vraiment très peu en php et j'ai pas encore eus le temps de l'apprendre.
Peux-tu me donner un exemple ou m'expliquer comment faire dans mon code stp ?
Merci.
wow, ok, mais je ne sais pas du tout faire tout ça !
COmme je l'ai dis je ne suis pas l'auteur de ce code, je m'y connais vraiment très peu en php et j'ai pas encore eus le temps de l'apprendre.
Peux-tu me donner un exemple ou m'expliquer comment faire dans mon code stp ?
Merci.
Ouep enfin il suffit de rechercher un peu sur Internet pour trouver la réponse vu que je t'ai donné les fonctions à utiliser. Il faut t'y mettre au PHP au lieu de demander gratuitement à tout le monde de le faire à ta place, car déjà tu n'apprend rien, ensuite un jour on y implantera une backdoor ou une erreur qui peut tout faire planter et tu comprendras pas pourquoi car tu n'auras pas vérifier le script.
yg_be
Messages postés
23406
Date d'inscription
lundi 9 juin 2008
Statut
Contributeur
Dernière intervention
25 décembre 2024
Ambassadeur
1 557
29 janv. 2017 à 16:48
29 janv. 2017 à 16:48
Je propose d'ajouter ceci avant le commentaire
/* On affiche les résultats du compteur.*/
foreach (glob(".htcompteur.*") as $ancienfichier) { if ! ( $ancienfichier == $fichier ) { $lignes = file($ancienfichier) or die('Un problème est survenu avec '. $ancienfichier); $donnees = unserialize($lignes[0]); $nb_visiteurs = $nb_visiteurs + $donnees[$argument_visites]; $nb_requêtes = $nb_requêtes + $donnees[$argument_requêtes]; } }
corentin.bc
Messages postés
383
Date d'inscription
dimanche 8 février 2015
Statut
Membre
Dernière intervention
4 novembre 2022
8
29 janv. 2017 à 18:53
29 janv. 2017 à 18:53
@ZeNairolf ouais, mais je te l'ai dis j'ai pas le temps, déjà le collège toute la semaine alors le weekend je prend pas le temps de m'y mettre.
@yg_be merci mais ça ne fonctionne pas.
@yg_be merci mais ça ne fonctionne pas.
yg_be
Messages postés
23406
Date d'inscription
lundi 9 juin 2008
Statut
Contributeur
Dernière intervention
25 décembre 2024
1 557
29 janv. 2017 à 19:15
29 janv. 2017 à 19:15
et ceci affiche quoi?
echo 'avant foreach glob <br>'; foreach (glob(".htcompteur.*") as $ancienfichier) { echo 'ancienfichier: '. $ancienfichier .'<br>'; if ! ( $ancienfichier == $fichier ) { echo 'traitement ancienfichier: '. $ancienfichier .'<br>'; $lignes = file($ancienfichier) or die('Un problème est survenu avec '. $ancienfichier); $donnees = unserialize($lignes[0]); $nb_visiteurs = $nb_visiteurs + $donnees[$argument_visites]; $nb_requêtes = $nb_requêtes + $donnees[$argument_requêtes]; } } echo 'après foreach glob <br>';
corentin.bc
Messages postés
383
Date d'inscription
dimanche 8 février 2015
Statut
Membre
Dernière intervention
4 novembre 2022
8
29 janv. 2017 à 20:45
29 janv. 2017 à 20:45
Rien du tout :(
yg_be
Messages postés
23406
Date d'inscription
lundi 9 juin 2008
Statut
Contributeur
Dernière intervention
25 décembre 2024
1 557
29 janv. 2017 à 21:02
29 janv. 2017 à 21:02
Et donc, avant que tu ajoutes mon code, cela affichait les statistiques d'une année, et maintenant, avec mon code ajouté, cela n'affiche plus rien?
Peux-tu montrer le code complet?
Peux-tu montrer le code complet?
corentin.bc
Messages postés
383
Date d'inscription
dimanche 8 février 2015
Statut
Membre
Dernière intervention
4 novembre 2022
8
Modifié par jordane45 le 29/01/2017 à 22:11
Modifié par jordane45 le 29/01/2017 à 22:11
Aucun souci :
Amicalement! Corentin.
<?php // Si le fichier où l'on stock,* les données n'existe pas encore* on le crée.*/ $year = date("y"); $fichier = '.htcompteur'; $fichier = $fichier . $year; if( !file_exists($fichier) ) { $fp = fopen($fichier, "w"); fwrite($fp, serialize(array())); fclose($fp); } /** Définition de variables* nécessaire au compteur :* - deux termes constants,* - l'ip du visiteur,* - la date et l'heure.*/ $argument_visites = 'visites'; $argument_requêtes = 'requêtes'; $ip = $_SERVER['REMOTE_ADDR']; $time = date('YmdGis'); /** Récupération des données du* compteur précédemment stockées.*/ $lignes = file($fichier) or die('Un problème est survenu, le compteur ne peut pas s\'afficher'); $donnees = unserialize($lignes[0]); /** Pour chaque clé du tableau de données* qui ne soit pas attribuée aux visites et aux requêtes* si la valeur correspond à une date antérieure* au même jour, on supprime l'ip du visiteur.*/ foreach( $donnees as $cle => $valeur ){ if( substr($valeur, 0, 8) != substr($time, 0, 8) && $cle != $argument_visites && $cle != $argument_requêtes ) { unset($donnees[$cle]); }}/** On incrémente ( ajoute +1 ) la valeur* du nombre de requêtes.* Si l'ip n'est pas encore enregistrée,* on incrémente la valeur du nombre de visites* et on ajoute l'ip dans le tableau accompagné* de la date et de l'heure de l'exécution.*/ $donnees[$argument_requêtes]++; if( !$donnees[$ip] ) { $donnees[$argument_visites]++; $donnees[$ip] = $time; } /** On effectue un petit report de variable* pour une utilisation ultérieur plus aisée.*/ $nb_visiteurs = $donnees[$argument_visites]; $nb_aujourdhui = count($donnees)-2; $nb_requêtes = $donnees[$argument_requêtes]; /** On stock le tableau dans le fichier de données* en écrasant sa valeur précédente.*/ $fp = fopen($fichier,"wb"); fwrite($fp, serialize($donnees)); fclose($fp); echo 'avant foreach glob <br>'; foreach (glob(".htcompteur.*") as $ancienfichier){ echo 'ancienfichier: '. $ancienfichier .'<br>'; if ! ( $ancienfichier == $fichier ) { echo 'traitement ancienfichier: '. $ancienfichier .'<br>'; $lignes = file($ancienfichier) or die('Un problème est survenu avec '. $ancienfichier); $donnees = unserialize($lignes[0]); $nb_visiteurs = $nb_visiteurs + $donnees[$argument_visites]; $nb_requêtes = $nb_requêtes + $donnees[$argument_requêtes]; }}echo 'après foreach glob <br>'; /** On affiche les résultats du compteur.*/ if ($nb_visiteurs == '1') {print $nb_visiteurs. " visiteur depuis le 01/01/20"; } else {print $nb_visiteurs. " visiteurs depuis le 01/01/20"; } print $year." dont "; print $nb_aujourdhui. " aujourd'hui, "; if ($nb_requêtes == '1') {print $nb_requêtes. " page chargée.<br />"; } else {print $nb_requêtes. " pages chargées.<br />"; } ?> try{ $requete="SELECT * FROM administrateur"; $query=sqlsrv_query($conn, $requete); while($donnees=sqlsrv_fetch_array($query)){ if($donnees['username']===$username && $donnees['Motd_passe']===$Motd_passe){ session_start(); $_SESSION['id']=$donnees['id']; $_SESSION['admin']=$username; header("Location: /admin/ordinateur/index.php"); } } sqlsrv_free_stmt($query); }catch(Exception $e){ die('Erreur '.$e->getMessage()); } } sqlsrv_close($query);
EDIT : Ajout des balises de code (encore.....) !
.Amicalement! Corentin.
jordane45
Messages postés
38347
Date d'inscription
mercredi 22 octobre 2003
Statut
Modérateur
Dernière intervention
24 décembre 2024
4 719
Modifié par jordane45 le 29/01/2017 à 22:16
Modifié par jordane45 le 29/01/2017 à 22:16
Bonjour,
Je me permet juste quelques remarques :
1 - Merci de poster ton code AVEC les balises de code (et en faisant de l'indentation...)
(je viens de le faire pour toi encore une fois....)
2 - Tu corrigeras le bout de code :
Par celui que nous t'avons donné dans ton autre discussion .....
3 - Comme cela t'a été indiqué ... N'utilise pas de caractères accentués comme "noms de variables"
4 - Active l'affichage des erreurs PHP. (voir mes messages dans tes questions précédentes...)
Je me permet juste quelques remarques :
1 - Merci de poster ton code AVEC les balises de code (et en faisant de l'indentation...)
(je viens de le faire pour toi encore une fois....)
2 - Tu corrigeras le bout de code :
try{ $requete="SELECT * FROM administrateur"; $query=sqlsrv_query($conn, $requete); while($donnees=sqlsrv_fetch_array($query)){ if($donnees['username']===$username && $donnees['Motd_passe']===$Motd_passe){ session_start(); $_SESSION['id']=$donnees['id']; $_SESSION['admin']=$username; header("Location: /admin/ordinateur/index.php"); } } sqlsrv_free_stmt($query); }catch(Exception $e){ die('Erreur '.$e->getMessage()); } } sqlsrv_close($query);
Par celui que nous t'avons donné dans ton autre discussion .....
3 - Comme cela t'a été indiqué ... N'utilise pas de caractères accentués comme "noms de variables"
4 - Active l'affichage des erreurs PHP. (voir mes messages dans tes questions précédentes...)
yg_be
Messages postés
23406
Date d'inscription
lundi 9 juin 2008
Statut
Contributeur
Dernière intervention
25 décembre 2024
1 557
29 janv. 2017 à 22:55
29 janv. 2017 à 22:55
Et si tu retires le code que je t'ai proposé, cela affiche de nouveau les statistiques d'une année?
corentin.bc
Messages postés
383
Date d'inscription
dimanche 8 février 2015
Statut
Membre
Dernière intervention
4 novembre 2022
8
30 janv. 2017 à 19:45
30 janv. 2017 à 19:45
Oui.
yg_be
Messages postés
23406
Date d'inscription
lundi 9 juin 2008
Statut
Contributeur
Dernière intervention
25 décembre 2024
1 557
30 janv. 2017 à 20:04
30 janv. 2017 à 20:04
Et ainsi?
echo 'avant foreach glob <br />'; foreach (glob(".htcompteur.*") as $ancienfichier) { echo 'ancienfichier: '. $ancienfichier .'<br />'; if ! ( $ancienfichier == $fichier ) { echo 'traitement ancienfichier: '. $ancienfichier .'<br />'; $lignes = file($ancienfichier) or die('Un problème est survenu avec '. $ancienfichier); $donnees = unserialize($lignes[0]); $nb_visiteurs = $nb_visiteurs + $donnees[$argument_visites]; $nb_requêtes = $nb_requêtes + $donnees[$argument_requêtes]; } } echo 'après foreach glob <br />';
Flachy Joe
Messages postés
2103
Date d'inscription
jeudi 16 septembre 2004
Statut
Membre
Dernière intervention
21 novembre 2023
260
Modifié par Flachy Joe le 30/01/2017 à 22:37
Modifié par Flachy Joe le 30/01/2017 à 22:37
yg_be, ton code fonctionne presque :
ligne 5
Pour résumer :
Les ip n'étant lues que dans le fichier de l'année en cours, ceux qui reviennent sur la page après un changement d'année sont comptés plusieurs fois.
A mon avis, puisqu'il y a une base de donnée, on pourrait envoyer le contenu des fichiers dedans une fois pour toute et gérer les 2 compteurs en SQL.
ligne 5
if ( $ancienfichier != $fichier )
Pour résumer :
<?php header('Content-Type: text/html; charset=utf-8'); ini_set('display_errors', 'On'); error_reporting(E_ALL); /* * Si le fichier où l'on stock, * les données n'existe pas encore * on le crée.*/ $year = date("y"); $fichier = '.htcompteur'; $fichier = $fichier . $year; if( !file_exists($fichier) ) { $fp = fopen($fichier, "w"); fwrite($fp, serialize(array())); fclose($fp); } /** Définition de variables * nécessaire au compteur : * - deux termes constants, * - l'ip du visiteur, * - la date et l'heure.*/ $argument_visites = 'visites'; $argument_requetes = 'requêtes'; $ip = $_SERVER['REMOTE_ADDR']; $time = date('YmdGis'); /** Récupération des données du * compteur précédemment stockées.*/ $lignes = file($fichier) or die('Un problème est survenu, le compteur ne peut pas s\'afficher'); $donnees = unserialize($lignes[0]); /** Pour chaque clé du tableau de données * qui ne soit pas attribuée aux visites et aux requêtes * si la valeur correspond à une date antérieure * au même jour, on supprime l'ip du visiteur.*/ foreach( $donnees as $cle => $valeur ){ if( substr($valeur, 0, 8) != substr($time, 0, 8) && $cle != $argument_visites && $cle != $argument_requetes ) { unset($donnees[$cle]); } } /** On incrémente ( ajoute +1 ) la valeur * du nombre de requêtes. * Si l'ip n'est pas encore enregistrée, * on incrémente la valeur du nombre de visites * et on ajoute l'ip dans le tableau accompagné * de la date et de l'heure de l'exécution.*/ $donnees[$argument_requetes]++; if( !$donnees[$ip] ) { $donnees[$argument_visites]++; $donnees[$ip] = $time; } /** On effectue un petit report de variable * pour une utilisation ultérieur plus aisée.*/ $nb_visiteurs = $donnees[$argument_visites]; $nb_aujourdhui = count($donnees)-2; $nb_requetes = $donnees[$argument_requetes]; /** On stock le tableau dans le fichier de données * en écrasant sa valeur précédente.*/ $fp = fopen($fichier,"wb"); fwrite($fp, serialize($donnees)); fclose($fp); /** Lecture des années précédentes **/ foreach (glob(".htcompteur*") as $ancienfichier) { if ( $ancienfichier != $fichier ){ $lignes = file($ancienfichier) or die('Un problème est survenu avec '. $ancienfichier); $donnees = unserialize($lignes[0]); $nb_visiteurs = $nb_visiteurs + $donnees[$argument_visites]; $nb_requetes = $nb_requetes + $donnees[$argument_requetes]; } } /** On affiche les résultats du compteur.*/ print $nb_visiteurs. " visiteur".($nb_visiteurs>1?'s':'')." depuis le 01/01/20".$year; print " dont ".$nb_aujourdhui. " aujourd'hui, "; print $nb_requetes. " pages chargée".($nb_requetes>1?'s':'').".<br />"; /** Compteur des connectés **/ $bdd = mysqli_connect('localhost', 'xxxx', 'yyyy', 'zzzzz') or die('Erreur de connexion à la BDD'); $donnees = $bdd->query('SELECT COUNT(*) AS nbre_entrees FROM connectes WHERE ip=\'' . $_SERVER['REMOTE_ADDR'] . '\'')->fetch_array(); if ($donnees['nbre_entrees'] == 0){ $bdd->query('INSERT INTO connectes VALUES(\'' . $_SERVER['REMOTE_ADDR'] . '\', ' . time() . ')'); }else{ $bdd->query('UPDATE connectes SET timestamp=' . time() . ' WHERE ip=\'' . $_SERVER['REMOTE_ADDR'] . '\''); } $timestamp_5min = time() - (60 * 5); $bdd->query('DELETE FROM connectes WHERE timestamp < ' . $timestamp_5min); $donnees = $bdd->query('SELECT COUNT(*) AS nbre_entrees FROM connectes')->fetch_array(); print $donnees["nbre_entrees"]. " connecté".($nb_entrees>1?'s':'')." en ce moment !"; ?>
Les ip n'étant lues que dans le fichier de l'année en cours, ceux qui reviennent sur la page après un changement d'année sont comptés plusieurs fois.
A mon avis, puisqu'il y a une base de donnée, on pourrait envoyer le contenu des fichiers dedans une fois pour toute et gérer les 2 compteurs en SQL.