premier poc
This commit is contained in:
commit
f68d2ac333
2208 changed files with 731809 additions and 0 deletions
119
Lib/Discriminant/AlertAnalyzer.php
Normal file
119
Lib/Discriminant/AlertAnalyzer.php
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Classifier\Lib\Discriminant;
|
||||
|
||||
use Classifier\Lib\Utils\StringCleaner;
|
||||
|
||||
class AlertAnalyzer
|
||||
{
|
||||
/**
|
||||
* Seuil de confiance pour déclencher une alerte (0.0 à 1.0)
|
||||
*/
|
||||
public const CONFIDENCE_THRESHOLD = 0.75;
|
||||
|
||||
/**
|
||||
* Seuil de similarité pour les mots simples (0.0 à 1.0)
|
||||
*/
|
||||
private const SIMILARITY_THRESHOLD = 0.85;
|
||||
|
||||
/** @var WhiteList */
|
||||
private $whiteList;
|
||||
|
||||
/** @var BlackList */
|
||||
private $blackList;
|
||||
|
||||
/** @var StringCleaner */
|
||||
private $cleaner;
|
||||
|
||||
/** @var int */
|
||||
private $activationThreshold;
|
||||
|
||||
public function __construct(
|
||||
WhiteList $whiteList,
|
||||
BlackList $blackList,
|
||||
StringCleaner $cleaner,
|
||||
int $activationThreshold = 100
|
||||
) {
|
||||
$this->whiteList = $whiteList;
|
||||
$this->blackList = $blackList;
|
||||
$this->cleaner = $cleaner;
|
||||
$this->activationThreshold = $activationThreshold;
|
||||
}
|
||||
|
||||
public function analyze(string $rawText): AnalyzeResult
|
||||
{
|
||||
$cleanChain = $this->cleaner->getCleanChain($rawText);
|
||||
$words = $this->cleaner->preprocessMessage($rawText);
|
||||
|
||||
$totalScore = 0.0;
|
||||
$found = [];
|
||||
|
||||
foreach ($this->whiteList->getKeywords() as $keyword => $weight) {
|
||||
// * Nettoyage rapide du mot-clé lui-même (au cas où il ait des accents)
|
||||
$cleanKeyword = $this->cleaner->getCleanChain($keyword);
|
||||
|
||||
if (strpos($cleanKeyword, ' ') !== false) {
|
||||
// * RECHERCHE DE MOTS COMPOSÉS (Exacte ou Fuzzy sur chaîne)
|
||||
if (mb_strpos($cleanChain, $cleanKeyword) !== false) {
|
||||
$totalScore += $weight;
|
||||
$found[] = $keyword;
|
||||
}
|
||||
} else {
|
||||
// * RECHERCHE DE MOT SIMPLE (Fuzzy Levenshtein)
|
||||
$similarity = $this->findBestSimilarity($cleanKeyword, $words);
|
||||
if ($similarity > self::SIMILARITY_THRESHOLD) {
|
||||
$totalScore += ($weight * $similarity);
|
||||
$found[] = $keyword;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->blackList->getKeywords() as $badWord) {
|
||||
if (mb_strpos($cleanChain, $this->cleaner->getCleanChain($badWord)) !== false) {
|
||||
return new AnalyzeResult(
|
||||
0.0,
|
||||
0.0,
|
||||
false,
|
||||
true,
|
||||
"Blacklist : {$badWord}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Si le score dépasse le seuil, la confiance est de 100% (1.0)
|
||||
$confidence = min(1.0, $totalScore / $this->activationThreshold);
|
||||
|
||||
return new AnalyzeResult(
|
||||
round($confidence, 2),
|
||||
$totalScore,
|
||||
$confidence >= self::CONFIDENCE_THRESHOLD,
|
||||
false,
|
||||
!empty($found) ?
|
||||
'Keywords found: ' . implode(', ', $found) :
|
||||
'No keywords found',
|
||||
$found
|
||||
);
|
||||
}
|
||||
|
||||
private function findBestSimilarity(string $keyword, array $words): float
|
||||
{
|
||||
$best = 0.0;
|
||||
foreach ($words as $word) {
|
||||
$dist = levenshtein($keyword, $word);
|
||||
$maxLen = max(strlen($keyword), strlen($word));
|
||||
if ($maxLen === 0) {
|
||||
continue;
|
||||
}
|
||||
$sim = 1 - ($dist / $maxLen);
|
||||
if ($sim > $best) {
|
||||
$best = $sim;
|
||||
}
|
||||
if ($best == 1.0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $best;
|
||||
}
|
||||
}
|
||||
44
Lib/Discriminant/AnalyzeResult.php
Normal file
44
Lib/Discriminant/AnalyzeResult.php
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Classifier\Lib\Discriminant;
|
||||
|
||||
class AnalyzeResult
|
||||
{
|
||||
// FIXME : php8.1 readonly props
|
||||
|
||||
/** @var float */
|
||||
public $score;
|
||||
|
||||
/** @var float */
|
||||
public $rawScore;
|
||||
|
||||
/** @var bool */
|
||||
public $isAlert;
|
||||
|
||||
/** @var bool */
|
||||
public $isBlacklisted;
|
||||
|
||||
/** @var string */
|
||||
public $reason;
|
||||
|
||||
/** @var string[] */
|
||||
public $keywordsFound;
|
||||
|
||||
public function __construct(
|
||||
float $score,
|
||||
float $rawScore,
|
||||
bool $isAlert,
|
||||
bool $isBlacklisted = false,
|
||||
string $reason = '',
|
||||
array $keywordsFound = []
|
||||
) {
|
||||
$this->score = $score;
|
||||
$this->rawScore = $rawScore;
|
||||
$this->isAlert = $isAlert;
|
||||
$this->isBlacklisted = $isBlacklisted;
|
||||
$this->reason = $reason;
|
||||
$this->keywordsFound = $keywordsFound;
|
||||
}
|
||||
}
|
||||
39
Lib/Discriminant/BlackList.php
Normal file
39
Lib/Discriminant/BlackList.php
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Classifier\Lib\Discriminant;
|
||||
|
||||
use Classifier\Lib\Utils\StringCleaner;
|
||||
|
||||
class BlackList
|
||||
{
|
||||
/** @var string[] */
|
||||
private $keywords;
|
||||
|
||||
public function __construct(array $keywords, StringCleaner $cleaner)
|
||||
{
|
||||
$this->keywords = [];
|
||||
|
||||
foreach ($keywords as $keyword) {
|
||||
$cleanedKeyword = $cleaner->getCleanChain($keyword);
|
||||
|
||||
if (!is_string($cleanedKeyword) || preg_match('/\s/', $cleanedKeyword)) {
|
||||
throw new \InvalidArgumentException(
|
||||
"Erreur : Les mots-clés de la blacklist doivent être des chaînes de caractères simples (sans espaces) '{$cleanedKeyword}'."
|
||||
);
|
||||
}
|
||||
$this->keywords[] = $cleanedKeyword;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne la liste des mots-clés de la blacklist
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getKeywords(): array
|
||||
{
|
||||
return $this->keywords;
|
||||
}
|
||||
}
|
||||
46
Lib/Discriminant/WhiteList.php
Normal file
46
Lib/Discriminant/WhiteList.php
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Classifier\Lib\Discriminant;
|
||||
|
||||
use Classifier\Lib\Utils\StringCleaner;
|
||||
|
||||
class WhiteList
|
||||
{
|
||||
/** @var array<string,int> */
|
||||
private $keywords;
|
||||
|
||||
public function __construct(array $keywords, StringCleaner $cleaner)
|
||||
{
|
||||
foreach ($keywords as $keyword => $score) {
|
||||
$cleanedKeyword = $cleaner->getCleanChain($keyword);
|
||||
|
||||
if (!is_string($cleanedKeyword) || preg_match('/\s/', $cleanedKeyword)) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Erreur : Les mots-clés de la whitelist doivent être des chaînes de caractères simples (sans espaces).'
|
||||
);
|
||||
}
|
||||
|
||||
if (!is_numeric($score) || $score < 0) {
|
||||
throw new \InvalidArgumentException(
|
||||
"Erreur : Le score pour le mot-clé '{$cleanedKeyword}' doit être un nombre positif."
|
||||
);
|
||||
}
|
||||
|
||||
$keywords[$cleanedKeyword] = (int)$score;
|
||||
}
|
||||
|
||||
$this->keywords = $keywords;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne la liste des mots-clés avec leurs poids associés
|
||||
*
|
||||
* @return array<string,int>
|
||||
*/
|
||||
public function getKeywords(): array
|
||||
{
|
||||
return $this->keywords;
|
||||
}
|
||||
}
|
||||
17
Lib/Enum/ClassificationMethod.php
Normal file
17
Lib/Enum/ClassificationMethod.php
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Classifier\Lib;
|
||||
|
||||
use MyCLabs\Enum\Enum;
|
||||
|
||||
/**
|
||||
* @method static ClassificationMethod MACHINE()
|
||||
* @method static ClassificationMethod DICTIONARY()
|
||||
*/
|
||||
final class ClassificationMethod extends Enum
|
||||
{
|
||||
private const MACHINE = 'MACHINE';
|
||||
private const DICTIONARY = 'DICTIONARY';
|
||||
}
|
||||
19
Lib/Enum/MessageType.php
Normal file
19
Lib/Enum/MessageType.php
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Classifier\Lib\Enum;
|
||||
|
||||
use MyCLabs\Enum\Enum;
|
||||
|
||||
/**
|
||||
* @method static MessageType ALERTE()
|
||||
* @method static MessageType INFO()
|
||||
* @method static MessageType DOUBT()
|
||||
*/
|
||||
final class MessageType extends Enum
|
||||
{
|
||||
private const ALERTE = 'ALERTE';
|
||||
private const INFO = 'INFO';
|
||||
private const DOUBT = 'DOUTE_HUMAIN';
|
||||
}
|
||||
76
Lib/MessageClassificationResult.php
Normal file
76
Lib/MessageClassificationResult.php
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Classifier\Lib;
|
||||
|
||||
use Classifier\Lib\ClassificationMethod;
|
||||
use Classifier\Lib\Enum\MessageType;
|
||||
|
||||
class MessageClassificationResult
|
||||
{
|
||||
// FIXME : php8.1 readonly props
|
||||
|
||||
/** @var MessageType */
|
||||
public $decision;
|
||||
|
||||
/** @var ClassificationMethod */
|
||||
public $method;
|
||||
|
||||
/** @var float */
|
||||
public $confidence;
|
||||
|
||||
/** @var array<string,float> */
|
||||
private $details;
|
||||
|
||||
/** @var MessageType|null */
|
||||
public $machineDecision;
|
||||
|
||||
public function __construct(
|
||||
MessageType $decision,
|
||||
ClassificationMethod $method,
|
||||
float $confidence,
|
||||
array $details = [],
|
||||
?MessageType $machineDecision = null
|
||||
) {
|
||||
$this->decision = $decision;
|
||||
$this->method = $method;
|
||||
$this->confidence = $confidence;
|
||||
$this->details = $details;
|
||||
$this->machineDecision = $machineDecision;
|
||||
|
||||
// * Validation des détails
|
||||
foreach ($details as $key => $value) {
|
||||
if (empty($key) || !is_string($key)) {
|
||||
throw new \InvalidArgumentException("Clé de détail invalide : " . var_export($key, true));
|
||||
}
|
||||
if (!is_float($value) && !is_int($value)) {
|
||||
throw new \InvalidArgumentException("Valeur de détail pour '$key' invalide : " . var_export($value, true));
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($details as $key => $value) {
|
||||
if (empty($key) || !is_string($key)) {
|
||||
throw new \InvalidArgumentException("Clé de détail invalide : " . var_export($key, true));
|
||||
}
|
||||
if (!is_float($value) && !is_int($value)) {
|
||||
throw new \InvalidArgumentException("Valeur de détail pour '$key' invalide : " . var_export($value, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @return array{word:string,score:float}[] */
|
||||
public function getDetails(): array
|
||||
{
|
||||
/** @var object{'word':string,'score':float}[] */
|
||||
$output = [];
|
||||
|
||||
foreach ($this->details as $key => $value) {
|
||||
$output[] = (object)[
|
||||
'word' => $key,
|
||||
'score' => $value
|
||||
];
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
137
Lib/MessageClassifier.php
Normal file
137
Lib/MessageClassifier.php
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Classifier\Lib;
|
||||
|
||||
use Classifier\Lib\Discriminant\AlertAnalyzer;
|
||||
use Classifier\Lib\Enum\MessageType;
|
||||
use Classifier\Lib\Model\MessageQualifier;
|
||||
|
||||
class MessageClassifier
|
||||
{
|
||||
/** @var AlertAnalyzer */
|
||||
private $analyzer;
|
||||
|
||||
/** @var MessageQualifier */
|
||||
private $qualifier;
|
||||
|
||||
/** @var MessageType */
|
||||
private $defaultAlertType;
|
||||
|
||||
// * Seuil en dessous duquel on ne fait pas confiance à la machine
|
||||
private const MACHINE_CONFIDENCE_THRESHOLD = 0.65;
|
||||
|
||||
// * Seuil pour forcer une validation humaine sur une alerte critique
|
||||
private const CRITICAL_SAFETY_BAR = 0.85;
|
||||
|
||||
public function __construct(
|
||||
AlertAnalyzer $analyzer,
|
||||
MessageQualifier $qualifier,
|
||||
MessageType $defaultAlertType
|
||||
) {
|
||||
$this->analyzer = $analyzer;
|
||||
$this->qualifier = $qualifier;
|
||||
$this->defaultAlertType = $defaultAlertType;
|
||||
}
|
||||
|
||||
public function classify(string $message): MessageClassificationResult
|
||||
{
|
||||
// * Analyse Déterministe (Priorité Absolue)
|
||||
$dictResult = $this->analyzer->analyze($message);
|
||||
|
||||
if ($dictResult->isBlacklisted) {
|
||||
return new MessageClassificationResult(
|
||||
MessageType::INFO(),
|
||||
ClassificationMethod::DICTIONARY(),
|
||||
1.0,
|
||||
[$dictResult->reason => 1.0]
|
||||
);
|
||||
}
|
||||
|
||||
// * Si score >= 1.0 (ex: mot "attentat" ou "seveso"), c'est une certitude.
|
||||
if ($dictResult->score >= 1.0) {
|
||||
return new MessageClassificationResult(
|
||||
MessageType::ALERTE(),
|
||||
ClassificationMethod::DICTIONARY(),
|
||||
1.0,
|
||||
array_map(function (): int {
|
||||
// * Tous les mots trouvés sont considérés comme des preuves à 100%
|
||||
return 1;
|
||||
}, array_flip($dictResult->keywordsFound))
|
||||
);
|
||||
}
|
||||
|
||||
// * Analyse Probabiliste (Machine Learning)
|
||||
$mlResult = $this->qualifier->predictWithConfidence($message);
|
||||
|
||||
$predictedMessageType = $mlResult->decision;
|
||||
$confidence = $mlResult->confidence;
|
||||
$scores = $mlResult->scores;
|
||||
|
||||
// * Arbitrage Logique
|
||||
|
||||
// ? La machine n'est pas assez sûre d'elle
|
||||
if ($confidence < self::MACHINE_CONFIDENCE_THRESHOLD) {
|
||||
return new MessageClassificationResult(
|
||||
$this->defaultAlertType,
|
||||
ClassificationMethod::MACHINE(),
|
||||
$confidence,
|
||||
$scores,
|
||||
$predictedMessageType
|
||||
);
|
||||
}
|
||||
|
||||
// ? Si la machine doute, on applique la règle de sécurité par défaut
|
||||
if ($predictedMessageType->equals(MessageType::DOUBT())) {
|
||||
return new MessageClassificationResult(
|
||||
$this->defaultAlertType,
|
||||
ClassificationMethod::MACHINE(),
|
||||
$confidence,
|
||||
$scores,
|
||||
$predictedMessageType
|
||||
);
|
||||
}
|
||||
|
||||
// * La machine est confiante et ne doute pas. On regarde ce qu'elle a trouvé.
|
||||
|
||||
// ? Si la machine dit "INFO", on lui fait confiance (risque faible)
|
||||
if ($predictedMessageType->equals(MessageType::INFO())) {
|
||||
return new MessageClassificationResult(
|
||||
MessageType::INFO(),
|
||||
ClassificationMethod::MACHINE(),
|
||||
$confidence,
|
||||
$scores,
|
||||
$predictedMessageType
|
||||
);
|
||||
}
|
||||
|
||||
// ? Si la machine dit "ALERTE", on applique une sécurité supplémentaire
|
||||
if ($predictedMessageType->equals(MessageType::ALERTE())) {
|
||||
// ? Si c'est une alerte mais que la confiance est "moyenne" (ex: 70%)
|
||||
if ($confidence < self::CRITICAL_SAFETY_BAR) {
|
||||
return new MessageClassificationResult(
|
||||
// * "Alerte probable, mais besoin de validation"
|
||||
$this->defaultAlertType,
|
||||
ClassificationMethod::MACHINE(),
|
||||
$confidence,
|
||||
$scores,
|
||||
$predictedMessageType
|
||||
);
|
||||
}
|
||||
|
||||
// * Sinon, c'est une ALERTE validée par la machine (> 85%)
|
||||
return new MessageClassificationResult(
|
||||
$predictedMessageType,
|
||||
ClassificationMethod::MACHINE(),
|
||||
$confidence,
|
||||
$scores,
|
||||
$predictedMessageType
|
||||
);
|
||||
}
|
||||
|
||||
throw new \RuntimeException(
|
||||
'Cas non prévu pour la classification du message.'
|
||||
);
|
||||
}
|
||||
}
|
||||
149
Lib/Model/MessageQualifier.php
Normal file
149
Lib/Model/MessageQualifier.php
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Classifier\Lib\Model;
|
||||
|
||||
use Classifier\Lib\Enum\MessageType;
|
||||
use Rubix\ML\Pipeline;
|
||||
use Rubix\ML\PersistentModel;
|
||||
use Rubix\ML\Persisters\Filesystem;
|
||||
use Rubix\ML\Datasets\Labeled;
|
||||
use Rubix\ML\Datasets\Unlabeled;
|
||||
use Rubix\ML\Classifiers\KNearestNeighbors;
|
||||
use Rubix\ML\Kernels\Distance\Cosine;
|
||||
use Rubix\ML\Transformers\TextNormalizer;
|
||||
use Rubix\ML\Transformers\WordCountVectorizer;
|
||||
use Rubix\ML\Transformers\TfIdfTransformer;
|
||||
|
||||
/**
|
||||
* Gère la classification des messages via un modèle de machine learning.
|
||||
* Utilise Rubix ML pour l'apprentissage et la prédiction.
|
||||
*/
|
||||
class MessageQualifier
|
||||
{
|
||||
|
||||
private const MODEL_CONFIDENCE_THRESHOLD = 0.60;
|
||||
|
||||
/** @var PersistentModel */
|
||||
private $estimator;
|
||||
|
||||
/** @var string */
|
||||
private $modelPath;
|
||||
|
||||
public function __construct(string $modelPath = __DIR__ . '/model.rbx')
|
||||
{
|
||||
$this->modelPath = $modelPath;
|
||||
$persister = new Filesystem($this->modelPath);
|
||||
|
||||
if (file_exists($this->modelPath)) {
|
||||
$this->estimator = PersistentModel::load($persister);
|
||||
} else {
|
||||
$this->estimator = new PersistentModel(
|
||||
new Pipeline(
|
||||
[
|
||||
// * Normalisation de texte pour réduire la variance (ex: "Error" vs "error")
|
||||
new TextNormalizer(),
|
||||
// * Unigrammes + Bigrammes pour capturer les mots composés
|
||||
new WordCountVectorizer(10000, 1, 2),
|
||||
// * Pondération TF-IDF pour mieux différencier les mots fréquents mais peu informatifs
|
||||
new TfIdfTransformer(),
|
||||
],
|
||||
// * Classifieur KNN simple (peut être remplacé par un SVM ou un Random Forest pour de meilleures performances)
|
||||
new KNearestNeighbors(5, false, new Cosine())
|
||||
),
|
||||
$persister
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Entraîne le modèle et sauvegarde le fichier rbx
|
||||
*/
|
||||
public function train(array $samples, array $labels): void
|
||||
{
|
||||
if (file_exists($this->modelPath)) {
|
||||
unlink($this->modelPath);
|
||||
}
|
||||
|
||||
$dataset = new Labeled($samples, $labels);
|
||||
$this->estimator->train($dataset);
|
||||
$this->estimator->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prédiction simplifiée (Retourne juste le label)
|
||||
*/
|
||||
public function predict(string $message): MessageType
|
||||
{
|
||||
$result = $this->predictWithConfidence($message);
|
||||
|
||||
return $result->decision;
|
||||
}
|
||||
|
||||
public function predictWithConfidence(string $message): Prediction
|
||||
{
|
||||
// NOTE: Rubix attend un tableau de tableaux pour les échantillons
|
||||
$dataset = new Unlabeled([[$message]]);
|
||||
|
||||
// * Récupération des probabilités (ex: ['ALERTE' => 0.8, 'INFO' => 0.2])
|
||||
// var_dump($this->estimator->proba($dataset));
|
||||
// die;
|
||||
$probabilities = $this->estimator->proba($dataset)[0];
|
||||
|
||||
// * Trie pour obtenir le meilleur score en premier
|
||||
arsort($probabilities);
|
||||
$bestLabel = (string) key($probabilities);
|
||||
$confidence = (float) current($probabilities);
|
||||
|
||||
// var_dump(
|
||||
// $bestLabel,
|
||||
// $confidence,
|
||||
// $probabilities
|
||||
// );
|
||||
// die;
|
||||
|
||||
$label = $this->fromLabelToMessageType($bestLabel);
|
||||
$finalLabel = $this->applyDecisionThreshold($label, $confidence);
|
||||
|
||||
return new Prediction(
|
||||
$finalLabel,
|
||||
$label,
|
||||
'machine_learning',
|
||||
$confidence,
|
||||
$probabilities
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logique métier pour décider si le score est suffisant
|
||||
*/
|
||||
private function applyDecisionThreshold(MessageType $label, float $confidence): MessageType
|
||||
{
|
||||
if ($confidence < self::MODEL_CONFIDENCE_THRESHOLD) {
|
||||
return MessageType::DOUBT();
|
||||
}
|
||||
|
||||
return $label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si le modèle a déjà été entraîné
|
||||
*/
|
||||
public function isTrained(): bool
|
||||
{
|
||||
return file_exists($this->modelPath);
|
||||
}
|
||||
|
||||
private function fromLabelToMessageType(string $label): MessageType
|
||||
{
|
||||
switch ($label) {
|
||||
case 'ALERTE':
|
||||
return MessageType::ALERTE();
|
||||
case 'INFO':
|
||||
return MessageType::INFO();
|
||||
default:
|
||||
return MessageType::DOUBT();
|
||||
}
|
||||
}
|
||||
}
|
||||
48
Lib/Model/ModelTrainer.php
Normal file
48
Lib/Model/ModelTrainer.php
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Classifier\Lib\Model;
|
||||
|
||||
/**
|
||||
* Gère l'apprentissage du modèle à partir des données sources.
|
||||
*/
|
||||
class ModelTrainer
|
||||
{
|
||||
/** @var MessageQualifier */
|
||||
private $qualifier;
|
||||
|
||||
public function __construct(MessageQualifier $qualifier)
|
||||
{
|
||||
$this->qualifier = $qualifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Entraîne le modèle à partir d'un tableau associatif [Label => [Messages]]
|
||||
*
|
||||
* @param array<string,string[]> $data
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function trainFromData(array $data): void
|
||||
{
|
||||
$samples = [];
|
||||
$labels = [];
|
||||
|
||||
foreach ($data as $category => $messages) {
|
||||
foreach ($messages as $msg) {
|
||||
$cleanedMsg = trim($msg);
|
||||
if (!empty($cleanedMsg)) {
|
||||
// NOTE: Rubix attend un tableau de caractéristiques (une seule colonne pour le texte)
|
||||
$samples[] = [$cleanedMsg];
|
||||
$labels[] = $category;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($samples)) {
|
||||
throw new \Exception("Erreur : Aucun échantillon valide trouvé pour l'entraînement.");
|
||||
}
|
||||
|
||||
$this->qualifier->train($samples, $labels);
|
||||
}
|
||||
}
|
||||
65
Lib/Model/Prediction.php
Normal file
65
Lib/Model/Prediction.php
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Classifier\Lib\Model;
|
||||
|
||||
use Classifier\Lib\Enum\MessageType;
|
||||
|
||||
class Prediction
|
||||
{
|
||||
// FIXME : php8.1 readonly props
|
||||
|
||||
/**
|
||||
* Label final (avec gestion du doute)
|
||||
* @var MessageType
|
||||
*/
|
||||
public $decision;
|
||||
|
||||
/**
|
||||
* Label le plus probable selon le modèle entrainé (avant application du seuil de doute)
|
||||
* @var MessageType
|
||||
*/
|
||||
public $machineDecision;
|
||||
|
||||
/**
|
||||
* Méthode qui a conduit à la décision
|
||||
* @var string
|
||||
*/
|
||||
public $method;
|
||||
|
||||
/**
|
||||
* Score (0.0 à 1.0)
|
||||
* @var float
|
||||
*/
|
||||
public $confidence;
|
||||
|
||||
/**
|
||||
* Détail complet
|
||||
* @var array<string,float>
|
||||
*/
|
||||
public $scores;
|
||||
|
||||
public function __construct(
|
||||
MessageType $decision,
|
||||
MessageType $machineDecision,
|
||||
string $method,
|
||||
float $confidence,
|
||||
array $scores = []
|
||||
) {
|
||||
$this->decision = $decision;
|
||||
$this->machineDecision = $machineDecision;
|
||||
$this->method = $method;
|
||||
$this->confidence = $confidence;
|
||||
$this->scores = $scores;
|
||||
|
||||
foreach ($scores as $label => $score) {
|
||||
if (empty($label) || !is_string($label)) {
|
||||
throw new \InvalidArgumentException("Label de score invalide : " . var_export($label, true));
|
||||
}
|
||||
if ((!is_float($score) && !is_int($score)) || $score < 0.0 || $score > 1.0) {
|
||||
throw new \InvalidArgumentException("Score de label '$label' invalide : " . var_export($score, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
127
Lib/RawDataClassifier.php
Normal file
127
Lib/RawDataClassifier.php
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Classifier\Lib;
|
||||
|
||||
use Classifier\Lib\Enum\MessageType;
|
||||
use Classifier\Lib\MessageClassifier;
|
||||
use Classifier\Lib\Model\ModelTrainer;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\Console\Input\ArgvInput;
|
||||
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||
|
||||
class RawDataClassifier
|
||||
{
|
||||
const OUTPUT_DIR = __DIR__ . '/../../output';
|
||||
const GOOD_FILE = self::OUTPUT_DIR . '/positive.php';
|
||||
const BAD_FILE = self::OUTPUT_DIR . '/negative.php';
|
||||
const IGNORE_FILE = self::OUTPUT_DIR . '/ignored.php';
|
||||
|
||||
private $strings = [];
|
||||
private $io;
|
||||
private $results = ['good' => [], 'bad' => [], 'ignored' => []];
|
||||
private $master;
|
||||
private $trainer;
|
||||
|
||||
public function __construct(array $strings, MessageClassifier $master, ModelTrainer $trainer)
|
||||
{
|
||||
$this->io = new SymfonyStyle(new ArgvInput(), new ConsoleOutput());
|
||||
$this->master = $master;
|
||||
$this->trainer = $trainer;
|
||||
|
||||
$this->loadExistingData();
|
||||
|
||||
$cleaned = array_unique(array_map(function ($v) {
|
||||
return preg_replace('/\s+/', ' ', trim(mb_strtolower($v)));
|
||||
}, $strings));
|
||||
$alreadyDone = array_merge($this->results['good'], $this->results['bad'], $this->results['ignored']);
|
||||
|
||||
$this->strings = array_diff($cleaned, $alreadyDone);
|
||||
|
||||
if (!is_dir(self::OUTPUT_DIR)) {
|
||||
mkdir(self::OUTPUT_DIR, 0777, true);
|
||||
}
|
||||
}
|
||||
|
||||
private function loadExistingData(): void
|
||||
{
|
||||
$files = ['good' => self::GOOD_FILE, 'bad' => self::BAD_FILE, 'ignored' => self::IGNORE_FILE];
|
||||
foreach ($files as $key => $path) {
|
||||
if (file_exists($path)) {
|
||||
$this->results[$key] = include $path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function runQuestions(): void
|
||||
{
|
||||
$count = count($this->strings);
|
||||
if ($count === 0) {
|
||||
$this->io->success("Toutes les chaînes sont déjà traitées.");
|
||||
$this->askForTraining();
|
||||
return;
|
||||
}
|
||||
|
||||
$this->io->title('Test & Labellisation Assistée par Machine');
|
||||
|
||||
foreach ($this->strings as $string) {
|
||||
// L'algorithme fait une suggestion
|
||||
$prediction = $this->master->classify($string);
|
||||
|
||||
$this->io->section("Message à analyser");
|
||||
$this->io->text($string);
|
||||
$this->io->note(sprintf(
|
||||
"Suggestion : %s (via %s) - Confiance : %d%% - Détails : %s",
|
||||
$prediction->decision->getValue(),
|
||||
$prediction->method,
|
||||
$prediction->confidence * 100,
|
||||
implode(', ', array_map(function (object $d) {
|
||||
return $d->word . " (" . round($d->score * 100, 2) . "%)";
|
||||
}, $prediction->getDetails()))
|
||||
));
|
||||
|
||||
$answer = $this->io->choice('Valider cette classification ?', [
|
||||
'y' => 'Oui (Alerte)',
|
||||
'n' => 'Non (Info)',
|
||||
'i' => 'Ignorer',
|
||||
'q' => 'Sauvegarder et Quitter'
|
||||
], $prediction->decision->equals(MessageType::ALERTE()) ? 'y' : 'n');
|
||||
|
||||
if ($answer === 'q') {
|
||||
break;
|
||||
}
|
||||
|
||||
if ($answer === 'y') {
|
||||
$this->results['good'][] = $string;
|
||||
} elseif ($answer === 'i') {
|
||||
$this->results['ignored'][] = $string;
|
||||
} else {
|
||||
$this->results['bad'][] = $string;
|
||||
}
|
||||
}
|
||||
|
||||
$this->saveResults();
|
||||
$this->askForTraining();
|
||||
}
|
||||
|
||||
private function askForTraining(): void
|
||||
{
|
||||
if ($this->io->confirm("Voulez-vous lancer l'apprentissage immédiat du modèle avec ces données ?", true)) {
|
||||
$this->io->comment("Entraînement en cours...");
|
||||
$this->trainer->trainFromData([
|
||||
'ALERTE' => $this->results['good'],
|
||||
'INFO' => $this->results['bad']
|
||||
]);
|
||||
$this->io->success("Modèle mis à jour et sauvegardé !");
|
||||
}
|
||||
}
|
||||
|
||||
private function saveResults(): void
|
||||
{
|
||||
foreach (['good' => self::GOOD_FILE, 'bad' => self::BAD_FILE, 'ignored' => self::IGNORE_FILE] as $key => $path) {
|
||||
sort($this->results[$key]);
|
||||
file_put_contents($path, "<?php\n\nreturn " . var_export($this->results[$key], true) . ";\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
203
Lib/RawDataLoader.php
Normal file
203
Lib/RawDataLoader.php
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Classifier\Lib;
|
||||
|
||||
class RawDataLoader
|
||||
{
|
||||
private const RAW_DATA_PATH = __DIR__ . '/../data/raw';
|
||||
|
||||
private const SMS_SEPARATOR = "\"\n\"";
|
||||
private const SMS_FILE = self::RAW_DATA_PATH . '/sms';
|
||||
|
||||
private const SMS_SEPARATOR_DEV = "|\n|";
|
||||
private const SMS_FILE_DEV = self::RAW_DATA_PATH . '/sms_dev_maria_suff';
|
||||
|
||||
private const MAIL_SEPARATOR = "___";
|
||||
private const MAIL_FILE = self::RAW_DATA_PATH . '/mails';
|
||||
|
||||
private const MIXED_TA_LOG_SEPARATOR = "###";
|
||||
private const MIXED_TA_LOG_FILE = self::RAW_DATA_PATH . '/t.log';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
if (!file_exists(self::RAW_DATA_PATH)) {
|
||||
mkdir(self::RAW_DATA_PATH);
|
||||
}
|
||||
|
||||
if (!file_exists(self::SMS_FILE)) {
|
||||
throw new \Exception('SMS file not found');
|
||||
}
|
||||
if (!file_exists(self::MAIL_FILE)) {
|
||||
throw new \Exception('Mail file not found');
|
||||
}
|
||||
if (!file_exists(self::MIXED_TA_LOG_FILE)) {
|
||||
throw new \Exception('Mixed TA log file not found');
|
||||
}
|
||||
}
|
||||
|
||||
/** @return string[] */
|
||||
public function getSanitizedStrings(): array
|
||||
{
|
||||
return array_merge(
|
||||
// $this->loadMailData(),
|
||||
// $this->loadSmsData2(),
|
||||
// $this->loadSmsDataDev(),
|
||||
$this->loadMixedTaLogData()
|
||||
);
|
||||
}
|
||||
|
||||
private function sanitize(string $value): string
|
||||
{
|
||||
$output = $this->fromUt8ToPlainText($value);
|
||||
$output = $this->safelyRemoveEmptyLines($output);
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
|
||||
private function fromUt8ToPlainText(string $value): string
|
||||
{
|
||||
// * Supprimer les balises
|
||||
$output = strip_tags($value);
|
||||
|
||||
// * Convertir les entités html (ex: & devient &)
|
||||
$output = html_entity_decode($output, ENT_QUOTES | ENT_HTML5, 'UTF-8');
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
private function safelyRemoveEmptyLines(string $value): string
|
||||
{
|
||||
// * Remplace les lignes ne contenant que des espaces/tabs par une chaîne vide
|
||||
$result = preg_replace('/^[\s\t]*[\r\n]+/m', '', $value);
|
||||
|
||||
// * Remplace les sauts de lignes avec un `\n` unique
|
||||
$result = preg_replace('/\R/', "\n", $result);
|
||||
|
||||
return $result ?? $value;
|
||||
}
|
||||
|
||||
private function loadMailData(): array
|
||||
{
|
||||
/** @var string[] */
|
||||
$output = [];
|
||||
$data = $this->loadData(self::MAIL_FILE);
|
||||
|
||||
$token = strtok($data, self::MAIL_SEPARATOR);
|
||||
while ($token !== false) {
|
||||
$sanitizedToken = $this->sanitize($token);
|
||||
|
||||
$sanitizedToken = mb_trim(str_replace('\\\'', '\'', $sanitizedToken));
|
||||
|
||||
if (!empty($sanitizedToken)) {
|
||||
$output[] = $sanitizedToken;
|
||||
}
|
||||
$token = strtok(self::MAIL_SEPARATOR);
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
private function loadSmsData(): array
|
||||
{
|
||||
/** @var string[] */
|
||||
$output = [];
|
||||
$data = $this->loadData(self::SMS_FILE);
|
||||
|
||||
$token = strtok($data, self::SMS_SEPARATOR);
|
||||
while ($token !== false) {
|
||||
$sanitizedToken = $this->sanitize($token);
|
||||
|
||||
$sanitizedToken = mb_trim(str_replace('\\\'', '\'', $sanitizedToken));
|
||||
|
||||
if (!empty($sanitizedToken)) {
|
||||
$output[] = $sanitizedToken;
|
||||
}
|
||||
$token = strtok(self::SMS_SEPARATOR);
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
private function loadSmsData2(): array
|
||||
{
|
||||
/** @var string[] */
|
||||
$output = [];
|
||||
$data = $this->loadData(self::SMS_FILE);
|
||||
|
||||
$splitted = preg_split('/' . preg_quote(self::SMS_SEPARATOR, '/') . '/', $data);
|
||||
|
||||
foreach ($splitted as $token) {
|
||||
$sanitizedToken = $this->sanitize($token);
|
||||
|
||||
$sanitizedToken = mb_trim(str_replace('\\\'', '\'', $sanitizedToken));
|
||||
|
||||
if (!empty($sanitizedToken)) {
|
||||
$output[] = $sanitizedToken;
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
private function loadSmsDataDev(): array
|
||||
{
|
||||
/** @var string[] */
|
||||
$output = [];
|
||||
$data = $this->loadData(self::SMS_FILE_DEV);
|
||||
|
||||
$splitted = preg_split('/' . preg_quote(self::SMS_SEPARATOR_DEV, '/') . '/', $data);
|
||||
|
||||
foreach ($splitted as $token) {
|
||||
$sanitizedToken = $this->sanitize($token);
|
||||
|
||||
$sanitizedToken = mb_trim(str_replace('\\\'', '\'', $sanitizedToken));
|
||||
$sanitizedToken = preg_replace('/¶/', '', $sanitizedToken);
|
||||
$sanitizedToken = preg_replace('/^\|/', '', $sanitizedToken);
|
||||
$sanitizedToken = preg_replace('/\|$/', '', $sanitizedToken);
|
||||
$sanitizedToken = trim($sanitizedToken);
|
||||
|
||||
if (!empty($sanitizedToken)) {
|
||||
$output[] = $sanitizedToken;
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
private function loadMixedTaLogData(): array
|
||||
{
|
||||
/** @var string[] */
|
||||
$output = [];
|
||||
$data = $this->loadData(self::MIXED_TA_LOG_FILE);
|
||||
|
||||
$splitted = preg_split('/' . preg_quote(self::MIXED_TA_LOG_SEPARATOR, '/') . '/', $data);
|
||||
|
||||
shuffle($splitted);
|
||||
|
||||
foreach ($splitted as $token) {
|
||||
$sanitizedToken = $this->sanitize($token);
|
||||
|
||||
$sanitizedToken = mb_trim(str_replace('\\\'', '\'', $sanitizedToken));
|
||||
$sanitizedToken = preg_replace('/¶/', '', $sanitizedToken);
|
||||
$sanitizedToken = preg_replace('/^\|/', '', $sanitizedToken);
|
||||
$sanitizedToken = preg_replace('/\|$/', '', $sanitizedToken);
|
||||
$sanitizedToken = preg_replace(['/\\n/', '/\\\n/', '/\\\\n/'], "\n", $sanitizedToken);
|
||||
$sanitizedToken = preg_replace('/\\t/', "\t", $sanitizedToken);
|
||||
$sanitizedToken = trim($sanitizedToken);
|
||||
|
||||
if (!empty($sanitizedToken)) {
|
||||
$output[] = $sanitizedToken;
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
private function loadData(string $file): string
|
||||
{
|
||||
return file_get_contents($file);
|
||||
}
|
||||
}
|
||||
174
Lib/Utils/StringCleaner.php
Normal file
174
Lib/Utils/StringCleaner.php
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Classifier\Lib\Utils;
|
||||
|
||||
class StringCleaner
|
||||
{
|
||||
/** @var string[] */
|
||||
private $stopWords;
|
||||
|
||||
public function __construct(array $stopWords = [])
|
||||
{
|
||||
$this->stopWords = array_map(function (string $word) {
|
||||
return trim(mb_strtolower($word, 'UTF-8'));
|
||||
}, $stopWords);
|
||||
}
|
||||
|
||||
public function getCleanChain(string $text): string
|
||||
{
|
||||
$text = $this->toUtf8($text);
|
||||
$text = $this->handleAcronyms($text);
|
||||
$text = mb_strtolower($text, 'UTF-8');
|
||||
$text = $this->translitterate($text);
|
||||
return $this->removeMultiSpaces($text); // "alerte mise en securite"
|
||||
}
|
||||
|
||||
/**
|
||||
* Nettoie une chaîne de caractères en appliquant plusieurs étapes de transformation
|
||||
*
|
||||
* @param string $text
|
||||
* @return string[] Tableau de mots nettoyés
|
||||
*/
|
||||
public function preprocessMessage(string $text): array
|
||||
{
|
||||
$text = $this->toUtf8($text);
|
||||
$text = mb_strtolower($text, 'UTF-8');
|
||||
$text = $this->handleAcronyms($text);
|
||||
$text = $this->fromUtf8ToPlainText($text);
|
||||
$text = $this->safelyRemoveEmptyLines($text);
|
||||
$text = $this->controlCharToSpace($text);
|
||||
$text = $this->translitterate($text);
|
||||
$text = $this->removeMultiSpaces($text);
|
||||
|
||||
|
||||
$words = $this->cutIntoWords($text);
|
||||
$filteredWords = $this->removeStopWords($words);
|
||||
|
||||
return array_values($filteredWords);
|
||||
}
|
||||
|
||||
private function cutIntoWords(string $text): array
|
||||
{
|
||||
return explode(' ', $text);
|
||||
}
|
||||
|
||||
private function handleAcronyms(string $text): string
|
||||
{
|
||||
// Transforme "P O I" ou "P.O.I" en "POI"
|
||||
return preg_replace('/(?<=\b\w)\s(?=\w\b)/', '', $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translittération (enlève les accents proprement)
|
||||
*/
|
||||
private function translitterate(string $value): string
|
||||
{
|
||||
// *Translittération (enlève les accents proprement)
|
||||
$transliterated = false;
|
||||
if (class_exists('\Transliterator')) {
|
||||
$transliterator = \Transliterator::create('Any-Latin; Latin-ASCII');
|
||||
if ($transliterator) {
|
||||
$result = $transliterator->transliterate($value);
|
||||
if ($result !== false) {
|
||||
$value = $result;
|
||||
$transliterated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$transliterated && function_exists('iconv')) {
|
||||
$result = iconv('UTF-8', 'ASCII//TRANSLIT', $value);
|
||||
if ($result !== false) {
|
||||
$value = $result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return preg_replace('/[^\p{L}\p{N}\s]/u', '', $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remplace les caractères de contrôle (sauf les espaces) par des espaces
|
||||
*/
|
||||
private function controlCharToSpace(string $value): string
|
||||
{
|
||||
return preg_replace('/[\x00-\x1F\x7F]+/', ' ', $value);
|
||||
}
|
||||
|
||||
private function removeMultiSpaces(string $value): string
|
||||
{
|
||||
return trim(preg_replace('/\s+/', ' ', $value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Supprime les stop words d'un tableau de mots
|
||||
* et les mots de 1 caractère ou moins
|
||||
*
|
||||
* @param string[] $words
|
||||
*/
|
||||
private function removeStopWords(array $words): array
|
||||
{
|
||||
return array_filter($words, function ($word) {
|
||||
return !in_array($word, $this->stopWords) && mb_strlen($word) > 1;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Convertit une chaîne UTF-8 en texte brut, en supprimant les balises et en décodant les entités HTML
|
||||
*/
|
||||
private function fromUtf8ToPlainText(string $value): string
|
||||
{
|
||||
// * Supprimer les balises
|
||||
$output = strip_tags($value);
|
||||
|
||||
// * Convertir les entités html (ex: & devient &)
|
||||
$output = html_entity_decode($output, ENT_QUOTES | ENT_HTML5, 'UTF-8');
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Supprime les lignes vides ou ne contenant que des espaces/tabs, et normalise les sauts de ligne
|
||||
*/
|
||||
private function safelyRemoveEmptyLines(string $value): string
|
||||
{
|
||||
// * Remplace les lignes ne contenant que des espaces/tabs par une chaîne vide
|
||||
$result = preg_replace('/^\s*[\r\n]+/m', '', $value);
|
||||
|
||||
// * Remplace les sauts de lignes avec un `\n` unique
|
||||
$result = preg_replace('/\R/', "\n", $result);
|
||||
|
||||
return $result ?? $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convertit intelligemment vers UTF-8
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return string
|
||||
*/
|
||||
private function toUtf8($value): string
|
||||
{
|
||||
if ($value === null || $value === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
$str = (string)$value;
|
||||
|
||||
if (mb_check_encoding($str, 'UTF-8')) {
|
||||
return $str;
|
||||
}
|
||||
|
||||
// * Détection du symbole € en ISO-8859-15 (\xA4)
|
||||
if (strpos($str, "\xA4") !== false) {
|
||||
$converted = iconv('ISO-8859-15', 'UTF-8//IGNORE', $str);
|
||||
return ($converted !== false) ? $converted : $str;
|
||||
}
|
||||
|
||||
// * Tenter conversion de ISO-8859-1 vers UTF-8
|
||||
$converted = iconv('ISO-8859-1', 'UTF-8//IGNORE', $str);
|
||||
|
||||
return ($converted !== false) ? $converted : $str;
|
||||
}
|
||||
}
|
||||
22
Lib/index.php
Normal file
22
Lib/index.php
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/Utils/StringCleaner.php';
|
||||
|
||||
require_once __DIR__ . '/Discriminant/AlertAnalyzer.php';
|
||||
require_once __DIR__ . '/Discriminant/BlackList.php';
|
||||
require_once __DIR__ . '/Discriminant/WhiteList.php';
|
||||
require_once __DIR__ . '/Discriminant/AnalyzeResult.php';
|
||||
|
||||
require_once __DIR__ . '/Model/ModelTrainer.php';
|
||||
require_once __DIR__ . '/Model/MessageQualifier.php';
|
||||
require_once __DIR__ . '/Model/Prediction.php';
|
||||
|
||||
require_once __DIR__ . '/Enum/ClassificationMethod.php';
|
||||
require_once __DIR__ . '/Enum/MessageType.php';
|
||||
|
||||
require_once __DIR__ . '/MessageClassificationResult.php';
|
||||
require_once __DIR__ . '/MessageClassifier.php';
|
||||
require_once __DIR__ . '/RawDataClassifier.php';
|
||||
require_once __DIR__ . '/RawDataLoader.php';
|
||||
48
autotrainer.php
Normal file
48
autotrainer.php
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Classifier\Lib\RawDataLoader;
|
||||
use Classifier\Lib\Discriminant\AlertAnalyzer;
|
||||
use Classifier\Lib\Discriminant\BlackList;
|
||||
use Classifier\Lib\Discriminant\WhiteList;
|
||||
use Classifier\Lib\Enum\MessageType;
|
||||
use Classifier\Lib\MessageClassifier;
|
||||
use Classifier\Lib\Model\MessageQualifier;
|
||||
use Classifier\Lib\Model\ModelTrainer;
|
||||
use Classifier\Lib\RawDataClassifier;
|
||||
use Classifier\Lib\Utils\StringCleaner;
|
||||
|
||||
require_once __DIR__ . '/vendor/autoload.php';
|
||||
require_once __DIR__ . '/Lib/index.php';
|
||||
|
||||
$modelPath = __DIR__ . '/model.rbx';
|
||||
|
||||
// Stop words : Mots à ignorer pour le nettoyage des messages
|
||||
$stopWords = require __DIR__ . '/data/stopwords.php';
|
||||
$strCleaner = new StringCleaner($stopWords);
|
||||
|
||||
// Liste noire : Priorité absolue pour tuer les faux positifs
|
||||
$blackList = new BlackList(require __DIR__ . '/data/blacklist.php', $strCleaner);
|
||||
|
||||
// Liste blanche : Mots clés avec poids pour le dictionnaire fuzzy
|
||||
$whiteList = new WhiteList(require __DIR__ . '/data/whitelist.php', $strCleaner);
|
||||
|
||||
|
||||
// * Charger messages bruts (ex: depuis une BDD ou un fichier)
|
||||
$sanitizer = new RawDataLoader();
|
||||
$rawMessages = $sanitizer->getSanitizedStrings();
|
||||
|
||||
// * Setup du moteur & Dictionnaire
|
||||
|
||||
$analyzer = new AlertAnalyzer($whiteList, $blackList, $strCleaner, 100);
|
||||
$qualifier = new MessageQualifier($modelPath);
|
||||
$trainer = new ModelTrainer($qualifier);
|
||||
|
||||
// * Setup du Master (Hybride)
|
||||
$defaultAlertType = MessageType::ALERTE();
|
||||
$master = new MessageClassifier($analyzer, $qualifier, $defaultAlertType);
|
||||
|
||||
// * Lancement du banc de test
|
||||
$classifierTool = new RawDataClassifier($rawMessages, $master, $trainer);
|
||||
$classifierTool->runQuestions();
|
||||
9
composer.json
Normal file
9
composer.json
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"require": {
|
||||
"yooper/php-text-analysis": "^1.5",
|
||||
"php-ai/php-ml": "^0.9.0",
|
||||
"rubix/ml": "^0.4.3",
|
||||
"symfony/console": "^5.4",
|
||||
"myclabs/php-enum": "^1.8"
|
||||
}
|
||||
}
|
||||
2201
composer.lock
generated
Normal file
2201
composer.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
27
data/blacklist.php
Normal file
27
data/blacklist.php
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'iphone',
|
||||
'vente',
|
||||
'gratuit',
|
||||
'offre',
|
||||
'promotion',
|
||||
'cadeau',
|
||||
'gagner',
|
||||
'loyer',
|
||||
'quittance',
|
||||
'echeance',
|
||||
'facture',
|
||||
'solde',
|
||||
'rabais',
|
||||
'allocation',
|
||||
'caf',
|
||||
'dossier',
|
||||
'identifiant',
|
||||
'commémoration',
|
||||
'anniversaire',
|
||||
'pétanque',
|
||||
'réunion',
|
||||
];
|
||||
43
data/raw/mails
Normal file
43
data/raw/mails
Normal file
File diff suppressed because one or more lines are too long
687
data/raw/sms
Normal file
687
data/raw/sms
Normal file
|
|
@ -0,0 +1,687 @@
|
|||
"Ceci est un message de formation
|
||||
Transports scolaires interdits de jour sur le 43
|
||||
Veuillez consulter l\'arreté ci-dessous ou votre messagerie"
|
||||
"Ceci est un message d\'exercice.
|
||||
|
||||
Un arreté portant interdiction des transports scolaires a été pris ce jour sur l\'ensemble du département de la Haute-Loire.
|
||||
|
||||
Veuillez consulter votre messagerie pour télécharger l\'arreté"
|
||||
"Ceci est un message de formation
|
||||
Transports scolaires interdits de jour sur le 43
|
||||
Veuillez consulter l\'arreté ci-dessous ou votre messagerie"
|
||||
"Ceci est un message de formation
|
||||
FIN DE L\'INTERDICTION DE TRANSPORTS SCOLAIRES"
|
||||
"Ceci est un message exercice
|
||||
Transport scolaire interdit ce jour sur le 43
|
||||
Veuillez consulter l\'arreté ci-dessous ou votre mail"
|
||||
"Ceci est un message exercice
|
||||
Transport scolaire interdit ce jour sur le 43
|
||||
Veuillez consulter l\'arreté ci-dessous ou votre mail"
|
||||
"Ceci est un message exercice
|
||||
Transport scolaire interdit ce jour sur le 43
|
||||
Veuillez consulter l\'arreté ci-dessous ou votre mail"
|
||||
"Ceci est un message exercice
|
||||
Transport scolaire interdit ce jour sur le 43
|
||||
Veuillez consulter l\'arreté ci-dessous ou votre mail"
|
||||
"On écoute la formatrice Sandra
|
||||
Campagne terminée. On a retrouvé le soleil"
|
||||
"Bande de saucisses"
|
||||
"Ceci est un message exercice
|
||||
Transport scolaire interdit ce jour sur le 43
|
||||
Veuillez consulter l\'arreté ci-dessous ou votre mail"
|
||||
"Ceci est un message de formation
|
||||
Pour etre mis en relation avec le tenebreux patoche, tapez 1 ou appelez le 3615 patoche
|
||||
|
||||
Transports scolaires interdits de jour sur le 43
|
||||
Veuillez consulter l\'arreté ci-dessous ou votre message"
|
||||
"Ceci est un message de formation
|
||||
Pour etre mis en relation avec le tenebreux patoche tapez 1 ou appelez le 3615 patoche
|
||||
|
||||
Transports scolaires interdits de jour sur le 43
|
||||
Veuillez consulter l\'arreté ci-dessous ou votre messagerie"
|
||||
"Ceci est un message exercice
|
||||
Transport scolaire interdit ce jour sur le 43
|
||||
Veuillez consulter l\'arreté ci-dessous ou votre mail"
|
||||
"Ceci est un message exercice
|
||||
Transport scolaire interdit ce jour sur le 43
|
||||
Veuillez consulter l\'arreté ci-dessous ou votre mail"
|
||||
"Ceci est un message exercice
|
||||
Transport scolaire interdit ce jour sur le 43
|
||||
Veuillez consulter l\'arreté ci-dessous ou votre mail"
|
||||
"Ceci est un message exercice
|
||||
Transport scolaire interdit ce jour sur le 43
|
||||
Veuillez consulter l\'arreté ci-dessous ou votre mail"
|
||||
"Ceci est un message de ré information.
|
||||
Veuillez ne pas tenir compte des messages de Frédéric F.
|
||||
Il est fatigué.
|
||||
La préfecture vous remercie de votre attention."
|
||||
"Le préfet communique
|
||||
|
||||
Merci de ne pas tenir compte des messages de Frédéric F
|
||||
|
||||
Il est fatigué
|
||||
|
||||
Restez vigilants"
|
||||
"Votre code d\'authentification téléalerte : (%champ libre)
|
||||
Recopiez ce code pour vous authentifier."
|
||||
"Votre code d\'authentification téléalerte : (%champ libre)
|
||||
Recopiez ce code pour vous authentifier."
|
||||
"Votre code d\'authentification téléalerte : (%champ libre)
|
||||
Recopiez ce code pour vous authentifier."
|
||||
"ceci est un test"
|
||||
"ceci est un test
|
||||
pour validation"
|
||||
"Message test.
|
||||
Perturbation des transports scolaires est prévue de 9h à 18h.
|
||||
Veuillez vous connecter sur www.Haute-Loire.gouv.fr .
|
||||
Sinon téléphonez au FBI"
|
||||
"Message test.
|
||||
Perturbation des transports scolaires est prévue de 9h à 18h.
|
||||
Veuillez vous connecter sur www.Haute-Loire.gouv.fr .
|
||||
Sinon téléphonez au FBI"
|
||||
"Ceci est un message de test
|
||||
Perturbation des transports scolaires ce jour de 9hà 18h
|
||||
Veuillez consulter le site de la préfecture sur www.haute-loire .gouv.fr"
|
||||
"Ceci est un message de test
|
||||
|
||||
Perturbation des transports scolaires ce jour de 9hà 18h
|
||||
|
||||
Veuillez consulter le site de la préfecture sur www.haute-loire .gouv.fr"
|
||||
"Ceci est un message de test
|
||||
Perturbation transports scolaires ce jour de 9h à 18h.
|
||||
Veuillez vous connecter sur le site www.haute-loire.gouv.fr"
|
||||
"Ceci est un message de test
|
||||
Perturbation transports scolaires ce jour de 9h à 18h.
|
||||
Veuillez vous connecter sur le site www.haute-loire.gouv.fr"
|
||||
"Ceci est un message de test
|
||||
Perturbation transports scolaires ce jour de 9h à 18h.
|
||||
Veuillez vous connecter sur le site www.haute-loire.gouv.fr"
|
||||
"Ceci est un message de test
|
||||
Perturbation transports scolaires ce jour de 9h à 18h.
|
||||
Veuillez vous connecter sur le site www.haute-loire.gouv.fr"
|
||||
"Ceci est un message de test
|
||||
Attention : Vigilance rouge Neige en cours sur la Haute-Loire. Plus d\'infos sur vigilance.meteofrance.fr/fr/haute-loire"
|
||||
"Ceci est un message de test
|
||||
ATTENTION - Transports scolaires et routiers collectifs interdits ce jour en Haute Loire. Veuillez consulter l\'arreté ci-joint ou votre messagerie courriel."
|
||||
"Ceci est un message de test
|
||||
ATTENTION - Transports scolaires et routiers collectifs interdits ce jour en Haute Loire. Veuillez consulter l\'arreté ci-joint ou votre messagerie courriel."
|
||||
"Ceci est un message de test
|
||||
Perturbation transports scolaires ce jour de 9h à 18h.
|
||||
Veuillez vous connecter sur le site www.haute-loire.gouv.fr"
|
||||
"Ceci est un message de test
|
||||
Perturbation transports scolaires ce jour de 9h à 18h.
|
||||
Veuillez vous connecter sur le site www.haute-loire.gouv.fr"
|
||||
"Ceci est un message de test
|
||||
Perturbation transports scolaires ce jour de 9h à 18h.
|
||||
Veuillez vous connecter sur le site www.haute-loire.gouv.fr"
|
||||
"Ceci est un message de test
|
||||
Attention : Vigilance rouge Neige en cours sur la Haute-Loire. Plus d\'infos sur vigilance.meteofrance.fr/fr/haute-loire"
|
||||
"Votre code d\'authentification téléalerte : (%champ libre)
|
||||
Recopiez ce code pour vous authentifier."
|
||||
"essai automate alerte CII TELECOM
|
||||
essai automate alerte CII TELECOM
|
||||
essai automate alerte CII TELECOM
|
||||
essai automate alerte CII TELECOM
|
||||
essai automate alerte CII TELECOM
|
||||
Exercice formation CIITELECOM du 232 mars 2023.
|
||||
Exercice formation CIITELECOM du 21 mars 2023*25
|
||||
Exercice formation CIITELECOM du 21 mars 2023*25
|
||||
Exercice formation CIITELECOM du 21 mars 2023*25
|
||||
Exercice formation CIITELECOM du 21 mars 2023*25
|
||||
Ce message est un test préalable à la mise en place du nouvel automate d\'alerte de la préfecture de la Haute-Loire.
|
||||
Ce message est un test préalable à la mise en place du nouvel automate d\'alerte de la préfecture de la Haute-Loire."
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange orages annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Dans le cadre d\'un exercice de gestion de crise routière, la section de la RN88 entre le carrefour giratoire de "Lachamp" et l\'échangeur n49 "Fay la Triouleyre" sera fermée le mercredi 31 mai 2023 de 18h45 à 22h30, et la déviation PGT 88-5 activée pendant cette durée.
|
||||
Un mail reprenant ces éléments vous à été adressé.
|
||||
Préfecture - Haute-Loire"
|
||||
"Exercice routier du 31 mai - 18h45 - 22h30
|
||||
coupure RN88 et déviation PGT-88.5 secteur Lachamps - Fay la Trouleyre
|
||||
veuillez consulter le mail qui vous a été transmis
|
||||
Préfecture 43
|
||||
vérifiez vos SPAM"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange orages annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange orages annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance rouge neige-verglas annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"PREF43 - INFO IMPORTANTE
|
||||
A consulter sur la boite mail mairie l\'arrete prefectoral pris ce jour concernant les mesures d\'interdiction temporaire de ce WE"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange orages annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange orages annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange orages annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Bonsoir,
|
||||
Le préfet de Haute-Loire informe que le département est placé en vigilance orange canicule à compter de ce jeudi 17 aout.
|
||||
Plus d\'infos et sur les conduites à tenir sur vigilance.meteofrance.fr et par mail (surveillez vos SPAMS)"
|
||||
"Bonsoir,
|
||||
Le préfet de Haute-Loire informe que le département est placé en vigilance orange canicule à compter de ce jeudi 17 aout.
|
||||
Plus d\'infos et sur les conduites à tenir sur vigilance.meteofrance.fr et par mail (surveillez vos SPAMS)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Le préfet de Haute-Loire informe que le département est placé en vigilance rouge canicule à compter de ce mardi 22 aout à partir de midi.
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange orages à compter d\'aujourd\'hui en milieu d\'après-midi.
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"INFO Préfecture 43
|
||||
EXERCICE DE SECURITE CIVILE prévu le 05/10/23 sur le barrage de NAUSSAC
|
||||
Plus d\'information par mail (surveillez vos SPAM)"
|
||||
"INFO Préfecture 43
|
||||
EXERCICE SECURITE CIVILE prévu le 05/10/23 sur le barrage de NAUSSAC
|
||||
Consultez vos mails (surveillez SPAM)"
|
||||
"INFO Préfecture 43
|
||||
EXERCICE SECURITE CIVILE prévu le 05/10/23 sur le barrage de NAUSSAC
|
||||
Consultez vos mails (surveillez SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange vents violents annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange vents violents annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange vents violents annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Interdiction de circulation, véhicules transport de marchandises PTAC >3.5 t articulés, RN88 et RN102 secteur Sud du département
|
||||
PJ : arreté préfectoral
|
||||
Préf43"
|
||||
"Interdiction de circulation, véhicules transport de marchandises PTAC >3.5 t articulés, RN88 et RN102 secteur Sud du département
|
||||
PJ : arreté préfectoral
|
||||
Préf43"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange neige-verglas annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Interdiction de circulation, véhicules transport de marchandises PTAC >7.5 t sur autoroute A75, dans les deux sens de circulation, entre la jonction avec l\'A71 et la limite départementale Sud de la Lozère.
|
||||
PJ : arreté préfectoral
|
||||
Préf43"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange neige-verglas annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
La Vigilance orange neige-verglas sera prolongée demain jusqu\'à 18h
|
||||
Plus d\'infos sur vigilance.meteofrance.fr"
|
||||
"Information Préfecture Haute-Loire
|
||||
La Vigilance orange neige-verglas sera prolongée jusqu\'à demain 18h
|
||||
Plus d\'infos sur vigilance.meteofrance.fr"
|
||||
"Interdiction de circulation, véhicules transport de marchandises PTAC >7.5 t, RN88 et RN102 secteur Sud du département
|
||||
PJ : arreté préfectoral
|
||||
Préf43"
|
||||
"Interdiction de circulation, véhicules transport de marchandises PTAC >7.5 t, RN88 et RN102 secteur Sud du département
|
||||
PJ : arreté préfectoral
|
||||
Préf43"
|
||||
"Interdiction de circulation, véhicules transport de marchandises PTAC >7.5 t, RN88 et RN102 secteur Sud du département
|
||||
PJ : arreté préfectoral
|
||||
Préf43"
|
||||
"Interdiction de circulation, véhicules transport de marchandises PTAC >7.5 t, RN88 et RN102 secteur Sud du département
|
||||
PJ : arreté préfectoral
|
||||
Préf43"
|
||||
"Interdiction de circulation, véhicules transport de marchandises PTAC >7.5 t, RN88 et RN102 secteur Sud du département
|
||||
PJ : arreté préfectoral
|
||||
Préf43"
|
||||
"Fin de l\'interdiction de circulation, pour les véhicules de transport de marchandises PTAC >7.5 t sur RN88/RN102 secteur Sud du département.
|
||||
Préf43"
|
||||
"Interdiction de circulation, véhicules transport de marchandises articulés PTAC >3.5 t, RN102 secteur Sud du département
|
||||
PJ : arreté préfectoral
|
||||
Préf43"
|
||||
"INFO Préfecture
|
||||
Service de prévision des crues : vigilance jaune crue - Troncon Loire Vellave
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et mail (surveillez vos SPAM)"
|
||||
"Information Préfecture
|
||||
Service de prévision des crues : vigilance jaune crue - Troncon Haut Allier
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et mail (surveillez SPAM)"
|
||||
"Information Préfecture
|
||||
Service de prévision des crues : vigilance jaune crue - Troncon Allier Brivadois
|
||||
Infos : vigicrues.gouv.fr
|
||||
et mail (surveillez vos SPAM)"
|
||||
"Information Préfecture
|
||||
Service de prévision des crues : vigilance jaune crue - Troncon Borne
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et mail (surveillez SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange vents violents annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"INFO Préfecture
|
||||
Service de prévision des crues : vigilance jaune crue - Troncon Lignon du Velay
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et mail (surveillez SPAM)"
|
||||
"Interdiction de circulation, véhicules transport de marchandises PTAC >3.5t, puis tous véhicules, sur RN102 secteur Sud du département
|
||||
PJ : arreté préfectoral
|
||||
Préf43"
|
||||
"Le préfet de la Haute-Loire informe que le département sera placé en vigilance orange "neige / verglas" à compter de minuit et jusqu\'à neuf heures.
|
||||
Plus d\'information sur le site https://vigilance.meteofrance.fr"
|
||||
"Information Préfecture Haute-Loire
|
||||
Épisode de pollution atmosphérique en raison de la persistance de poussières désertiques dans l\'air
|
||||
Infos complémentaires par mail (surveillez vos SPAM)"
|
||||
"INFO Préfecture
|
||||
Service de prévision des crues : vigilance jaune crue - Troncon Loire Vellave
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et mail (surveillez vos SPAM)"
|
||||
"Information Préfecture
|
||||
Service de prévision des crues : vigilance jaune crue - Troncon Haut Allier
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et mail (surveillez SPAM)"
|
||||
"Interdiction de circulation, véhicules transport de marchandises PTAC >7.5 t, RN88 secteur Sud du département
|
||||
PJ : arreté préfectoral
|
||||
Préf43"
|
||||
"Information Préfecture 43
|
||||
Service de prévision des crues : Vigilance jaune crue - Troncon Alagnon Aval
|
||||
Infos sur vigicrues.gouv.fr
|
||||
et mail (surveillez vos SPAM)"
|
||||
"Information Préfecture 43
|
||||
Fin de la vigilance jaune crue sur le Troncon Alagnon-Aval"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange orages annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture
|
||||
Service de prévision des crues : vigilance jaune crue - Troncon Allier Brivadois
|
||||
Infos : vigicrues.gouv.fr
|
||||
et mail (surveillez vos SPAM)"
|
||||
"Information Préfecture
|
||||
Service de prévision des crues : vigilance jaune crue - Troncon Haut Allier
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et mail (surveillez SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange orages annoncée.
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange orages annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange orages annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange orages annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange canicule annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange canicule annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"(%champ libre) est votre code téléalerte
|
||||
Recopiez ce code pour vous authentifier."
|
||||
"(%champ libre) est votre code téléalerte
|
||||
Recopiez ce code pour vous authentifier."
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange orages annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange orages annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information préfecture 43 :
|
||||
placement en vigilance jaune crue du troncon Alagnon.
|
||||
Risque de montée rapide des niveaux sous orage.
|
||||
Infos sur vigicrues.gouv.fr
|
||||
et mail (surveillez vos SPAM)"
|
||||
"Information préfecture 43 :
|
||||
placement en vigilance jaune crue du troncon Allier brivadois.
|
||||
Risque de montée rapide des niveaux sous orage.
|
||||
Infos sur vigicrues.gouv.fr
|
||||
et mail (surveillez vos SPAM)"
|
||||
"Information préfecture 43 :
|
||||
placement en vigilance jaune crue du troncon Haut Allier.
|
||||
Risque de montée rapide des niveaux sous orages.
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et mail (surveillez SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange orages annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange orages annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange orages annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information préfecture 43 :
|
||||
placement en vigilance jaune crues du troncon Haut Allier. Risque de montée rapide des niveaux sous orages.
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et mail (surveillez SPAM)"
|
||||
"Information préfecture 43 :
|
||||
placement en vigilance jaune crue du troncon Allier Brivadois. Risque de montée rapide des niveaux sous orage.
|
||||
Infos : vigicrues.gouv.fr
|
||||
et mail (surveillez vos SPAM)"
|
||||
"Information Préfecture 43
|
||||
Vigilance jaune crue activée sur le troncon Alagnon
|
||||
Infos sur vigicrues.gouv.fr et mail (surveillez vos SPAM)"
|
||||
"Information Préfecture 43
|
||||
Vigilance jaune crue activée sur le troncon Alagnon
|
||||
Infos sur vigicrues.gouv.fr et mail (surveillez vos SPAM)"
|
||||
"Information Préfecture
|
||||
Vigilance jaune crue activée sur le troncon Allier Brivadois
|
||||
Infos : vigicrues.gouv.fr et mail (surveillez vos SPAM)"
|
||||
"Information Préfecture
|
||||
Vigilance jaune crue activée sur le troncon Haut Allier
|
||||
Plus d\'infos sur vigicrues.gouv.fr et mail (surveillez SPAM)"
|
||||
"Info Préfecture Haute-Loire
|
||||
Vigilance orange pluie-inondation annoncée sur le 43
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"INFO Préfecture
|
||||
Service de prévision des crues : vigilance jaune crue - Troncon Loire Vellave
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et mail (surveillez vos SPAM)"
|
||||
"Information Préfecture
|
||||
Vigilance jaune crue activée sur le Troncon Haut Allier
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture
|
||||
Vigilance jaune crue activée sur le Troncon Haut Allier
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"INFO Préfecture
|
||||
vigilance jaune crue activée sur le Troncon Loire Vellave
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et mail (surveillez vos SPAM)"
|
||||
"INFO Préfecture
|
||||
vigilance jaune crue activée sur le Troncon Loire Vellave
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"INFO Préfecture
|
||||
Vigilance jaune crue activé pour le Troncon Lignon Vellave
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et par mail (surveillez SPAM)"
|
||||
"INFO Préfecture
|
||||
Vigilance jaune crue activée pour le Troncon Lignon du Velay.
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et par mail (surveillez SPAM)"
|
||||
"Information PREF 43
|
||||
Vigilance orange pluie-inondation activée sur le 43.
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information PREF 43
|
||||
Vigilance orange pluie-inondation activée sur le 43.
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture
|
||||
vigilance jaune crue activée sur le Troncon Allier Brivadois
|
||||
plus d\'infos : vigicrues.gouv.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture
|
||||
vigilance jaune crue activée sur le Troncon Allier Brivadois
|
||||
plus d\'infos : vigicrues.gouv.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"INFO Préfecture
|
||||
Vigilance orange crue activée sur le Troncon Lignon Vellave
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et mail (surveillez SPAM)"
|
||||
"INFO Préfecture
|
||||
Vigilance orange crue activée sur le Troncon Loire Vellave
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"INFO Préfecture
|
||||
Vigilance rouge crue activée sur le Troncon Lignon Vellave
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et par mail (surveillez SPAM)"
|
||||
"INFO Préfecture
|
||||
Vvigilance rouge crue activée sur le Troncon Loire Vellave
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture
|
||||
Vigilance rouge crue activée sur le Troncon Haut Allier
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et par mail (surveillez SPAM)"
|
||||
"Information Préfecture
|
||||
Service de prévision des crues : vigilance jaune crue - Troncon Haut Allier
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et mail (surveillez SPAM)"
|
||||
"Information Préfecture
|
||||
Service de prévision des crues : vigilance jaune crue - Troncon Allier Brivadois
|
||||
Infos : vigicrues.gouv.fr
|
||||
et mail (surveillez vos SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange vent annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange vent annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange vents annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Interdiction temporaire de circulation de certains PL sur RN102 secteur Sud du département
|
||||
Voir arreté préfectoral par mail
|
||||
Préf43"
|
||||
"Interdiction de circulation, véhicules transport de marchandises PTAC >7.5 t, RN88 et RN102 secteur Sud du département
|
||||
PJ : arreté préfectoral
|
||||
Préf43"
|
||||
"Interdiction de circulation, véhicules transport de marchandises PTAC >7.5 t sur RN88 et RN102 : secteur SUd du département.
|
||||
Obligation port d\'équipement hivernaux tous véhicules.
|
||||
PJ : arreté préfectoral
|
||||
Préf43"
|
||||
"Interdiction de circulation, véhicules de transport collectif de plus de 3.5t du vendredi 07 février 2025 22h00 au dimanche 09 février 18h00, sur les nationales 88 et 102 au sud du département de la Haute-Loire
|
||||
PJ : arreté préfectoral
|
||||
Préf43"
|
||||
"Info Préf 43
|
||||
Vigilance orange neige-verglas annoncée samedi 08/02/25 de 00h à 21h
|
||||
Plus d\'infos sur vigilance.meteofrance.fr et par mail (surveillez vos SPAM)"
|
||||
"Info Préf 43
|
||||
Vigilance orange neige-verglas annoncée samedi 08/02/25 de 00h à 21h
|
||||
Plus d\'infos sur vigilance.meteofrance.fr et par mail (surveillez vos SPAM)"
|
||||
"Interdiction de circulation, véhicules transport de marchandises PTAC >7.5 t sur RN88, secteur Nord/Est du département dans le sens Firminy- le puy-en - Velay
|
||||
Obligation port d\'équipement hivernaux tous véhicules.
|
||||
PJ : arreté préfectoral
|
||||
Préf43"
|
||||
"Interdiction de circulation, véhicules transport de marchandises PTAC >7.5 t, RN88 secteur Nord/Est du département (sens LE PUY EN VELAY-ST ETIENNE).
|
||||
PJ : arreté préfectoral
|
||||
Préf43"
|
||||
"Fin de l\'interdiction de circulation, pour les véhicules de transport de marchandises PTAC >7.5 t sur RN88 secteur Nord/Est du département, dans les deux sens .
|
||||
Préf43"
|
||||
"Fin de l\'interdiction de circulation, pour les véhicules de transport de marchandises PTAC >7.5 t et des transports en commun de plus de 3,5 t de PTAC sur la RN88 et la RN102, secteur Sud du département.
|
||||
Préf43"
|
||||
"INFO Préfecture
|
||||
Service de prévision des crues : vigilance jaune crue - Troncon Loire Vellave
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et mail (surveillez vos SPAM)"
|
||||
"Information Préfecture
|
||||
Service de prévision des crues : vigilance jaune crue - Troncon Haut Allier
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et mail (surveillez SPAM)"
|
||||
"Information Préfecture
|
||||
Service de prévision des crues : vigilance jaune crue - Troncon Haut Allier
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et mail (surveillez SPAM)"
|
||||
"Information Préfecture
|
||||
Service de prévision des crues : vigilance jaune crue - Troncon Haut Allier
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et mail (surveillez SPAM)"
|
||||
"INFO Préfecture
|
||||
Service de prévision des crues : vigilance jaune crue - Troncon Loire Vellave
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et mail (surveillez vos SPAM)"
|
||||
"INFO Préfecture
|
||||
Service de prévision des crues : vigilance jaune crue - Troncon Loire Vellave
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et mail (surveillez vos SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange orages annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange orages annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange orages annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Infos Préfet Haute-Loire
|
||||
Vigilance orange pluie-inondation demain à partir de 10h. Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Infos Préfet Haute-Loire
|
||||
Vigilance orange pluie-inondation demain à partir de 10h. Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture
|
||||
Service de prévision des crues : vigilance jaune crue - Troncon Haut Allier
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et mail (surveillez SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange orages annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"(%champ libre) est votre code téléalerte
|
||||
Recopiez ce code pour vous authentifier."
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange orages annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange orages annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange canicule à compter de dimanche 12h
|
||||
infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange canicule à compter de dimanche 12h
|
||||
infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange orages annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange orages étendue jusqu\'à 22h
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange canicules annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
la levée de la vigilance orange canicule annoncée pour ce soir 22h
|
||||
plus d\'infos sur https:/vigilance.meteofrance.fr/"
|
||||
"Information Préfecture
|
||||
Service de prévision des crues : vigilance jaune crue - Troncon Haut Allier
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et mail (surveillez SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange orages annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr et par mail
|
||||
(Surveillez vos SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange orages annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr et par mail
|
||||
(Surveillez vos SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange orages annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr et par mail
|
||||
(surveillez vos SPAM)"
|
||||
"Information Préfecture Haute-Loire
|
||||
Vigilance orange orages annoncée
|
||||
Plus d\'infos sur vigilance.meteofrance.fr
|
||||
et par mail (surveillez vos SPAM)"
|
||||
"Information Préfecture
|
||||
Service de prévision des crues : vigilance jaune crue - Troncon Allier Brivadois
|
||||
Infos : vigicrues.gouv.fr
|
||||
et mail (surveillez vos SPAM)"
|
||||
"Information Préfecture 43
|
||||
Service de prévision des crues : Vigilance jaune crue - Troncon Alagnon
|
||||
Infos sur vigicrues.gouv.fr
|
||||
et mail (surveillez vos SPAM)"
|
||||
"Information Préfecture
|
||||
Service de prévision des crues : vigilance jaune crue - Troncon Haut Allier
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et mail (surveillez SPAM)"
|
||||
"Interdiction de circulation, véhicules transport de marchandises PTAC >7.5 t, RN88 et RN102 secteur Sud du département
|
||||
PJ : arreté préfectoral
|
||||
Préf43"
|
||||
"Interdiction de circulation, véhicules transport de marchandises PTAC >7.5 t, RN88 extreme Sud du département (Pradelles/Langogne)
|
||||
PJ : arreté préfectoral
|
||||
Préf43"
|
||||
"Fin de l\'interdiction de circulation, pour les véhicules de transport de marchandises PTAC >7.5 t sur RN88 de Pradelles en direction de Langogne
|
||||
Préf43"
|
||||
"Information Préfecture
|
||||
Service de prévision des crues : vigilance jaune crue - Troncon Haut Allier
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et mail (surveillez SPAM)"
|
||||
"Information Préfecture
|
||||
Service de prévision des crues : vigilance jaune crue - Troncon Allier Brivadois
|
||||
Infos : vigicrues.gouv.fr
|
||||
et mail (surveillez vos SPAM)"
|
||||
"Interdiction de circulation, véhicules transport de marchandises PTAC >7.5 t, RN88 Sud du département Haute-Loire
|
||||
PJ : arreté préfectoral
|
||||
Préf43"
|
||||
"Interdiction circulation ts véhicules sur RN88, dans les 2 sens, entre sortie 50 (Le Monteil) et le giratoire des Fangeas
|
||||
PJ : AP
|
||||
Préf43"
|
||||
"Fin de l\'interdiction de circulation ts véhicules sur RN88.
|
||||
Les déviations mises en place restent conseillées pour le transit PL
|
||||
Préf43"
|
||||
"Interdiction de circulation, véhicules transport de marchandises articulés, RN88 et RN102 secteur Sud du département
|
||||
PJ : arreté préfectoral
|
||||
Préf43"
|
||||
"Prolongation jusqu\'à 20h de l\'interdiction de circulation, véhicules articulés de transport de marchandises , RN88 et RN102 Sud du 43"
|
||||
"Information Préfecture
|
||||
Service de prévision des crues : vigilance jaune crue - Troncon Haut Allier
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et mail (surveillez SPAM)"
|
||||
"Information Préfecture
|
||||
Service de prévision des crues : vigilance jaune crue - Troncon Haut Allier
|
||||
Plus d\'infos sur vigicrues.gouv.fr
|
||||
et mail (surveillez SPAM)"
|
||||
"Information Préfecture
|
||||
Service de prévision des crues : vigilance jaune crue - Troncon Allier Brivadois
|
||||
Infos : vigicrues.gouv.fr
|
||||
et mail (surveillez vos SPAM)"
|
||||
"Information Préfecture
|
||||
Service de prévision des crues : vigilance jaune crue - Troncon Allier Brivadois
|
||||
Infos : vigicrues.gouv.fr
|
||||
et mail (surveillez vos SPAM)"
|
||||
"Interdiction de circulation, poids-lourds articulés transport de marchandises RN102 secteur Sud du département
|
||||
PJ : arreté préfectoral
|
||||
Préf43"
|
||||
"Interdiction de circulation, véhicules transport de marchandises PTAC >7.5 t, RN88 et RN102 secteur Sud du département
|
||||
PJ : arreté préfectoral
|
||||
Préf43"
|
||||
"Ceci est un message de test
|
||||
Un accident est survenu à l\'usine SAIPOL
|
||||
Des fumées se dégagent du site
|
||||
Veuillez ne pas sortir du batiment, calfeutrez portes et fenetres, attendez l\'arrivée des secours."
|
||||
"Message de test
|
||||
Suspicion d\'attentat au Palais de Justice.
|
||||
Confinez-vous jusqu\'à nouvel ordre."
|
||||
"Message de test
|
||||
Suspicion d\'attentat au Palais de Justice.
|
||||
Confinez-vous jusqu\'à nouvel ordre."
|
||||
"message de test
|
||||
45580
data/raw/sms_dev_maria_suff
Normal file
45580
data/raw/sms_dev_maria_suff
Normal file
File diff suppressed because it is too large
Load diff
9954
data/raw/t.log
Normal file
9954
data/raw/t.log
Normal file
File diff suppressed because one or more lines are too long
136
data/stopwords.php
Normal file
136
data/stopwords.php
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'le',
|
||||
'la',
|
||||
'les',
|
||||
'un',
|
||||
'une',
|
||||
'des',
|
||||
'à',
|
||||
'de',
|
||||
'du',
|
||||
'et',
|
||||
'en',
|
||||
'ce',
|
||||
'ces',
|
||||
'pour',
|
||||
'avec',
|
||||
'sans',
|
||||
'dans',
|
||||
'sur',
|
||||
'par',
|
||||
'au',
|
||||
'aux',
|
||||
'ne',
|
||||
'pas',
|
||||
'que',
|
||||
'qui',
|
||||
'quoi',
|
||||
'dont',
|
||||
'où',
|
||||
'quand',
|
||||
'comment',
|
||||
'pourquoi',
|
||||
'mais',
|
||||
'ou',
|
||||
'si',
|
||||
'car',
|
||||
'je',
|
||||
'tu',
|
||||
'il',
|
||||
'elle',
|
||||
'nous',
|
||||
'vous',
|
||||
'ils',
|
||||
'elles',
|
||||
'on',
|
||||
'mon',
|
||||
'ton',
|
||||
'son',
|
||||
'notre',
|
||||
'votre',
|
||||
'leur',
|
||||
'mes',
|
||||
'tes',
|
||||
'ses',
|
||||
'nos',
|
||||
'vos',
|
||||
'leurs',
|
||||
'ceci',
|
||||
'cela',
|
||||
'celui',
|
||||
'celle',
|
||||
'ceux',
|
||||
'celles',
|
||||
'lui',
|
||||
'leur',
|
||||
'moi',
|
||||
'toi',
|
||||
'y',
|
||||
'en',
|
||||
'là',
|
||||
'ici',
|
||||
'là-bas',
|
||||
'alors',
|
||||
'ainsi',
|
||||
'donc',
|
||||
'or',
|
||||
'ni',
|
||||
'car',
|
||||
'tandis',
|
||||
'pendant',
|
||||
'malgré',
|
||||
'bien que',
|
||||
'si',
|
||||
'quand',
|
||||
'lorsque',
|
||||
'au moment où',
|
||||
'tant que',
|
||||
'aussitôt que',
|
||||
'dès que',
|
||||
'après que',
|
||||
'avant que',
|
||||
'jusqu\'à ce que',
|
||||
'pour que',
|
||||
'afin que',
|
||||
'de sorte que',
|
||||
'de peur que',
|
||||
'sans que',
|
||||
'en attendant que',
|
||||
'quoique',
|
||||
'bien que',
|
||||
'encore que',
|
||||
'même si',
|
||||
'et',
|
||||
'ou',
|
||||
'mais',
|
||||
'car',
|
||||
'donc',
|
||||
'or',
|
||||
'ni',
|
||||
'tandis que',
|
||||
'pendant que',
|
||||
'malgré que',
|
||||
'bien que',
|
||||
'quoique',
|
||||
'encore que',
|
||||
'même si',
|
||||
'aussi',
|
||||
'de plus',
|
||||
'en outre',
|
||||
'par ailleurs',
|
||||
'de même',
|
||||
'en effet',
|
||||
'd\'ailleurs',
|
||||
'de surcroît',
|
||||
'en plus',
|
||||
'de même',
|
||||
'en réalité',
|
||||
'en vérité',
|
||||
'en fait',
|
||||
'en réalité',
|
||||
'en vérité',
|
||||
];
|
||||
67
data/whitelist.php
Normal file
67
data/whitelist.php
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
// Risques et Phénomènes (Poids fort : 80-100)
|
||||
'attentat' => 100,
|
||||
'mort' => 100,
|
||||
'seveso' => 90,
|
||||
'explosion' => 90,
|
||||
'typhon' => 90,
|
||||
'tempête' => 90,
|
||||
'tornade' => 90,
|
||||
'submersion' => 90, // Nouveau : identifié dans plusieurs exercices
|
||||
'crue' => 90, // Nouveau : terme récurrent pour les inondations majeures
|
||||
'incendie' => 80,
|
||||
'feu' => 80,
|
||||
'inondation' => 80,
|
||||
'effondrement' => 80,
|
||||
'canicule' => 80, // Nouveau : alertes météo santé [cite: 13359, 13365]
|
||||
'orage' => 80, // Nouveau : source de vigilance orange [cite: 10774]
|
||||
'sanitaire' => 80,
|
||||
'gaz' => 80,
|
||||
'poi' => 80,
|
||||
'ppi' => 80,
|
||||
'toxic' => 80, // Nouveau : mentionné pour la pollution/nuage [cite: 4041]
|
||||
|
||||
// Consignes de sécurité (Poids moyen : 60-70)
|
||||
'confinement' => 70,
|
||||
'calfeutrez' => 70, // Nouveau : consigne spécifique risque industriel
|
||||
'evacuer' => 60,
|
||||
'sinistre' => 60,
|
||||
'consigne' => 60, // Nouveau : introduit souvent les ordres de sécurité [cite: 13361]
|
||||
'vigilance' => 60, // Augmenté : très présent avec code couleur
|
||||
|
||||
// Acteurs et Sources (Poids modéré : 30-50)
|
||||
'secours' => 50,
|
||||
'police' => 50,
|
||||
'pompiers' => 50,
|
||||
'sapeurs-pompiers' => 50,
|
||||
'gendarmerie' => 50,
|
||||
|
||||
// État et Information (Poids modéré : 30-50)
|
||||
'collision' => 50,
|
||||
'accident' => 50,
|
||||
'incident' => 50,
|
||||
'réanimation' => 50,
|
||||
'noyade' => 50,
|
||||
'décédé' => 50,
|
||||
'dégâts' => 40,
|
||||
'alerte' => 40,
|
||||
'canicule' => 40,
|
||||
'attaque' => 40,
|
||||
'seisme' => 40,
|
||||
'orage' => 40,
|
||||
'crue' => 40,
|
||||
'exercice' => 40,
|
||||
'astreinte' => 40,
|
||||
'verglas' => 40,
|
||||
'neige' => 40,
|
||||
'simulation' => 40, // Nouveau : souvent lié à l'exercice [cite: 13361]
|
||||
'urgent' => 30,
|
||||
'fuite' => 30,
|
||||
'attention' => 30,
|
||||
'prefecture' => 30, // Nouveau : source officielle de l'information [cite: 10770, 12243]
|
||||
'téléalerte' => 30 // Nouveau : système automatisé [cite: 4, 408]
|
||||
];
|
||||
BIN
model.rbx
Normal file
BIN
model.rbx
Normal file
Binary file not shown.
225
output/ignored.php
Normal file
225
output/ignored.php
Normal file
File diff suppressed because one or more lines are too long
195
output/negative.php
Normal file
195
output/negative.php
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
<?php
|
||||
|
||||
return array (
|
||||
0 => '- 31/08 à 19h : concert de chantaj duo',
|
||||
1 => '- rappel - ce soir à 19 h, à l\'ancienne école élémentaire de l\'aiguille (rue de picardie), vous etes convié à une réunion publique d\'information sur la recomposition urbaine de trèbes suite aux inondations de 2018',
|
||||
2 => '00-11/carte à retirer au guichet 11 s/pref de sgl, exclusivement le jeudi 20 juillet 2017 de 08h45 à 15h00 avec passeport recepisse titre séjour sans timbres fiscaux.',
|
||||
3 => '1. si vous n\'etes pas encore inscrit sur les listes électorales ; dernier délais avant élections ce vendredi 14 mai entre 16h et 18h. (amenez pièce d\'identité et justificatif de domicile) 2. vous pouvez retirer vos sacs poubelles et attrape frelons en mairie aux heures d\'ouverture habituelles',
|
||||
4 => '225 € sgl/carte à retirer à la s/pref sgl, du lundi au vendredi de 8h45 à 15h00, fermé le mardi avec passeport, ancienne carte de séjour, récépissé et 225 € en timbres fiscaux dématérialisés. l\'accès au guichet est conditionné à la présentation de ce message.',
|
||||
5 => '225/carte à retirer sp rambouillet / 8h45-12h30 / lundi mardi jeudi vendredi avec passeport récépissé titre séjour et 225 € en timbres fiscaux dématérialisés à partir du 25 novembre 2020. l\'accès au guichet est conditionné à la présentation de ce message. le port du masque est obligatoire et l\'utilisation de son propre stylo recommandée.',
|
||||
6 => '225/carte à retirer sp rambouillet / 8h45-12h30 / lundi mardi jeudi vendredi avec passeport récépissé titre séjour et 225 € en timbres fiscaux dématérialisés à partir du 28/06/2021. l\'accès au guichet est conditionné à la présentation de ce message. le port du masque est obligatoire et l\'utilisation de son propre stylo recommandée.',
|
||||
7 => '25 €/ carte à retirer à la s/pref sgl, mecredi 5 juillet 2023 de 13h à 15h, avec passeport, ancienne carte de séjour, récépissé et 25 € en timbres fiscaux dématérialisés. l\'accès au guichet est conditionné à la présentation de ce message.',
|
||||
8 => '269/carte à retirer au guichet 10, s/pref de saint-germain-en-laye a partir du 23 janvier 2018 le lundi, mardi, jeudi, vendredi, de 13h à 15h avec passeport, récépissé, titre séjour et 269 € en timbres fiscaux.',
|
||||
9 => '75€/ carte à retirer à la s/pref sgl,lundi 24 juillet de 13h à 15h, avec passeport, ancienne carte de séjour, récépissé et 75 € en timbres fiscaux dématérialisés. l\'accès au guichet est conditionné à la présentation de ce message.',
|
||||
10 => 'apéro-photovoltaique le samedi 1er oct.de 17h à 19h au foyer : une conférence sur l\'énergie solaire en autoconsommation. inscription au 07 56 41 02 39',
|
||||
11 => 'association natur\'en herbes organise le samedi 1 juin de 13h à 22h30, place du foyer à luc, le festival "druides et soeurcières" avec marché, animations, jeux de kermesse. restauration sur place. concert rock à 20h00.',
|
||||
12 => 'attention: changement de mois bonjour, les inscriptions cantine pour la semaine du 28 février au 4 mars sont à effectuer avant mardi 22 février à 9h.',
|
||||
13 => 'bonjour demande de personnels disponible en alertable',
|
||||
14 => 'bonjour les brebis de m alquier seront à la garrigue à partir de la semaine prochaine. garder vos chiens près de vous. merci mairie de luc sur aude',
|
||||
15 => 'bonjour votre titre de séjour est disponible à la sous-préfecture le 12/01/2021 entre 8h45 et 12h ou 13h et 15h45. vous devez vous présenter avec votre passeport,votre ancien titre et votre récépissé et un timbre électronique d\'une valeur de 25 €. le port du masque est obligatoire',
|
||||
16 => 'bonjour, ? vous etes convoqué le 18 juin 2020 à 13h. vous devrez apporter les documents suivants : - 4 photographies aux normes - décision de l\'ofpra ou la cnda (original et copie) - acte de naissance de l\'ofpra (original et copie) - un justificatif de domicile de moins de trois mois listé ci-dessous : tel qu\'indiqué sur la fiche du service public :https://www.service-public.fr/particuliers/vosdroits/f33052 ou une domiciliation auprès d\'une association agréée ou une domiciliation auprès d\'un ccas ? je vous invite à respecter strictement le jour et l\'heure indiquée. port du masque. cordialement bureau asile',
|
||||
17 => 'bonjour, adrien grégoire apiculteur sur le village propose un atelier, tout niveau, pour se sentir à l\'aise à suivre l"évolution de vos colonies d\'abeilles au fil de la saison. plus d\'informations et tarifs au 06 14 74 51 34. suite au présence des moustiques tigres sur la commune il est recommandé de vider vos récipients avec l\'eau stagnante dans lequel ils se reproduisent.',
|
||||
18 => 'bonjour, après 3 ans d\'absence l\'association des chasseurs de luc sur aude sera heureuse de vous accueillir à son repas annuel le samedi 9 juillet. inscriptions auprès de m daniel gambus au 06 06 45 42 87. prix journée (midi et soir) 25, repas midi 20, repas soir 15.',
|
||||
19 => 'bonjour, bilan du mandat ce vendredi 10 octobre à 18h00 dans la salle du pressoir. mairie de luc',
|
||||
20 => 'bonjour, bonjour, l\'association des chasseurs de luc va cuisiner une daube de sanglier. les barquettes de 4/5 parts seront vendues au prix de 10 , elles peuvent etre congelées et seront disponibles le vendredi et samedi 18 et 19 juillet de 17 à 19h, place de la mairie. pour tout renseignement: m gambus daniel au 06 06 45 42 87',
|
||||
21 => 'bonjour, c\'est bien le dimanche 25 et non le 24. mes excuses !',
|
||||
22 => 'bonjour, c\'est bien le samedi 11 novembre et non le vendredi. mes excuses !',
|
||||
23 => 'bonjour, ce dimanche 13 juillet à 19h au beaubar, concert de crossroad project avec sophie (basse, violoncelle et choeurs) et gilles (guitare, dobro, banjo, harmo, voix). artistes au chapeau. pensez à prendre de quoi grignoter si vous souhaitez manger sur place. association lucioles',
|
||||
24 => 'bonjour, ce mercredi 29 février, de 10-12h, devant le foyer : le beaubar avec danièle et son stand de légumes ainsi philippe "des mots et des bulles", bouquiniste avec son librairie-bouqui-bus ! à mercredi !',
|
||||
25 => 'bonjour, ce samedi 27 aout aura lieu la traditionnelle fete du village, organisé par le comité des fetes, avec concours de pétanque en triplette, repas, et bal avec dj. inscription pour le repas au 06 13 51 69 36.',
|
||||
26 => 'bonjour, ce samedi 28 octobre à 19h30 une retraite aux flambeaux est organisée pour le festival "samhain fest". départ cimetière, arrivée place du foyer. tous les habitants sont chaleureusement invités. restauration et buvette à la salle du foyer.',
|
||||
27 => 'bonjour, ce vendredi 11 mars à 20h30 au foyer une pièce de théatre tout public par la "compagnie ephémère" via l\'atp. entrée 10 pour les lucois.',
|
||||
28 => 'bonjour, ce vendredi soir à 18h00 au pressoir, michael dif et l\'équipe de l\'association causes communes 11 présenteront leur projet de concentrateur solaire qui s\'installera à luc. le beaubar sera ouvert pour poursuivre questions et échanges.',
|
||||
29 => 'bonjour, cette semaine la mairie est ouverte au public le matin de 9 à 12 h et fermée l\'après midi. le secrétariat de la mairie de luc sera fermé pour congés du 05 au 16 aout inclus. en cas d\'urgence vous pouvez appeler m le maire au 06 80 40 58 60. merci pour votre compréhension.',
|
||||
30 => 'bonjour, comme suite à la réforme des redevances de l\'agence de l\'eau pour les années 2025-2030, une adaptation du logiciel est nécessaire pour le transfert de la facturation sur la plateforme de la dgfip et elle s\'effectuera en juin. la facturation d\'eau pour la consommation 2024 aura donc lieu fin juin début juillet 2025. mairie de luc',
|
||||
31 => 'bonjour, comme suite à la réunion publique de mercredi, nous vous communiquons l\'adresse mail où vous pouvez joindre l\'entreprise au cas où que vous voudriez poser une question ou faire une remarque: info@solhelar.eu',
|
||||
32 => 'bonjour, comme vous le savez la situation en ukraine entraine un flux de réfugiés en europe et notamment en france ; chacun doit prendre sa part dans le malheur qui accable les familles touchées. chacun peut faire quelque chose selon ses possibilités et ses moyens ; je vous invite à participer à une réunion d\'information sur cette question qui aura lieu samedi 2 avril à 18h à la salle du pressoir. le maire',
|
||||
33 => 'bonjour, demain mardi 11 novembre à 11h aura lieu au monument aux morts la cérémonie de célébration de la paix ; vous etes invités à y participer le maire',
|
||||
34 => 'bonjour, des cendres chaudes déposées dans une benne à ordures ont failli mettre le feu à la benne, il y a quelques jours. il est donc rappelé que les cendres chaudes ne doivent pas etre déposées dans les containers à ordures. les cendres de bois doivent etre épandues dans le jardin elles sont riches en potasse et divers minéraux et contribueront à la fertilité du sol. merci.',
|
||||
35 => 'bonjour, des travaux de goudronnage des rues et chemins de la commune vont commencer à partir de mercredi ; merci de faciliter les travaux de l\'entreprise et de ne pas laisser vos véhicules stationner sur la voie publique.',
|
||||
36 => 'bonjour, dimanche 2 mars l\'association luciole organise une balade autour du village, le départ est à 13h devant le foyer avec retour au beaubar pour partager le gouter tous ensemble. accessible à tous, sans inscription. a dimanche !',
|
||||
37 => 'bonjour, dimanche 20 juillet au beaubar à luc-sur-aude concert avec zou ! reprises festives (balkans, forro, chansons) artistes au chapeau',
|
||||
38 => 'bonjour, dimanche 24 février une équipe de bénévoles se propose de nettoyer les berges de l\'aude afin d\'oter tous les déchets présents sur les rives. les habitants de luc sont invités à s\'y joindre. rendez vous à 8h45 au foyer de luc. inscriptions au 06 23 24 95 57',
|
||||
39 => 'bonjour, dimanche 5 février aura lieu à couiza une formation aux premiers secours à la quelle chacun est invité à participer ; se renseigner à la mairie.',
|
||||
40 => 'bonjour, du mardi 13 janvier au vendredi 16 des travaux de voiries seront engagés sur le chemin de castillou, laquelle voie sera temporairement inaccessible.',
|
||||
41 => 'bonjour, en raison des conditions météorologiques défavorables, nous sommes dans l\'obligation de reporter la manifestation "rocheville à la campagne" prévue ce samedi 15 et dimanche 16 novembre 2025. nous vous donnons rendez-vous pour cet évènement familial le samedi 10 et dimanche 11 janvier 2026.',
|
||||
42 => 'bonjour, grand vide-maison (meubles-vaisselle-linge maison-bibelots) 1 lot la carairado, ce samedi 26 juillet de 10-18h et dimanche 27 juillet de 9-16h. info 06 45 66 92 50.',
|
||||
43 => 'bonjour, gratiferia et forum ouvert sur l\'autonomie alimentaire ce dimanche 26 septembre à partir de14h au foyer de luc.',
|
||||
44 => 'bonjour, jeudi 3 juin à 18h, salle du pressoir, vous etes invités à participer à la réunion publique que tiendra m pierre castel dans le cadre des élections départementales prochaines.',
|
||||
45 => 'bonjour, l\'acca de luc organise un vide grenier au foyer de luc le samedi 11 mai à partir de 7h00. stand 1 le mètre linéaire. inscriptions m baeza : 06 95 12 48 80 restauration sur place.',
|
||||
46 => 'bonjour, l\'acca de luc, peyrolles et serres sont heureuses de vous accueillir à leur repas annuel le samedi 14 juin à peyrolles. inscriptions au plus tard le 07 juin auprès de daniel gambus au 06 06 45 42 87 ou jean louis carbonneau au 07 81 41 29 36. prix journée 25, repas midi 20, repas soir 15.',
|
||||
47 => 'bonjour, l\'association luciole offre l\'apéritif à tous les lucois et lucoises pour l\'ouverture du beau bar le dimanche 10 juillet à 18h sur la place de la mairie. a dimanche !',
|
||||
48 => 'bonjour, l\'enquete publique de la déclaration de projet modifiant de plu aura lieu en mairie de luc sur aude du 7 mai à 9h00 au 23 mai à 18h00. le commissaire enqueteur recevra le public le 7 mai de 9h à 12h et le 23 mai de 15h à 18h. vous pouvez consulter le dossier le lundi, mercredi et vendredi de 9h à 12h et de 15h à 17h, le vendredi jusqu\'à 19h. le maire.',
|
||||
49 => 'bonjour, l\'inhumation de najat garcia, ancienne conseillère municipale, décédée dimanche soir aura lieu aujourd\'hui à 14h au cimetière de couiza. mairie de luc',
|
||||
50 => 'bonjour, l\'inspection d\'académie a averti le maire ce jour que la classe de luc sur aude ne fermera pas. merci à tous de votre mobilisation !',
|
||||
51 => 'bonjour, l\'opération brioche des hirondelles 2019 au profit des personnes en situation handicap a débutée. les brioches au prix de 6 sont en vente en mairie à partir de vendredi 11 octobre, aux heures d\'ouverture habituelles.',
|
||||
52 => 'bonjour, l\'opération brioches de l\'afdaim est lancée. les brioches sont au prix de 6 euro et au profit des projets d\'amélioration des conditions de vie des personnes handicapées. aux heures d\'ouverture de la mairie à partir de ce matin. merci bien.',
|
||||
53 => 'bonjour, l\'opération brioches de l\'afdaim est lancée. les brioches sont au prix de 7 euro et au profit des projets d\'amélioration des conditions de vie des personnes handicapées. aux heures d\'ouverture de la mairie à partir de cet après-midi. merci bien.',
|
||||
54 => 'bonjour, la déchetterie de montazels a rouvert aux horaires habituels d\'ouverture; le mardi, mercredi et vendredi 8-12h et 14-18h. le jeudi 8-12h et le samedi 9-12h et 14-18h. fermeture de lundi et jeudi après-midi. mairie de luc',
|
||||
55 => 'bonjour, la déchetterie sera fermée exceptionnellement demain mardi après midi. la mairie',
|
||||
56 => 'bonjour, la liste "luc sur aude par vous et pour vous", vous invite à la présentation de ses membres et de ses projets mardi 3 février à 18h au foyer',
|
||||
57 => 'bonjour, la secrétaire étant en formation la mairie sera fermé le lundi 11 mars toute la journée et le vendredi 15 mars de 14h à 17h. merci pour votre compréhension.',
|
||||
58 => 'bonjour, la secrétaire étant en formation la mairie sera fermée le vendredi 14 novembre l\'après-midi. merci pour votre compréhension.',
|
||||
59 => 'bonjour, la semaine du 21 au 25 octobre le secrétariat de mairie sera ouvert que le lundi et vendredi matin de 9h00 à midi. merci de votre compréhension.',
|
||||
60 => 'bonjour, la société solhelar prévoit un important projet tant à la borde de luc que sur la zone artisanale ; ce projet à termes transformera l\'économie du village. une présentation publique en sera faite mercredi 28 juin à 18h salle du pressoir, soyez nombreux à y assister. le maire',
|
||||
61 => 'bonjour, le comité des fetes organise le 31 aout un concours de pétanque, un repas et soirée dansant avec le duo epsylon. pensez à vous inscrire pour le repas au 04 68 74 07 60 venez nombreux !',
|
||||
62 => 'bonjour, le conseil municipal s\'est réuni hier et a élu jean-claude pons maire, mm hédy dargere et dominique droit, adjoints. l\'équipe est opérationnelle pour ce nouveau mandat.',
|
||||
63 => 'bonjour, le doyen du village m garros est décédé à l\'age de 104 ans. une cérémonie aura lieu à l\'église de luc lundi 16 décembre à 15h00. le maire',
|
||||
64 => 'bonjour, le mardi 4 octobre à 18h00 salle du foyer, aura lieu une réunion publique sur les projets d\'aménagement du foyer et coeur du village.',
|
||||
65 => 'bonjour, le prochain conseil municipal de luc sur aude se tiendra le mardi 19 septembre à 18h à la mairie. vous etes les bienvenus.',
|
||||
66 => 'bonjour, le secrétariat de la mairie de luc sera fermé jusqu\'au 20 aout inclus. merci pour votre compréhension.',
|
||||
67 => 'bonjour, le secrétariat de la mairie de luc sera fermé pour congés du 18 au 22 juillet inclus. en cas d\'urgence vous pouvez appeler m le maire au 06 80 40 58 60. merci pour votre compréhension.',
|
||||
68 => 'bonjour, le secrétariat de la mairie de luc sera fermé pour congés du 23 au 27 décembre inclus. en cas d\'urgence vous pouvez appeler m le maire au 06 80 40 58 60. merci pour votre compréhension.',
|
||||
69 => 'bonjour, le secrétariat de la mairie de luc sera fermé pour congés du 25 aout au 5 septembre inclus. en cas d\'urgence vous pouvez appeler m le maire au 06 80 40 58 60. merci pour votre compréhension.',
|
||||
70 => 'bonjour, le secrétariat de mairie est fermé jusqu\'au 2 janvier inclus pour congés. joyeuses fetes de fin d\'année !',
|
||||
71 => 'bonjour, les caisses bleues ne sont plus relevés. le contenue est à déposer directement dans les containers prévus à cet effet. personnes agées et handicapées peuvent contacter la mairie.',
|
||||
72 => 'bonjour, les déchetteries sont ouvert seulement pour les communes, donc ceux qui parmi vous qui ont des déchets verts à faire enlever doivent contacter denis au 06 50 67 27 90. mairie de luc',
|
||||
73 => 'bonjour, les habitants sont invités à participer à la cérémonie du lundi 11 novembre qui aura lieu à 11h devant le monument aux morts, avec la participation des élèves de l\'école; la matinée se terminera par un vin d\'honneur servi à la mairie. mairie de luc sur aude',
|
||||
74 => 'bonjour, les habitants sont invités à participer à la cérémonie du lundi 11 novembre qui aura lieu à 11h30 devant le monument aux morts. la matinée se terminera par un vin d\'honneur servi à la mairie. mairie de luc sur aude',
|
||||
75 => 'bonjour, les habitants sont invités à participer à la cérémonie du vendredi 11 novembre qui aura lieu à 11h00 devant le monument aux morts. la matinée se terminera par un vin d\'honneur servi à la mairie. mairie de luc sur aude',
|
||||
76 => 'bonjour, les habitants sont invités à participer à la cérémonie du vendredi 11 novembre qui aura lieu à 11h30 devant le monument aux morts. la matinée se terminera par un vin d\'honneur servi à la mairie. mairie de luc sur aude',
|
||||
77 => 'bonjour, lundi 11 novembre aura lieu à 11h la cérémonie à la paix devant le monument aux morts, en présence de la classe de ce2, ce sera l\'occasion de célébrer particulièrement la mémoire de lucide gambus. le maire',
|
||||
78 => 'bonjour, m ghislain hick, 1 rue du chateau, a trouvé une belle tortue dans son jardin. il recherche son éventuel propriétaire. mairie de luc',
|
||||
79 => 'bonjour, m le maire vous invite le vendredi 21 juin à 18h à l\'inauguration du nouveau local aménagé près du pressoir pour le beaubar, suivie d\'un verre de l\'amitié et de la fete de la musique de l\'asso luciole avec 3 groupes.',
|
||||
80 => 'bonjour, mardi 13 juillet à 10h aura lieu l\'inauguration d\'une village en transition par mr le préfet de l\'aude ; vous etes invités à cette manifestation ainsi qu\'au buffet qui suivra ; il vous est demandé de vous inscrire auprès de la mairie.',
|
||||
81 => 'bonjour, marine tondelier secrétaire générale des verts a souhaité visiter la commune de luc sur aude ; elle sera présente à partir de 11h mardi 13 juin à la salle du pressoir , tous ceux qui veulent participer à la rencontre sont les bienvenus.',
|
||||
82 => 'bonjour, mr alquier a mis ses brebis au paturage sur la garrigue. attention aux chiens pour les promeneurs, attention aux chiens errants hors controle des maitres.',
|
||||
83 => 'bonjour, mr alquier va mettre ses brebis au paturage sur la garrigue. attention aux chiens pour les promeneurs, attention aux chiens errants hors controle des maitres.',
|
||||
84 => 'bonjour, nous vous informons que la prochaine séance du conseil municipal aura lieu jeudi 16 décembre à 20h30. mairie de luc sur aude',
|
||||
85 => 'bonjour, nous vous informons que la prochaine séance du conseil municipal aura lieu mardi 16 juin à 20h30. mairie de luc sur aude',
|
||||
86 => 'bonjour, nous vous informons que la prochaine séance du conseil municipal aura lieu mardi 30 juin à 20h30. mairie de luc sur aude',
|
||||
87 => 'bonjour, nous vous informons que la prochaine séance du conseil municipal aura lieu mercredi 22 septembre à 20h00. mairie de luc sur aude',
|
||||
88 => 'bonjour, nous vous informons que la prochaine séance du conseil municipal aura lieu mercredi 23 septembre à 20h30. mairie de luc sur aude',
|
||||
89 => 'bonjour, nouveau à luc sur aude ; sophrologie-relaxation. des séances collectives chaque jeudi matin de 10h à 11h et 1 vendredi sur 2 de 18h30 à 20 heures. renseignements ; christelle blanquier 06 30 93 99 80',
|
||||
90 => 'bonjour, pour ceux qui ne sont pas encore inscrits, vous avez jusqu\'à vendredi soir pour vous inscrire sur les listes électorales pour les prochaines élections européennes.',
|
||||
91 => 'bonjour, pour information, le défibrillateur vient d\'etre déplacé à l\'entrée de l\'école, sous le porche de l\'entrée de l\'ancienne mairie, 14 rue du pressoir.',
|
||||
92 => 'bonjour, rappel : le mardi 4 octobre à 18h00 salle du foyer, aura lieu une réunion publique sur les projets d\'aménagement du foyer et coeur du village.',
|
||||
93 => 'bonjour, samedi 13 décembre de 18h à 20h30 à peyrolles une conférence sur des rapaces nocturnes. marche 1 km, à partir de 6 ans. inscriptions au 07 72 51 56 88.',
|
||||
94 => 'bonjour, samedi 17 octobre à 17 h au foyer municipal de luc-sur-aude. la compagnie création ephémère, en résidence à luc, vous invite à découvrir leur travail de répétition en cours et à un moment de partage autour des métiers du spectacle vivant. entrée libre.',
|
||||
95 => 'bonjour, samedi 22 octobre à 21h00 au foyer, pièce de théatre "lettres croisées" de jean paul alègre interprété par la compagnie de théatre en fenouillèdes. entrée 5, gratuit pour les moins de 12 ans. a ne pas louper !',
|
||||
96 => 'bonjour, si vous etes impacté par des coupures de courants récurrentes vous pouvez le signaler à enedis au numéro 09 72 67 50 11. mairie de luc sur aude',
|
||||
97 => 'bonjour, suite au rachat de la maison du 3 rue du pressoir, la mairie souhaite se séparer d\'une partie du mobilier et des objets qui s\'y trouvent ; la maison sera ouverte samedi 14 octobre prochain de 10 à 12h à ceux qui sont intéressés par cette offre. le maire',
|
||||
98 => 'bonjour, un chat errant a été capturé par les services de la mairie merci à son propriétaire de se manifester auprès de la mairie pour le récupérer. mairie de luc',
|
||||
99 => 'bonjour, une borne nouvelle pour le tri a été installée sur la place du foyer. mairie de luc',
|
||||
100 => 'bonjour, vendredi 1 octobre 20 h au foyer municipal. spectacle l\'amour médecin de molière. atelier de théatre le samedi 2 octobre à 10h au foyer et atelier de modelage avec zarno patamodeleur à 14h, au pressoir. inscription et renseignements au 06 25 74 06 27 samedi 2 octobre 18 h au foyer municipal, spectacle des dégingandés (clown/musique)',
|
||||
101 => 'bonjour, vendredi 18 juin à 18 heures se tiendra à la salle du pressoir une réunion publique avec les candidats de la liste unis pour l\'aude, dans le cadre des élections départementales.',
|
||||
102 => 'bonjour, vous avez recu votre facture d\'eau aujourd\'hui mentionnant qu\'elle doit etre réglée avant le 30 septembre. ce délai est reporté au 31 octobre, vous ne recevez pas d\'amende de 10% pour retard de paiement. mairie de luc',
|
||||
103 => 'bonjour, vous etes conviés mercredi 8 janvier à 18h au foyer de luc sur aude à l\'occasion de la cérémonie des voeux du conseil municipal , suivi d\'un partage de la galette des rois. mairie de luc',
|
||||
104 => 'bonjour, vous etes conviés vendredi 12 janvier à 18h au foyer de luc sur aude à l\'occasion de la cérémonie des voeux du conseil municipal , suivi d\'un partage de la galette des rois du fournil bio de luc. mairie de luc',
|
||||
105 => 'bonjour, vous etes conviés vendredi 16 janvier à 18h au foyer de luc sur aude à l\'occasion de la cérémonie des voeux du conseil municipal. a cet occasion collecte de dons de nourriture est fait pour les restaurants du coeur. mairie de luc',
|
||||
106 => 'bonjour, vous etes conviés à la réunion de bilan des 6 années du conseil municipal sortant, qui aura lieu demain jeudi 28 novembre à 18h au pressoir.',
|
||||
107 => 'bonjour, vous etes cordialement invités à l\'assemblée générale extraordinaire de l\'association luciole qui aura lieu le mercredi 22 juin à 10h place de la mairie. association luciole',
|
||||
108 => 'bonjour, vous etes invités dimanche 12 janvier à 18h au foyer de luc pour partager la galette des rois en l\'honneur de la nouvelle année 2020. comme toujours, munissez vous de conserves, riz ou autres aliments qui seront remis au resto du coeur. merci par avance de votre générosité.',
|
||||
109 => 'bonjour, vous etes invités à la présentation de la nouvelle équipe qui se présentera à vos suffrages lors des prochaines élections municipales; cette présentation aura lieu jeudi 5 mars au foyer à 18h et sera suivi d\'un apéritif offert par les candidats. jean claude pons',
|
||||
110 => 'bonjour, vous etes invités à participer à la cérémonie des voeux pour la nouvelle année qui aura lieu vendredi 6 janvier à 18h au foyer de luc.',
|
||||
111 => 'bonjour, vous etes invités à participer à la réunion, demain jeudi à 18h salle du pressoir, qui aura pour thème la possible installation d\'infrastructure d\'énergies renouvelables sur le territoire de la commune. le maire',
|
||||
112 => 'bonjour, vous etes invités à participer à une conférence "vautours en corbières" qui aura lieu vendredi 6 mars à 20h30 à la salle du pressoir. mairie de luc',
|
||||
113 => 'bonjour, vous etes invités à prendre connaissance et à réagir au projet d\'énergie renouvelable, qui est décrit sur le site de la commune à partir du lien loi aper. le maire',
|
||||
114 => 'bonjour, vous etes invités à vous réunir sur la place de la mairie ce soir à 18h30 pour une brève cérémonie en hommage à samuel paty et en soutien aux enseignants. le maire, jean claude pons',
|
||||
115 => 'bonjour, vous etes tous invités au ciné-concert de jean marc parayre, demain jeudi 17 septembre à 21h00 au foyer. entrée gratuite, port du masque obligatoire.',
|
||||
116 => 'bonjour, vous etes tous invités au merveilleux ciné concert (la fiancée des ténèbres) interprétée par tomstone, ce samedi 29 aout à 21h00. entrée gratuite. le port du masque sera obligatoire et la distanciation sociale recommandée.',
|
||||
117 => 'bonjour, vous pouvez venir chercher des sacs poubelles à la mairie aux heures d\'ouverture habituelles à partir de vendredi 20 septembre. mairie de luc',
|
||||
118 => 'bonjour, vous trouverez les horaires d\'été de la déchetterie de montazels sur le site de la commune : https://luc-sur-aude.fr/',
|
||||
119 => 'bonsoir, pour info le chef de garde du cs bonneville nous informe que la garde postée de ce soir ne dormira pas au centre de secours en raison de la température trop élevée dans les locaux. cheffe de centre prévenue. le délais de départ sera donc plus long. ltn jean-philippe gervex.',
|
||||
120 => 'carte prete préfecture versailles av europe. retrait lundi mardi jeudi vendredi de 12h30-14h30 et mercredi 19/04/17 et 26/04/2017 de 12h30-14h30 dans la limite des tickets disponibles avec passeport récépissé titre séjour 49 e timbres fiscaux',
|
||||
121 => 'carte séjour prete préfecture versailles avenue europe. rdv mercredi 15 mars 2017 à 9 h pour retrait avec passeport récépissé titre séjour',
|
||||
122 => 'ce mercredi de 9h30 à 11h30 ouvre à la mairie une épicerie de produits locaux secs et produits frais sur commande. plus de renseignements au 09 84 55 68 54. avec toujours la vente de légumes sur la place. le port du masque ou d\'un foulard couvrant la bouche et le nez est obligatoire.',
|
||||
123 => 'ce soir à 18h au foyer, rencontre avec les conseillers départementaux. venez poser vos questions. la réunion sera close avec le verre de l\'amitié.',
|
||||
124 => 'ce vendredi 16 à 18h au pressoir aura lieu la projection d\'un film documentaire à l\'occasion du 80eme anniversaire de l\'attaque menée par la résistance le 17/8/1944 au lieu dit les roches à luc. ce vendredi 30 et samedi 31 aout aura lieu la traditionnelle fete du village, organisé par le comité des fetes, avec repas et bal le vendredi et concours de pétanque et bal avec dj le samedi. inscriptions au 06 13 51 69 36 ou 04 68 74 07 60. ville à joie et la luciole proposent au beau bar le mercredi 11 septembre de 10h à 14h : marché de producteurs, artisans locaux et services du territoire (santé, mobilité, rénovation, services département) pour répondre à vos questions ! concert polyphonique harpe /guitare et auberge espagnole le midi !',
|
||||
125 => 'ce vendredi 25 et samedi 26 aout aura lieu la traditionnelle fete du village, organisé par le comité des fetes, avec repas et bal le vendredi et concours de pétanque et bal avec dj le samedi. inscriptions au 06 13 51 69 36 ou 04 68 74 07 60.',
|
||||
126 => 'ce vendredi 27 et samedi 28 au pressoir, un moine tibétain effectuera un mandala de sable coloré. deux jeunes danseuses traditionnelles tibétaines se produiront. entrée libre et gratuite de 10h à 18h. un évènement organisé par l\'association natur\'en herbes',
|
||||
127 => 'cond waltzer incivilité (28voy40 12h29 st francois) veh 4313 il est relevé',
|
||||
128 => 'conseil municipal mardi 18 octobre à 21h à la mairie - voir ordre du jour sur le site de la commune',
|
||||
129 => 'cs la rochette: manque du personnels - poj non atteint - sofops / adc catherine cosnelle',
|
||||
130 => 'csp moutiers urgent - besoin dispotel ccr epa en inter',
|
||||
131 => 'demain 17 aout à 11h30 aura lieu, à la stèle des gorges, la commémoration annuelle du guet-apens que la résistance tendit au troupes nazis en 1945, vous etes tous conviés à y assister. le maire jean claude pons',
|
||||
132 => 'demain dimanche 22 décembre, le beaubar ouvre une dernière fois en 2024 avec un apéro solstice de 13h30 à 16h30. venez nombreux.',
|
||||
133 => 'demain samedi, à 11h, aura lieu à la stèle, la commémoration de l\'attaque du commando bournet contre le convoi nazi le 17 aout 1944.',
|
||||
134 => 'docteur, nous vous rappelons les dates et horaires de vacations pour la semaine du 14/01/19 au 18/01/19. lundi 14/01/19 matin. cordialement le secrétariat',
|
||||
135 => 'docteur, nous vous rappelons les dates et horaires de vos vacations pour la semaine du 03 au 07/02/2020 : - lundi 03/02/2020 le matin cordialement, le secrétariat',
|
||||
136 => 'docteur, nous vous rappelons les dates et horaires de vos vacations pour la semaine du 1er au 5 juillet 2019 : - jeudi 04/07/2019 le matin cordialement, le secrétariat',
|
||||
137 => 'en raison d\'une coupure artemis ce matin, inscrivez-vous si dispo adj morand soffops',
|
||||
138 => 'essai pour jef et emeline téléphonez moi pour me confirmer la réception du sms',
|
||||
139 => 'info astreinte dspintervention dans immeuble 76 cours gambetta - 69007 suite à infiltrations d\'eau liées à travaux de toiture. deux logements impactés. pas de relogement immédiat mais à prévoir dans la journée. électricité coupé par enedis dans l\'ensemble de l\'immeuble.régie et propriétaire seront contactés ce matin.autorités informées p. ciarlitti',
|
||||
140 => 'information voyageurs - s09 - plus d\'infos sur http://citeline.fr/alerts#2420',
|
||||
141 => 'informations voyageurs - lignes 33, 37 et 53 - plus d\'infos sur http://citeline.fr/alerts#2391',
|
||||
142 => 'l\'audyssée de l\'énergie citoyenne se tiendra ce jeudi 17 novembre à 17h30 à la salle du foyer. réflexions autour du photovoltaique, du low tech et du bois énergie.',
|
||||
143 => 'l\'éducation nationale veut fermer une des 2 classes de luc ; il faut s\'opposer à ce projet catastrophique comme nous l\'avons fait dans le passé. je vous invite donc à passer à la mairie pour signer la pétition',
|
||||
144 => 'la commune de luc sur aude est heureuse de vous inviter à un spectacle "tout public", ce samedi 15 avril 2023 à 17h00 au foyer. entrée libre. bizarre... bizarre... par la compagnie porte sud un atelier initiation est également proposé pour les enfants à partir de 5 ans, le samedi matin de 10h00 et 12h00 au foyer. gratuit.',
|
||||
145 => 'la peugeot 308cc noire immatriculée cd-542-qp garée sur le parking du vieux pont doit etre enlevée de toute urgence.',
|
||||
146 => 'la pose des compteurs linky a commencée. en cas de problème avec les agents d\'enedis, vous pouvez faire appel à la mairie en composant le numéro suivant : 04 48 31 00 28',
|
||||
147 => 'la rénovation de l\'éclairage public va commencer ; si certains d\'entre vous sont intéressés par le récupération des anciens candélabres, en faire la demande à la mairie.',
|
||||
148 => 'le pluih est en cours d\'élaboration. une dernière version du classement des sols vient d\'etre présentée. les propriétaires sont invités à venir en mairie lors des horaires d\'ouverture afin de vérifier le classement des parcelles. ce ven. 22/03 à 14h45, plantation d\'un arbre symbolisant la lutte contre le rascisme et antisémitisme devant le foyer. evènement suivi d\'un gouter à 15h30. message du collectif anti-linky de luc : les compteurs linky vont bientot arriver. si vous désirez le refuser, écrire en lettre rar à enedis, 78 av. du général leclerc 11100 narbonne, et en remettre une copie à la mairie pour qu\'elle puisse vous apporter son soutient si besoin. plus d\'info: 06 77 46 61 19',
|
||||
149 => 'le samedi 28 octobre le festival samhain fest aura lieu à luc sur aude: marché créateurs et artisans, food truck, restauration et buvette maquillages, ateliers enfants (contes pinata etc), danse des sorcières concours de costumes, retraite au flambeaux concerts avec gérard santi et burger queen',
|
||||
150 => 'les mesures de so2 en limite et à l\'intérieur du site sont nulles.',
|
||||
151 => 'les poubelles et containers de recyclages de l\'aire de covoiturage ont été déplacé derrière l\'entreprise nougalet, après le pont d\'espagne à droite.',
|
||||
152 => 'mairie de chamonix : rappel : commission de sécurité restreinte, mercredi 4 avril 2018 à 18h00, au majestic, salle paul payot . merci',
|
||||
153 => 'mardi 21 novembre, à 18h à la salle du foyer, aura lieu un ciné-débat autour du film "virage vers le futur !", sur le sujet des mobilités rurales. gratuit.',
|
||||
154 => 'merci de faire parvenir à la sous-préfecture de rambouillet, pour compléter votre dossier de titre de séjour les photocopies des attestations de formation civique effectuées par l \'ofii',
|
||||
155 => 'merci de faire parvenir à la sous-préfecture de rambouillet, pour compléter votre dossier, 1 photo d\'identité en précisant dessus votre nom, prénom et numéro de titre de séjour, soit 9919003726.',
|
||||
156 => 'merci de vous présenter sp rambouillet /8h45-12h30/ lundi mardi jeudi vendredi ou par voie postale pour nous fournir un justificatif de domicile (impot, edf, etc...)',
|
||||
157 => 'mercredi 14 à 11h30 aura lieu au pressoir l\'inauguration de l\'exposition "un territoire, des insectes, des oiseaux et des hommes", vous etes invités à y assister.',
|
||||
158 => 'nous rappelons que le bureau de vote sera ouvert ce dimanche de 8h à 19h.',
|
||||
159 => 'nous vous informons que la prochaine séance du conseil municipal aura lieu ce mardi 22 mars à 18h dans les locaux de la mairie.',
|
||||
160 => 'pour information : jusqu\'au 31 aout la déchetterie de montazels sera ouverte du mardi au samedi de 7h00 à 13h45.',
|
||||
161 => 'pour soutenir l\'équipe du volero en demi-finale du championnat lafla ville du cannet et le volero le cannetsont heureux de vous inviter au matchle cannet / pays d\'aix venellesmercredi 26 avril à 20h salle de la palestre(invitation à retirer sur place dans la limite des places disponibles)un match de gala ! \'\'\'',
|
||||
162 => 'prochaines dates de l\'asso luciole - ce soir 24/08 à 19h : karaoké accoustique (restauration sur place) - 27/08 à 10h : petit marché - 27/08 à 20h30 : pièce de théatre "pataugeons !',
|
||||
163 => 'préfecture de versailles (1 avenue de l\'europe) ? asile - convocation le 10/08/2020 à 8h45 pour remise de votre dossier ofpra. port du masque.',
|
||||
164 => 'préfecture de versailles (1 avenue de l\'europe) ? bureau asile/séjour? convocation protection temporaire ? vous etes convoqué le 19/04/2022 à 08h45 (ticket m) pour le traitement de votre demande d\'une protection temporaire. vous devez apporter un justificatif de domicile ou domiciliation ou une attestation d\'hébergement chez un tiers de moins de six mois, dans le département des yvelines, 4 photos d\'identité récentes, ainsi que votre passeport. cordialement. bureau de l\'asile',
|
||||
165 => 'préfecture de versailles, rendez vous en remise de titre samedi 08 juillet à 11h. sur présentation convocation obligatoire, avec passeport, titre de séjour, 25€ timbres fiscaux.',
|
||||
166 => 'punch 2025 retrouvons-nous, avec l\'ensemble des collaborateurs municipaux, pour le traditionnel punch de fin d\'année qui aura lieu le vendredi 19 décembre 2025 à partir de 17h00 en salle du conseil municipal au 1er étage ainsi qu\'au 2ème étage de l\'hotel de ville du cannet.',
|
||||
167 => 'quel bilan pour l\'europe sur le plan démocratique, économique, géopolitique ? l\'union européenne s\'est-elle construite dans l\'opacité ? conférence débat animée par thierry medynski, dea d\'études européennes lundi 24 février 2025 à 20 heures à luc sur aude, salle du pressoir entrée libre',
|
||||
168 => 'rappel : ce soir à 18h cérémonie des voeux au foyer, n\'oubliez pas un colis qui sera remis aux resto du coeur, merci par avance mairie de luc',
|
||||
169 => 'rappel, il est encore possible de se faire inscrire sur les listes électorales jusqu\'au 4 mars en passant aux heures d\'ouverture de la mairie. les familles qui peuvent et qui souhaitent accueillir des réfugiés ukrainiens sont priées de se mettre en contact avec la mairie afin de retirer le dossier stipulant leur disponibilité. en ces moments de guerre et de malheur pour certains, l\'expression de la solidarité de chacun est important. le maire.',
|
||||
170 => 'rdv ce soir au foyer avec le groupe "le bal des bois" (répertoire de musique folk-trad). entrée libre, chapeau pour les musiciens ! 19h auberge espagnole 20h30 : danse ! le beaubar sera ouvert ce soir là pour les boissons. merci d\'inviter vos voisins, vos amis, pour cette soirée conviviale... lucioles',
|
||||
171 => 'rendez vous le 23 février 2021 à 10h00 préfecture de versailles pour madame jabri jenina sur présentation du sms avec passeport récépissé titre de séjour 225€ timbres fiscaux, , , port du masque obligatoire',
|
||||
172 => 'retrait carte de séjour préfecture versailles,vous avez rendez-vous le 30/10/2023 à 9h30 à la préfecture de versailles. sur présentation convocation obligatoire, avec passeport, récépissé, titre de séjour 225€ timbres fiscaux.',
|
||||
173 => 'samedi 12 à 20h30, au foyer de luc, spectacle sur le mythe de carmen dans la peinture, en compagnie de deux extraordinaires artistes de flamenco de toulouse : la danseuse la nimeña et le guitariste et chanteur, paco ruiz. entrée gratuite pour les habitants de luc sur présentation d\'un justificatif.',
|
||||
174 => 'samedi à 17h au pressoir, conférence sur l\'utilité de l\'ennéagramme pour l\'individu et le collectif, avec du théatre dedans ! beaubar ouvert dès 16h si beau tps',
|
||||
175 => 'soirée du beau bar ce jeudi 15 aout, devant le foyer de luc avec : - 18h30, scène ouverte - 20h30, concert de tam-lin (chants celtiques) restauration sur place',
|
||||
176 => 'sp-sgl/nat/livret nat bonjour, vous avez été naturalisé francais(e) et nous vous en félicitons. dans le contexte sanitaire actuel (covid-19), les cérémonies d\'accès à la citoyenneté francaise sont annulées jusqu\'à nouvel ordre. nous vous invitons donc à retirer votre livret de nationalité le 10/07/20 entre 9h et 10h en sous-préfecture saint-germain-en-laye muni de votre titre de séjour. en cas d\'impossibilité de vous rendre à cette convocation, merci de bien vouloir nous en informer à l\'adresse suivante : pref-spsgl-ceremonies-naturalisation@yvelines.gouv.fr nous vous prions de bien vouloir nous excuser pour la gene occasionnée. cordialement. la plate-forme départementale de naturalisation des yvelines ps : si vous etes souffrant, ne vous déplacez pas.',
|
||||
177 => 'sramb / carte à retirer sp rambouillet / 8h45-12h30 / mercredi 05/04/2017 avec passeport récépissé titre séjour',
|
||||
178 => 'sur présentation sms obligatoire, retrait de carte séjour préfecture versailles, jeudi 20/07/2023 à 10h00 avec récépissé titre de séjour, respect impératif de date et heure,',
|
||||
179 => 'sur présentation sms obligatoire, retrait de carte séjour préfecture versailles, jeudi 30/07/2020 à 11h00 avec passeport récépissé 175€ timbres fiscaux, respect impératif de date et heure, venir non accompagné, port du masque',
|
||||
180 => 'sur présentation sms obligatoire, retrait de carte séjour préfecture versailles, lundi 03/08/2020 à 13h00 avec passeport récépissé titre de séjour 75€ timbres fiscaux. respect impératif de date et heure venir non accompagné port du masque',
|
||||
181 => 'sur présentation sms obligatoire, retrait de carte séjour préfecture versailles, lundi 13/07/2020 à 11h00 avec passeport récépissé 75€ timbres fiscaux, respect impératif de date et heure, venir non accompagné, port du masque',
|
||||
182 => 'sur présentation sms obligatoire, retrait de carte séjour préfecture versailles, lundi 29/06/2020 à 11h00 avec passeport récépissé 225€ timbres fiscaux, respect impératif de date et heure, venir non accompagné, port du masque',
|
||||
183 => 'sur présentation sms obligatoire, retrait de carte séjour préfecture versailles, vendredi 05/06/2020 à 13h00 avec récépissé 25€ timbres fiscaux, respect impératif de date et heure, venir non accompagné, port du masque',
|
||||
184 => 'un automate d\'appel va vous appeler pour confirmer votre inscription au systeme d\'alertes. merci de la confirmer en tapant \'1\'.',
|
||||
185 => 'un chat non identifié a été capturé voir (pj) son propriétaire est prié d\'appeler denis au 06 50 67 27 90',
|
||||
186 => 'un concert d\'orpheon son d\'aici est organisé par la mairie ce samedi 23 à 18h30 au foyer de luc. suivi d\'un apéritif dinatoire géré par l\'asso luciole. venez discuter et participer au développement de la mobilité solidaire à luc-sur-aude lors d\'une réunion au foyer, le 25 septembre 2023 à 18h. réunion co-organisée par la mairie de luc et l\'association la trame',
|
||||
187 => 'votre titre de séjour est disponible pour le retrait. vous etes convoqué le 11/10/2023 à 09h00 à la préfecture des yvelines (01 avenue de l\'europe ? 78000 versailles). merci de vous présenter 15 minutes avant l\'heure de votre rendez-vous, muni de votre passeport, votre titre de séjour actuel, votre récépissé et 225 euros en timbres fiscaux. la dmi - s3op',
|
||||
188 => 'votre titre de séjour est à retirer à la sous-préfecture de mantes-la-jolie le 13 mai entre 13h00 et 15h45 - munissez vous de votre passeport , ancien titre de séjour et /ou récépissé - le port du masque est obligatoire',
|
||||
189 => 'vous etes invités le mardi 24 septembre à 18h, salle du pressoir, à la réunion organisée par la mairie sur le bilan de la première partie de ce mandat et ses perspectives. questions et débats sont les bienvenus.',
|
||||
190 => 'vous etes invités à manifester votre soutien aux marocains affectés par le désastre du tremblement de terre en contribuant aux dons que collecte la croix rouge. rdv www.luc-sur-aude.fr',
|
||||
);
|
||||
338
output/positive.php
Normal file
338
output/positive.php
Normal file
|
|
@ -0,0 +1,338 @@
|
|||
<?php
|
||||
|
||||
return array (
|
||||
0 => '"ceci est un message de formation transports scolaires interdits de jour sur le 43 veuillez consulter l\'arreté ci-dessous ou votre messagerie',
|
||||
1 => 'alerte canicule vigilance rouge lundi 18/07 à partir de 12h. ne sortez pas aux heures les plus chaudes. hydratez-vous. eglise ouverte toute la journée. prudence',
|
||||
2 => 'alerte crue jusqu\'à au moins jeudi midi. la d118 est fermée. merci d\'économiser l\'eau afin de maintenir un niveau suffisant dans le chateau d\'eau le temps du retour à la normale. une permanence se tiendra à la mairie pendant l\'alerte. n\'hésitez pas à rappeler 2 fois le n de la mairie pour nous joindre.',
|
||||
3 => 'alerte info - risque feu de foretpour la journée du 09/08/2025les massifs forestiers marseillais sont concernés par : - météo des forets : vigilance orange- les accès aux massifs sont autorisés- restrictions de travaux : autorisés de 5h à 13h avec dispositif de prévention et d\'extinction approprié.condition météo : le ciel sera légèrement voilé, et se dégagera en milieu d\'après-midi. de belles éclaircies feront leurs apparitions vers 16h00.les températures seront comprises entre 23c et 30. un léger vent de secteur ouest soufflera sur l\'ensemble de la journée, avec des valeurs attendues comprises entre 5 et 10km/h.pour plus d\'information, veuillez consulter vos mails. merci pour votre attentiondppgr - pcs04.91.55.10.00',
|
||||
4 => 'alloires: 12h41: 1 noyade pour un homme ayant disparu de la surface du lac. il est repéché à 13h52 et en cours de réanimation. ltn barral',
|
||||
5 => 'attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site.',
|
||||
6 => 'attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site.',
|
||||
7 => 'attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site.',
|
||||
8 => 'attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site.',
|
||||
9 => 'attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (crue du golo : hauteur d\'eau supérieure à 2,5 mètres à la station volpajola) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site.',
|
||||
10 => 'attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (crue de la seine : hauteur d\'eau supérieure à 8,5 mètres à la station petit-couronne) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site.',
|
||||
11 => 'attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (crue du golo : hauteur d\'eau supérieure à 2,5 mètres à la station volpajola) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (crue de la seine : hauteur d\'eau supérieure à 8,5 mètres à la station petit-couronne) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (crue de la seine : hauteur d\'eau supérieure à 8,5 mètres à la station petit-couronne) sont prévus dans les prochaines heures au droit de votre site.',
|
||||
12 => 'attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (crue du golo : hauteur d\'eau supérieure à 2,5 mètres à la station volpajola) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (crue du golo : hauteur d\'eau supérieure à 2,5 mètres à la station volpajola) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (crue de la seine : hauteur d\'eau supérieure à 8,5 mètres à la station petit-couronne) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (crue de la seine : hauteur d\'eau supérieure à 8,5 mètres à la station petit-couronne) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (crue de la seine : hauteur d\'eau supérieure à 8,5 mètres à la station petit-couronne) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (crue de la seine : hauteur d\'eau supérieure à 8,5 mètres à la station petit-couronne) sont prévus dans les prochaines heures au droit de votre site.',
|
||||
13 => 'attention ! de violents épisodes météorologiques (crue du golo : hauteur d\'eau supérieure à 2,5 mètres à la station volpajola) sont prévus dans les prochaines heures au droit de votre site. attention ! de violents épisodes météorologiques (alerte orange meteo france) sont prévus dans les prochaines heures au droit de votre site.',
|
||||
14 => 'besoin dispotel feu de silo en cours',
|
||||
15 => 'bonjour (%civilité) (%nom) ceci est un message d\'alerte national sécheresse. merci de vous reporter à la procédure définie pour la mise en place des mesures',
|
||||
16 => 'bonjour ceci est un message de test inondation annoncée ce soir jusqu\'à demain 18h prenez vos précautions, prévenez vos voisins, abritez vos biens ecoutez 98.2',
|
||||
17 => 'bonjour, alerte jaune, vent supérieur à 70 km/h. fermeture des parcs. autorités informés. alexandra dussud, jeremy castell',
|
||||
18 => 'bonjour, bonjour, en raison d\'une fuite d\'eau sur le réseau principal, des coupures d\'eau peuvent intervenir dans la journée. prenez vos précautions. merci de votre compréhension.',
|
||||
19 => 'bonjour, ce mercredi à partir de 9h reprise du marché sur la place; les mesures de protections resteront en vigueur. mairie de luc',
|
||||
20 => 'bonjour, ceci est un message d\'alerte',
|
||||
21 => 'bonjour, ceci est un message d\'alerte le tour de france arrive dans votre ville. veillez a respecter les consignes de sécurité',
|
||||
22 => 'bonjour, ceci est un message d\'alerte suite la panne nationale affectant les lignes des services d\'urgence les numeros de substitution suivants ont ete mis en place dans le rhone et la metropole de lyon samu : 04 72 11 61 77 pompiers : 08 00 71 18 69 police nationale : 17 depuis poste fixe ou mobile orange, ou 08 00 71 18 69 pour les autres operateurs.',
|
||||
23 => 'bonjour, ceci est un message de la ville de lyon, une grue doit accéder au sinistre de la montée bonafous. a compter du mardi 5 mai après-midi, merci d\'évacuer tous les véhicules des rues suivantes : -du numéros 18 au numéros 29 montée bonafous, - du numéros 1 au numéros 11 rue lebrun, - du numéros 11 au numéros 17 rue justin godard, - du numéros 2 au numéros 12 rue celu, merci de votre collaboration mairie de lyon',
|
||||
24 => 'bonjour, cette semaine, pour cause des travaux sur le chemin de la garrigue et le chemin du croux d\'alet, la circulation sera perturbée. mairie de luc',
|
||||
25 => 'bonjour, comme suite à la réparation d\'une fuite nous sommes obligés de faire une coupure d\'eau ; rue des gourmets et possiblement rue du pech, de 14h30 jusqu\'à ce soir. merci de votre compréhension',
|
||||
26 => 'bonjour, comme suite à la réparation d\'une fuite nous sommes obligés de faire une coupure d\'eau ; rue des gourmets et possiblement rue du pech, de 9h30 à 10h30. merci de votre compréhension',
|
||||
27 => 'bonjour, elections municipales et coronavirus; les électeurs seront invités dès leur entrée dans le bureau de vote de se laver les mains avec une solution hydroalcoolique, et à se munir d\'un masque s\'ils toussent ou sont malades. les personnes de 70 ans et plus sont invités à venir préférentiellement entre 15h et 17h, heures de peu d\'affluence. mairie de luc',
|
||||
28 => 'bonjour, en raison du risque d\'incendie les chemins d\'accès à la garrigue seront fermés pour véhicules (sauf pour les ayant droits qui ont signé une convention) à compter du 30-06-2025 jusqu\'à nouvel ordre. mairie de luc',
|
||||
29 => 'bonjour, en raison du risque d\'incendie les chemins d\'accès à la garrigue seront fermés pour véhicules à compter du 21-08-2023. mairie de luc',
|
||||
30 => 'bonjour, en raison du risque d\'incendie les chemins d\'accès à la garrigue seront fermés à compter du 31-07-2020 - une recrudescence de moustiques est notée sur le village : merci à chacun de veiller à vider les eaux stagnantes qui sont des lieux de reproduction des larves.',
|
||||
31 => 'bonjour, en raison du tour de france l\'accès à la rd118 sera fermé de 8h00 à 13h30 le dimanche 21 juillet. prenez vos précautions. mairie de luc sur aude',
|
||||
32 => 'bonjour, jeudi 2 mai le chateau d\'eau sera vidangé pour etre nettoyé. l\'eau sera coupée à 8h00 et rétablie en fin d\'après-midi. prenez vous précautions. merci de votre compréhension.',
|
||||
33 => 'bonjour, l\'arreté de m le préfet de l\'aude du 08 aout 2025 place notre commune dans un secteur en crise ; en ce qui nous concerne, notons que l\'arrosage des jardins d\'agréments et espaces verts privés est interdit. l\'arrosage des jardins potagers peut se faire entre 20h et 8h du matin. le lavage des voitures est interdit, ainsi que le lavage des voiries, terrasses, murs. le remplissage de citernes, cuves est interdit. enfin le remplissage pour la mise à niveau des piscines privées n\'est autorisée que de 20h à 8h. vous trouverez l\'arreté sur le site de la préfecture. le maire. plusieurs familles sont impactées par le manque d\'eau, en particulier sur le village. ceciest lié au réducteur de pression qui dysfonctionne. dès lundi l\'entreprise qui gère nos installations sera sollicitée pour changer le dispositif. en attendant, il faut que les familles concernées stockent l\'eau dans le courant de la journée quand la demande est moins forte. demain 17 aout à 11h aura lieu, à la stèle des gorges, la commémoration annuelle du guet-apens que la résistance tendit au troupes nazis en 1945. vous etes tous conviés.',
|
||||
34 => 'bonjour, l\'arreté portant reconnaissance de l\'état de catastrophe naturelle sécheresse-réhydratation des sols, pour luc, a été publié le 22-02-23. l\'assuré doit déclarer tout sinistre à l\'assureur au plus tard 10 jours après la publication. copie de l\'arreté à votre disposition à la mairie. mairie de luc.',
|
||||
35 => 'bonjour, l\'eau sera coupée mercredi 31 juillet de 15 à 16 h pour tout le bas du village à partir de l\'école. merci pour votre compréhension.',
|
||||
36 => 'bonjour, la mairie va faire la demande de catastrophe naturel pour sécheresse réhydratation des sols début décembre 2022 pour la période 2021. les habitants qui ont des fissures ou autres dégats à la maison peuvent le signaler à la mairie par écrit et avec photos si possible, pour appuyer notre demande. merci.',
|
||||
37 => 'bonjour, le secrétariat de la mairie de luc sera fermé du 10 au 17 mai inclus. en cas d\'urgence vous pouvez appeler m le maire au 06 80 40 58 60. merci pour votre compréhension.',
|
||||
38 => 'bonjour, le secrétariat de la mairie de luc sera fermé pour congés du 09 au 15 mai inclus. en cas d\'urgence vous pouvez appeler m le maire au 06 80 40 58 60. merci pour votre compréhension.',
|
||||
39 => 'bonjour, le secrétariat de la mairie de luc sera fermé pour congés du 13 au 22 septembre inclus. en cas d\'urgence vous pouvez appeler m le maire au 06 80 40 58 60. merci pour votre compréhension.',
|
||||
40 => 'bonjour, les secours ont été engagés pour un feu de garage d\'une surface de 25 m? attenant à une habitation, 334 rue de l\'école commune de thusy. feu éteint au moyen de deux ldv. aucune victime. adjoint à mr le maire et gendarmerie sur les lieux. ltn jean-philippe gervex',
|
||||
41 => 'bonjour, mercredi 24 mai de 11h15 à 15h00, l\'eau sera coupée av fontaine de la constance pour cause de travaux sur le réseau. la route sera barrée toute la journée. merci pour votre compréhension.',
|
||||
42 => 'bonjour, nous sommes au niveau rouge pour l\'alerte crue. veuillez rassembler vos affaires (pièces d\'identité etc) et vous rendre au foyer communal. éviter de prendre votre voiture si possible. l\'equipe municipale',
|
||||
43 => 'bonjour, nous sommes en alerte rouge pour le crue de l\'aude. veuillez limiter vos déplacements. pour information, le foyer de luc est ouvert pour vous accueillir si besoin. mairie de luc',
|
||||
44 => 'bonjour, pour cause de travaux de réfection de la chaussée sur toutes les zones, la déchetterie de montazels sera fermée le 7, 8 et 9 décembre, elle rouvrira le 10 décembre à 9h15.',
|
||||
45 => 'bonjour, pour la recherche d\'une fuite d\'eau nous sommes obligés de couper l\'eau; rue des gourmets, fontaine de constance, rue du pech, rue du colonel beltrame et route du haut du village jusqu\'au cimetière, à partir de ce soir 22h00 jusqu\'à 6h00 demain matin. le haut du village n\'est pas concerné. merci de votre compréhension.',
|
||||
46 => 'bonjour, sur la commune de thonon les bains : explosion de bateau ,point de situation. un homme 56 ans est transporté blessé léger sur le ch thonon. après inspection de la coque ,aucun dégats ,aucune voie d\'eau. l\' adjointe au maire prends attache avec la capitainerie. fin des opérations de secours . ltn lobjois. chef de salle opérationnelle .',
|
||||
47 => 'bonjour, une coupure d\'eau suite aux travaux est nécessaire pour tout le bas du village jusqu\'à l\'école et à partir de 13h00. veuillez nous excuser pour la gene occasionnée.',
|
||||
48 => 'bonjour, vous figurez sur le fichier d\'information et d\'alerte communal en cas de crise majeure. nous testons le fonctionnement de notre système d\'alerte au travers d\'un exercice d\'alerte submersion. rassurez-vous tout va bien, il s\'agit simplement d\'un test des fichiers et des outils. l\'équipe municipale.',
|
||||
49 => 'bonjour,interdiction de l\'emploi du feu en corse-du-sud à compter du vendredi 1er octobre 2021 jusqu\'au vendredi 08 octobre 2021 inclus.',
|
||||
50 => 'bonsoir pour info engagement de l\'exercice tunnel du vuache avec mise en oeuvre du lot sinus. ltn jean-philippe gervex.',
|
||||
51 => 'bonsoir, le préfet de haute-loire informe que le département est placé en vigilance orange canicule à compter de ce jeudi 17 aout. plus d\'infos et sur les conduites à tenir sur vigilance.meteofrance.fr et par mail (surveillez vos spams)',
|
||||
52 => 'ceci est un message d\'exercice. un arreté portant interdiction des transports scolaires a été pris ce jour sur l\'ensemble du département de la haute-loire. veuillez consulter votre messagerie pour télécharger l\'arreté',
|
||||
53 => 'ceci est un message de formation fin de l\'interdiction de transports scolaires',
|
||||
54 => 'ceci est un message de formation transports scolaires interdits de jour sur le 43 veuillez consulter l\'arreté ci-dessous ou votre messagerie',
|
||||
55 => 'ceci est un message de test un accident est survenu à l\'usine saipol des fumées se dégagent du site veuillez ne pas sortir du batiment, calfeutrez portes et fenetres, attendez l\'arrivée des secours.',
|
||||
56 => 'ceci est un message de test. un feu de foret s\'est declenche a la fontaine des naiades. quitter la zone au plus vite. rejoignez la zone de rassemblement rd 199. d\'autres consignes vous seront données ultérieurement.',
|
||||
57 => 'ceci est un message exercice transport scolaire interdit ce jour sur le 43 veuillez consulter l\'arreté ci-dessous ou votre mail',
|
||||
58 => 'commune d\'annecy :les sapeurs-pompiers sont intervenus dans un squat pour un homme de 53 ans retrouvé mort par un éducateur. police nationale sll. ltn c.akelian chef de salle opérationnelle.',
|
||||
59 => 'commune de doussard rue de la fontaine au carrefour market lieu public / 1 femme 50 ans en acr en cours de réanimation. lt denis simon',
|
||||
60 => 'commune de sallanches, route de luzier, feu à 04h56: feu de hangar de 80 m? entièrement embrasé, avec propagation à la toiture d\'une maison d\'habitation r+3 de 200 m? comportant 2 logement dont un seul occupé par une famille de 4 personnes. extinction en cours au moyen de 2 ldv 250. dégarnissage de la toiture en cours. moyens engagés: cdc / cdg / 3 fpt / epc / eps/ ccgc / ccf / vsav / ce ari / sso / vtu log soit 36 sp. mr le maire avisé. ltn lise-may langeven',
|
||||
61 => 'commune de val de fier : les sapeurs-pompiers interviennent pour un feu de végétation qui se propage à la foret suite à la chute d\'une ligne haute-tension de 20 000 volts, en parallèle très forte activité opérationnelle concernant les opérations diverses dues au vent. ltn c.akelian / chef de salle opérationnelle.',
|
||||
62 => 'cs montmelian urgent - besoin dispotel garde vide suite inter incendie sofops viviand bruno',
|
||||
63 => 'csp moutiers - besoin dispotel avp en cours rn 90',
|
||||
64 => 'csp moutiers urgent - besoin dispotel - fpt et mch au depart',
|
||||
65 => 'csp moutiers urgent - besoin dispotel - vrm et fpttu en inter',
|
||||
66 => 'dans le cadre d\'un exercice de gestion de crise routière, la section de la rn88 entre le carrefour giratoire de "lachamp" et l\'échangeur n49 "fay la triouleyre" sera fermée le mercredi 31 mai 2023 de 18h45 à 22h30, et la déviation pgt 88-5 activée pendant cette durée. un mail reprenant ces éléments vous à été adressé. préfecture - haute-loire',
|
||||
67 => 'dès lundi, la commune met en place un service quotidien de courses avec le magasin 8 à 8 de couiza, afin de limiter au maximum les contacts avec l\'extérieur pour les personnes vulnérables. appelez le 04 48 31 00 29 et suivez les instructions. commandez le jour meme, vous serez livré à domicile le lendemain matin. pour plus d\'information, voir le site de la mairie, la page facebook ou appeler le maire au 06 80 40 58 60',
|
||||
68 => 'départ imminent de la colonne sera 2 pour un rendez vous demain matin dans le sud de la france. ltn c.akelian / chef de salle opérationnelle.',
|
||||
69 => 'effondrement d immeuble a chambery 87 rue juiverie au depart specialite sd + commandement vsav fpt cyno en cours',
|
||||
70 => 'en raison d\'une fuite, l\'eau sera coupée ce jour entre 9h15 et 14h pour la partie basse du village située en contrebas de l\'école.',
|
||||
71 => 'en raison de l\'alerte canicule sur le département, une vigilance particulière est portée sur les personnes agées isolées. en cas de besoin, merci de contacter la mairie.',
|
||||
72 => 'en raison de l\'alerte canicule sur le département, une vigilance particulière est portée sur les personnes agées isolées. en cas de besoin, merci de contacter la mairie. en raison de la sécheresse, l\'accès à la garrigue sera fermée sauf pour les ayant-droits à partir du 8/08. les agriculteurs doivent éviter broyeur ou épareuse.',
|
||||
73 => 'epagny : accident de 2 vl avec forte cinétique le bilan fait état de 2 homme de 20 et 30 ans, blessés grave, ils ont été transporté sur le ch annecy par vsav epagny',
|
||||
74 => 'exercice communal. ceci est un message d\'alerte dans le cadre d\'un exercice communal (simulation). vigilance météo rouge vagues/submersion et orange vents violents (simulation). consignes : surveillez la montée des eaux, ne partez pas en mer, limitez les déplacements, n\'intervenez pas sur les toitures. restez informés via les médias. en cas de difficulté (exercice) : 18 ou mairie 05 46 29 82 89 / astreinte 06 17 04 78 82. fin de l\'exercice.',
|
||||
75 => 'exercice exercice exercice leman 23 : déclenchement à 09h37 pour explosion sur un bateau de la sgn coté france commune de thonon au large du port de plaisance , 61 personnes à l\'eau et 35 personnes sur le bateau. déclenchement du plan novi, cod et codis orange activés, plan multi latéral activé, engagement des secours suisse et ssn francais. ltne lise-may langeven',
|
||||
76 => 'exercice exercice exercicela préfecture des hauts-de-seine vous informe : un message d\'alerte concernant l\'activation du cod vient de vous etre transmis par mail. les services ne participant pas à l\'exercice en cours (blackout wenesday pref92) ne sont pas concernés par le message exercice exercice exercice',
|
||||
77 => 'exercice routier du 31 mai - 18h45 - 22h30 coupure rn88 et déviation pgt-88.5 secteur lachamps - fay la trouleyre veuillez consulter le mail qui vous a été transmis préfecture 43 vérifiez vos spam',
|
||||
78 => 'fin de l\'interdiction de circulation, pour les véhicules de transport de marchandises ptac >7.5 t et des transports en commun de plus de 3,5 t de ptac sur la rn88 et la rn102, secteur sud du département. préf43',
|
||||
79 => 'fin de l\'interdiction de circulation, pour les véhicules de transport de marchandises ptac >7.5 t sur rn88 de pradelles en direction de langogne préf43',
|
||||
80 => 'fin de l\'interdiction de circulation, pour les véhicules de transport de marchandises ptac >7.5 t sur rn88 secteur nord/est du département, dans les deux sens . préf43',
|
||||
81 => 'fin de l\'interdiction de circulation, pour les véhicules de transport de marchandises ptac >7.5 t sur rn88/rn102 secteur sud du département. préf43',
|
||||
82 => 'info astreinte dsp (message 1) 14 rue thomassin - lyon 2 feu dans cage d\'escalier (qui s\'est effondrée). 2 personnes en urgence absolue et 5 en urgence relative dont 2 pompiers et 11 impliqués. les évacués sont regroupé à l\'hotel mercure rue édouard herriot. sous préfet et directeur départemental sdmis sur les lieux. élu d\'astreinte et cabinet informés adrien du verger',
|
||||
83 => 'info astreinte dsp (message 2) le sinistre concerne le 16 rue des quatre chapeaux - lyon 2. l\'immeuble est évacué dans sa totalité. la régie st louis fait intervenir une entreprise pour sécuriser les lieux à 16h. la pm assure un périmètre de sécurité. 4 personnes relogées par la ville, tous les autres occupants ont une solution alternative. le maire du 2ème s\'est déplacé. la cump est en place dans l\'hotel mercure. adrien du verger',
|
||||
84 => 'info astreinte dsp - 10 rue des verriers lyon 7 - effondrement partiel du batiment type r+1 sur cour suite à travaux au rdc. - 3 logements impactés et évacués - pas de victime - 3 personnes relogées dans la famille et 2 frères relogés par la ville - intervention servimo pour condamner l\'accès - message laissé sur portable élu d\'astreinte et astreinte cabinet du maire informé . patrick burdillat astreinte en 2 pour christophe pel astreinte en 1 qui a realisé l\'intervention.',
|
||||
85 => 'info astreinte dsp - effraction d\'un kiosque propriété ville de lyon, place bellecour à lyon 2ème. intervention de la société servimmo pour sécuriser le kiosque non exploité actuellement. autorités informées. alexandra dussud',
|
||||
86 => 'info astreinte dsp - fermeture jusqu\'à nouvel ordre des parcs suite à l\'alerte jaune pour des rafales de vent supérieur à 70km/h. autorités informées. alexandra dussud.',
|
||||
87 => 'info astreinte dsp - info sp, feu de voiture dans parc de stationnement au 42 bvd de balmont à lyon 9eme. feu éteint, pas de désordres structurels, pas d\'évacuation des habitants. ventilation des allées en cours. sacvl, bailleur social sur les lieux. autorités informées. alexandra dussud',
|
||||
88 => 'info astreinte dsp - intervention en cours pour feu de magasin et vl au 31-33 rue étienne richerand à lyon 3ème. magasin de trottinettes et batteries lithium totalement détruit avec propagation à une vl sur vp et au 1er étage d\'un batiment r+6. 2 appartement impactés. 54 personnes évacuées dont 24 au 31 et 30 au 33. n33 en cours de réintégration et 31 en cours de reconnaissance par sp. directeur de cabinet du préfet sur place. probables relogements à prévoir. message de suivi à venir. autorités informées. a.dussud pour c.pel sur place. info astreinte dsp - suite incendie lyon 3. tous les locataires ont pu réintégrés leurs logements sauf appartement 1er étage au dessus du magasin. 2 personnes relogées et prises en charge par icf habitat, propriétaire bailleur. icf se charge également de la mise en sécurité, l\'expertise structure et le nettoyage de la vp devant l\'immeuble. autorités informées. a. dussud info astreinte dsp - suite à surtension quartier rues des docks et des brasseries à lyon 9ème, installation électrique du groupe scolaire laborde endommagée. incident en cours de traitement par enedis (secteur) et dgtb (école). intervention des pompiers pour échauffement, les enfants et leurs encadrants ont été évacués. ecole actuellement à l\'arret en raison du non fonctionnement des organes de sécurité. enfants pris en charge par leurs encadrants jusqu\'à la fin de la journée. un diagnostic par un électricien est prévu demain matin à 7h30. direction de l\'éducation prévenue, l\'école sera fermée à partir de ce soir en attendant les résultats du diagnostic. autorités informées. a. dussud info astreinte dsp - info sp, accident tram/piéton au niveau du 131 avenue berthelot lyon 7eme. piéton en urgence absolue, 2 personnes dans le tram en urgence relative, tous pris en charge par les pompiers. circulation tram coupée en cours de remise en service par keolis sur les lieux. autorités informées. alexandra dussud.',
|
||||
89 => 'info astreinte dsp - intervention pm pour effraction de la porte d\'entrée de l\'église désacralisée saint bernard situé au 15 rue vaucanson à lyon 1er. constatation pn. l\'astreinte dgtb a mandaté l\'entreprise servimmo pour mise en sécurité et fermeture de l\'établissement. autorités informées. alexandra dussud info astreinte dsp - intervention sp au centre nautique tony bertrand, quai claude bernard à lyon 7ème pour deux femmes, alcoolisées et sous métadone, bloquées sur les plages de la piscine. fracture du cadenas du portail sud pour intervention sous couvert d\'un équipage de la bac. intervention servimmo en cours pour installation d\'un nouveau cadenas. autorités informées, alexandra dussud',
|
||||
90 => 'info astreinte dsp - intervention pompiers en cours pour recherche d\'une personne qui a sauté dans le rhone au niveau du pont de l\'université. effectifs nombreux. p. burdillat',
|
||||
91 => 'info astreinte dsp - intervention à la demande des pompiers suite à un déclenchement d\'alarme incendie dans le foyer logement pour réfugiés aralis au 102 avenue général frere à lyon 8ème. après reconnaissance des sp, pas de sinistre, besoin d\'aide pour réarmer la centrale d\'alarme incendie en raison de la non-réponse de responsables du foyer. les sp ont du briser une paroi vitrée pour accéder à la centrale afin d\'acquitter le processus après réarmement des déclencheurs percutés. a notre départ, l\'alarme incendie était à nouveau opérationnelle. avis de passage laissé par les sp. autorités informées. alexandra dussud info astreinte dsp - tentative de cambriolage de la crèche municipale lieutenant colonel girard dans le 7ème arrondissement. demande d\'intervention par la police pour fermeture et mise en sécurité suite à la dégradation d\'une fenetre. prises d\'empreintes et d\'échantillons pas la police scientifique. fermeture par l\'astreinte dgtb à l\'aide du volet roulant permettant la mise en sécurité du site. autorités informées. alexandra dussud info astreinte dsp : intervention des pompiers au 45 avenue des frères lumière à lyon 8 pour des anciens affaissements de planchers sur un batiment r+2. après reconnaissance, le service constructions balmes prendra le relais dès demain matin pour faire missionner par le syndic, un ingénieur structure. autorités informées. info astreinte dsp : pgr en cours au niveau du 14 rue st pierre de vaise à lyon 9ème. circulation coupée dans les deux sens jusqu\'à mise en sécurité du site. autorités informés. r. coste-chareyre info astreinte dsp : pgr en cours au niveau du 26 rue st pierre de vaise à lyon 9ème. circulation coupée dans les deux sens jusqu\'à mise en sécurité du site. autorités informés. r. coste-chareyre',
|
||||
92 => 'info astreinte dsp - intervention à la demande du samu 69 pour une hospitalisation d\'office sur demande du représentant d\'état. jeune homme logé à l\'hotel l\'enghein, 22 rue enghein à lyon 2ème, pris en charge par une ambulance privée et transportée au vinatier. autorités informées. alexandra dussud et jérémy castell.',
|
||||
93 => 'info astreinte dsp - intervention: feu de vl + 2 roues avec propagation à la facade d\'un batiment r+6 au 6 rue du presbytère à lyon 8. 1 chambre d\'un appartement t3 au r+1 de l\'immeuble impactée par la propagation. 1 seul locataire concerné, pas de relogement. immeuble géré par la régie alliade. autorités informées. christophe pel info astreinte dsp - intervention suite à fuite d\'eau dans un appartement situé dans les combles aménagés d\'un batiment r+4+combles au 1 montée des carmélites à lyon 1er. dégats sur les plafonds des appartements r+2, r+3, r+4. fuite sur sanitaires stopée par sp. porte fracturée par les sp qui missionnent un serrurier pour refermer, locataire absent. coupure électricité des appartements r+4 et combles. les occupants réintègrent leurs appartements, pas de relogement. syndic: régie pédrini. autorités informées. christophe pel info astreinte dsp - feu dans un batiment squatté au 153 avenue berthelot à lyon 7eme. feu vraisemblablement d\'origine criminelle, deux départs de feu. 11 personnes incommodées dont 1 transportée par les sp. tram t2 coupé pendant l\'intervention des sp. elue d\'astreinte sur les lieux. intervention sp terminée, police municipale et nationale sur place. servimmo mandatée pour securisation, un arreté d\'évacuation sera pris. autorités informées. alexandra dussud, jeremy castell et romain coste- chareyre.',
|
||||
94 => 'info astreinte dsp - suite à la panne généralisée sur les numéros d\'urgence une campagne d\'alerte par sms a été faite sur la commune de lyon. elu d\'astreinte et cabinet du maire informés. p. burdillat',
|
||||
95 => 'info astreinte dsp 1 rue lavoisier - lyon 3 feu d\'appartement au r+4 d\'un batiment r+6. feu éteint, les reconnaissances sont en cours pour évaluer les appartements qui seront inhabitables. 2 adultes et 1 enfant transportés par les sp en urgence relative. une trentaine de sinistrés sont rassemblés dans l\'hotel ibis rue paul bert. recensement en cours par croix-rouge et dsp pour évaluer les besoins en relogements. présence du sous préfet, de m. chihi et de m. clerc (ma3). autorités informées. adrien du verger',
|
||||
96 => 'info astreinte dsp 10 montée du télégraphe - lyon 5ème branche d\'arbre tombée sur vp. entreprise mandatée pour mettre en sécurité les sections toujours menacantes. pas de dégats matériels et humains. périmètre de sécurité établi et tenu par la pm. accès vl au gymnase jean moulin interdit. autorités informées. alexandra dussud',
|
||||
97 => 'info astreinte dsp 165 grande rue de la guillotière - lyon 7 : feu d\'appartement vers 2h du matin au r+1 d\'un batiment en r+2. immeuble désaffecté et squatté, une personne a sauté du 1er étage pour s\'extraire et a été prise en charge par les pompiers en urgence relative. pas de dégats structurels, feu rapidement maitrisé. autorités informées. adrien du verger',
|
||||
98 => 'info astreinte dsp 17 rue sebastien gryphe lyon 7 - incendie dans batiment type r+2. local commercial (boucherie) et 1er étage impactés. dégats importants - 1er et 2ème en travaux, logements inoccupés. autorités informées. p burdillat',
|
||||
99 => 'info astreinte dsp 2 incidents en cours sur la ligne a du métro : - une personne tombée sur les voies station bellecour classée urgence absolue - un colis suspect station flachet pris en compte par les démineurs la ligne sera perturbée une bonne partie de la soirée. autorités informées. adrien du verger',
|
||||
100 => 'info astreinte dsp 2 rue de fargues - lyon 1 : intervention des pompiers pour chute d\'éléments de corniche sous toiture. la police municipale a fait déplacer un véhicule par précaution et les pompiers ont purgé les éléments menacants. les services de la métropole nettoient la voirie et un périmètre de sécurité est mis en place pour sécuriser les lieux en attendant que le syndic prenne le relai. autorités informées. adrien du verger',
|
||||
101 => 'info astreinte dsp 27 quai jean moulin - lyon 2 feu dans restaurant eat sushi (partie stockage). un incendie a déjà eu lieu dans ce restaurant le 15 octobre dernier. l\'ensemble des habitants a pu regagner son logement. aucune victime. un arreté d\'évacuation sera pris pour le restaurant. autorités informées. adrien du verger',
|
||||
102 => 'info astreinte dsp 27 quai jean moulin - lyon 2 incendie dans un restaurant "eat sushi" en rdc d\'un batiment à usage d\'habitation r+5. feu d\'origine électrique localisé dans un bureau en mezzanine. la partie accessible au public et l\'immeuble ne sont pas impactés par le sinistre. autorités informées. adrien du verger',
|
||||
103 => 'info astreinte dsp 4 rue de champagneux lyon 8 - intervention des pompiers pour incendie dans un box rapidement maitrisé au 1er sous-sol de l\'immeuble. habitants confinés et opération de desenfumage en cours. autorités informées. p. burdillat',
|
||||
104 => 'info astreinte dsp 44 rue denis père et fils, lyon 8 - intervention à la demande du président du club de boules pour un arbre vdl menacant une résidence. des branches sont tombées hier soir, ont endommagé un véhicule et la cloture mitoyenne au n38. des branches menacent toujours - entreprise chazal mandatée - intervention à 13h30. autorités informées. adrien du verger',
|
||||
105 => 'info astreinte dsp 53 quai joseph gillet - lyon 4 feu d\'appartement au 7ème étage d\'une résidence adoma en r+7. batiment vide d\'habitants en cours de déménagement pour démolition. 4 ouvriers présents au moment du sinistre - pas de blessé - feu éteint - responsable territorial adoma sur les lieux. autorités informées. adrien du verger',
|
||||
106 => 'info astreinte dsp 6 rue childebert - suite - évacuation des gravats par les pompiers toujours en cours- récupération des effets personnels depuis la grande échelle pour les personnes évacuées du 1er au 4ème étages prévue dans la soirée- surveillance du batiment assurée par les pompiers durant la nuit. p burdillat',
|
||||
107 => 'info astreinte dsp 6 rue childebert lyon 2 - opération des secours toujours en cours. diagnostic structure assuré par un ingénieur mandaté par régie. accès possible uniquement depuis la grande échelle. 9 logements évacués, pas de prise en charge par la ville. la rue childerbert restera fermée au moins cette nuit entre place de la république et place des jacobins. p burdillat',
|
||||
108 => 'info astreinte dsp 6 rue childebert lyon 2 - violent incendie en cours dans logement au 3ème étage qui s\'est propagé aux combles de l\'immeuble de type r+6. escalier effondré. pas de victimes annoncées. moyens de secours importants. autorités informées. patrick burdillat',
|
||||
109 => 'info astreinte dsp 98 rue de st cyr - lyon 9 : feu dans appartement squatté au 1er étage d\'un batiment r+4. 3 personnes vues par les pompiers dont 2 transportées à l\'hopital pour inhalation de fumées. feu éteint. pas de dommages structurels. autorités informées. pascal favre',
|
||||
110 => 'info astreinte dsp : 28 quai arloing lyon 9 - 1 personne blessée par arme à feu par agent de la police nationale suite à refus d\'obtempérer et usage d\'une hachette. personne transportée à heh en urgence relative. astreinte cabinet du maire et élu d\'astreinte informés. p burdillat info astreinte dsp - 90 quai pierre scize lyon 5. 7 véhicules détruits par incendie volontaire. facade de l\'immeuble noircie. vitrine commerce piano au rez de chaussée fragilisée. risque d\'effondrement de la vitrine et trottoirs encombré par matériels de plomberie sortie par les pompiers de l\'un des véhicules incendié. appel à société de gardiennage pour surveiller le site dans l\'attente de contacter le syndic d\'immeuble dans la matinée. elu d\'astreinte et cabinet du maire informé.p burdillat info astreinte dsp 52 rue pauline jaricot lyon 5 - début d\'incendie dans logement au dernier étage d\'un immeuble r+5 géré par sacvl pas de problème structurel ni de gros désordres mais l\'appartement est inhabitable en l\'état. habitante prise en charge par le bailleur. elu d\'astreinte informé. p burdillat',
|
||||
111 => 'info astreinte dsp : 3 blessés par arme blanche de 14 16 et 25 ans en ur. secours et blessés regroupés place gabriel péri sous protection crs et police en attendant de savoir de quel type d agression il s agit ( bagarre, attaque ). autorités informées. amélie colet info astreinte dsp : suite information place gabriel péri: blessés transportés et dispositif levé. la police effectue des controles dans le secteur. autorités informées. amélie collet.',
|
||||
112 => 'info astreinte dsp : 50 rue tramassac lyon 5.effondrement partiel de plancher au r+2 d\'un batiment r+4. pas de blessés. 10 personnes évacuées dont 3 relogées par la ville de lyon. autorités informées. amélie collet.',
|
||||
113 => 'info astreinte dsp : 54 rue st jean - lyon 5 effondrement partiel d\'un plafond au 2ème étage d\'un batiment r+5 suite à infiltrations d\'eau (origine à déterminer). l\'appartement du dessus est également impacté au niveau de la salle de bain. interdiction d\'accès dans les pièces concernées en attendant que le syndic fasse le nécessaire. le service construction balmes prend la suite de l\'intervention. autorités informées. adrien du verger',
|
||||
114 => 'info astreinte dsp : 7 rue phillipe fabia lyon 8. cheminée menacant de s\'effondrer d\'un batiment r+10. cheminée décorative abritant un antenne free déboulonnée à sa base. les pompiers l\'ont refixée et haubannee. glh était présent et fait le nécessaire avec free. autorités informées. amélie collet.',
|
||||
115 => 'info astreinte dsp : 86 bd pinel - lyon 3 risque d\'effondrement d\'une maison en r+1. un incendie a eu lieu dans celle-ci en juillet 2020 et des travaux de rénovation devaient etre entrepris. les pompiers ont procédé à l\'étaiement des niveaux et un périmètre de sécurité est mis en place par la métropole sur le trottoir attenant à la maison. unité péril métropole présente sur les lieux. autorités informées. adrien du verger',
|
||||
116 => 'info astreinte dsp : a la demande du sdmis, intervention pour fuite de fioul (env 7000l) dans caves au 57 rue louis blanc lyon 6. syndic de copro mandate entreprise pour pomper. arrete d\'évacuation des caves pris. pas de relogement. autorités informées. jf perez/ r coste-chareyre',
|
||||
117 => 'info astreinte dsp : accident sur vp à l\'angle du pont lafayette / quai jules courmont lyon 2. 2 vl impliquées. 1 incarcéré dans chaque vl et 1 personne éjectée. intervention toujours en cours des sp. circulation rétablie à 1 voie quai jules courmont sens sud nord. 1ua et 2 ur. autorités informées. amélie collet. info astreinte dsp - 4 rue casimir perier lyon 2 - intervention des pompiers suite à fuite sur colonne d\'alimentation en eau au bloc a. coupure faite sur alimentation générale de l\'eau de l\'ensemble des 4 blocs de la copropriété 4 8 10 rue c perier et 52 54 56 rue denuziere. une centaine de logements impactés. enedis a procédé à la coupure de l\'électricité des communs et de l\'ascenseur du bloc a. le syndic et l\'entreprise de maintenance ont été alertés pour procéder aux réparations permettant un retour à la normale au plus vite. autorités informées. patrick burdillat info astreinte dsp - une personne de sexe masculin s\'est jetée du pont gallieni vers 18h. operation des secours importante mais la victime n\'a pas été retrouvée. les pompiers viennent de lever le dispositif. elu d\'astreinte et astreinte cabinet du maire informés. patrick burdillat info astreinte dsp 10 place d\'helvetie lyon 6 - intervention des pompiers suite à fuite d\'eau dans un local inoccupé d\'une clinique de jour. a mon arrivée, la fuite était stoppée sans manipulation de vanne. un plombier mandaté par le syndic est sur place pour diagnostiquer ce problème, l\'origine reste à cette heure inexplicable, les pompiers sont repartis. patrick burdillat info astreinte dsp - 23 rue général gouraud lyon 8. apparition de fissures dans logement au 1er étage suite à démontage des cloisons dans logement du rez de chaussée. des mesures conservatoires ont été réalisées par les pompiers permettant à l\'habitante de rester dans son logement ce soir. la régie bouteille et le propriétairequi a réalisé les travaux seront avisés dès demain matin. autorités informées. patrick burdillat info astreinte dsp - angle rue baraban / rue d\'aubigny lyon 3 - accident entre 2 véhicules cette nuit à 2h50 impliquant 6 jeunes hommes d\'une vingtaine d\'années (3 / véhicules). 5 en transportés en urgence absolue et 1 décédé. autorités informées. patrick burdillat info astreinte dsp - intervention en cours pour effondrement partiel de toiture sur batiment r+2 + combles au 3 rue de tourville à lyon 7eme. seule la partie gauche de l\'immeuble est impactée par le désordre soit deux appartements, 6 personnes évacuées qui se relogent par leurs propres moyens (assurance et famille). étaiement de la structure par les pompiers en cours. syndic et autorités informés. a. dussud pour a. du verger sur place.',
|
||||
118 => 'info astreinte dsp : alerte orange préfecture vent violent - déclenchement automate d\'appel pour alerte orange vent violent et fermeture des grands parcs. p burdillat',
|
||||
119 => 'info astreinte dsp : appel de la pm pour des tags sur l\'école philibert delorme à lyon 8ème. tags relatant de menaces à l\'encontre du corps enseignant et du maire du 8ème arrondissement. constatations et remontée d\'information à paris effectuée par la police nationale. svp batiment procède au retrait, autorités informées. christophe pel',
|
||||
120 => 'info astreinte dsp : chute d\'un arbre sur une passerelle métallique situé au 17 bd de la duchère, lyon 9ème. celle-ci a été interdite d\'accès jusqu\'à l\'intervention des services des espaces verts demain. autorités informées. jérémy castell - alexandra dussud',
|
||||
121 => 'info astreinte dsp : dégradations sur le groupe scolaire jean kennedy au 15 rue jean sarrazin à lyon 8. 3 vitres endommagées et portail accès ouvert. dg mairie du 8ème sur place. astreinte svp batiment avisée, fait le nécessaire. autorités informées. christophe pel',
|
||||
122 => 'info astreinte dsp : feu d\'appartement 16 bd yves farges, lyon 7. appartement au 5ème étage. inhabitable. 1 personne évacué au moyen de l\'échelle aérienne. pas de blessé. 3 personnes impactées. pas de relogement. pas de désordres structurels. autorités informées. p.favre',
|
||||
123 => 'info astreinte dsp : feu d\'appartement au r+4 du 3 rue childebert lyon 2ème. pas de blessés. appartement vide en rénovation. ingénieur structure mandaté par régie simmonneau. pas de relogement. autorités informées. r coste-chareyre info astreinte dsp : intervention des pompiers pour une chute de hauteur de 6m d\'un travailleur. il serait passé à travers une trappe de désenfumage entre centre commercial part-dieu et tour oxygène. accident vers 21h05, transporté sur heh en ua après 22h. homme 27 ans. opj sur place. autorités informées. r coste-chareyre',
|
||||
124 => 'info astreinte dsp : feu de machinerie d\'ascenseur au r+6 dans hotel de région à lyon 2 vers 17h30. feu rapidement maitrisé par sp. 2 agents de sécurité incendie légèrement incommodés par fumées. réintégration du personnel évacué à 18h40. autorités informés. r coste-chareyre info astreinte dsp : info enedis, coupure de courant pour environs 80 foyers entre rue fabia et 119 bvd des etats-unis. retour à la normale prévu pour environ 21h. autorités informés. r coste-chareyre info astreinte dsp : intervention des sp sur feu d\'appartement au r+6 d\'un immeuble d\'habitation au 103 rue fournier lyon 9. feu éteint. pas de blessés, pas de désordre structurel. deux locataires relogés chez des amis. régie alliade sur place. autorités informés. r coste-chareyre',
|
||||
125 => 'info astreinte dsp : feu erp commerce de destockage 279 rue de crequi lyon 7 au rdc d\'un immeuble d\'habitation. pas de blessé ni désordre structurel. pas de relogement. demande métropole pour nettoyage vp et entreprise servimmo pour sécurisation du site. autorités informés. r coste-chareyre',
|
||||
126 => 'info astreinte dsp : info 1/3 : feu de parking sous terrain au 18 rue vendome à lyon 6, feu au 2ème sous-sol d\'un batiment de 8 étages. pas de victimes, pas de désordres structurels. info 2/3 : homme de 18 ans décédé après une chute accidentelle du 5ème étage au 8 rue rabelais à lyon 3. info 3/3 : femme de 22 ans décédée après avoir été percutée par une voiture place de fourvière à lyon 5. délit de fuite de la voiture en cause avant de se rendre au commissariat autorités informées christophe pel',
|
||||
127 => 'info astreinte dsp : information des sp pour un feu de véhicule dans le tunnel de la croix rousse. feu éteint. pas de victime. autorités informées. amélie collet.',
|
||||
128 => 'info astreinte dsp : intervention au 5 place de la baleine à lyon 5, pour un homme d\'une quarantaine d\'années retranché chez lui. la place de la baleine a été évacuée. intervention du raid de lyon en cours. autorités informées. christophe pel',
|
||||
129 => 'info astreinte dsp : intervention des pompiers au groupe scolaire provisoire sgt blandan rue du repos à lyon 7 suite à odeurs suspectes. les investigations n\'ont rien donné, réintégration des élèves en cours. autorités informées. patrick burdillat info astreinte dsp : 18 rue imbert colomes lyon 1 - fissure récente sur poutre du plancher du 2ème étage. mesures conservatoires réalisée par les pompiers. évacuation de 3 logements au 1er étage et 2 logements au 2ème étage. personnes sinistrées relogées par leur propre moyen. un arreté d\'évacuation sera pris pour officialiser les évacuations. le syndic sera contacté dès demain pour un diagnostic en urgence par un ingénieur structure. autorités informées. patrick burdillat',
|
||||
130 => 'info astreinte dsp : intervention des pompiers en cours au 4 place gabriel peri lyon 7. feu de cave d\'un batiment r+11. feu éteint et ventilation des communs en cours . aucun blessé et pas de dégats structurels. autorités informées . amélie collet.',
|
||||
131 => 'info astreinte dsp : intervention des pompiers pour un feu d\'appartement au r+3 au 33 rue imbert colomes lyon 1. appartement est inhabitable. pas de victime. une famille de 7 personnes dont 3 adultes/4 enfants évacuée et relogée par vdl à l\'hotel villemanzy pour une nuit. autorités informées. r coste-chareyre',
|
||||
132 => 'info astreinte dsp : intervention des sapeurs pompiers au 124 rue vauban à lyon 6. feu de cuisine dans un appartement au 3e étage d\'un batiment à usage d\'habitation de 7 étages et caves. pas de blessés. appartement inhabitable au vu des dégats liés à l\'incendie. une personne impactée, relogée par un ami ce soir et pris en charge par grand lyon habitat à compter de demain. autorités informées christophe pel / adrien du verger',
|
||||
133 => 'info astreinte dsp : intervention des sapeurs pompiers pour un feu d\'appartement au 4 rue roux soignat à lyon 3ème. feu localisé dans un appartement au 3ème étage, occupé par un homme de 50 ans atteint du syndrome de diogène. le locataire a été transporté sur heh, pavillon n. l\'immmeuble a été évacué le temps de l\'intervention. 4 portes d\'accès à des logements ont été endommagées par les sp, intervention de servimmo ce matin (police sur place). l\'appartement sinistré est inhabitable, sans désordres structurels, le point sera fait avec le locataire demain pour un éventuel relogement. les occupants ont pu réintégrer leur logement. régie à aviser : foncia autorités informées. christophe pel',
|
||||
134 => 'info astreinte dsp : intervention des sapeurs pompiers pour un homme de 21 ans tombé dans la saone à l\'ile barbe, lyon 9ème. l\'homme a été repéché à 4m de fond par les sapeurs pompiers, après tentative de réanimation, il est décédé sur place. autorités informées christophe pel',
|
||||
135 => 'info astreinte dsp : intervention des sapeurs-pompiers au 111 rue laennec pour une fuite d\'eau sur le domaine public. recherche de l\'origine en cours, fermeture de la rue laennec, nombreux logements privés d\'eau. autorités informées christophe pel',
|
||||
136 => 'info astreinte dsp : intervention des sapeurs-pompiers au 215 avenue berthelot pour un feu de parking souterrain. feu localisé dans un box au 2ème niveau de sous-sol d\'un batiment en r-2 + 7. pas de victimes, pas d\'évacuation, les parties communes n\'ont pas été impactées. l\'astreinte batiment fera effectuer une reconnaissance dans locaux d\'une crèche associative située au rdc (2 rue de l\'egalité) ce lundi. autorités informées',
|
||||
137 => 'info astreinte dsp : intervention des sapeurs-pompiers au 39 rue bechevelin à lyon 7 pour un accident impliquant un véhicule de la police municipale. 4 blessés légers dont 3 policiers municipaux. les victimes ont été transportées sur l\'hopital st joseph. autorités informées christophe pel',
|
||||
138 => 'info astreinte dsp : intervention des sapeurs-pompiers au 4 rue confort à lyon 2ème pour un feu de cuisine au rdc d\'un batiment de 5 étages (restaurant le giogio). deux personnes évacuées par les pompiers, pas de blessés. absence de désordres structurels, le plancher haut de la cuisine donne sur une cour intérieure. les occupants ont regagné leur logement. grdf et enedis procèdent à la mise en sécurité des installations. autorités informées. christophe pel',
|
||||
139 => 'info astreinte dsp : intervention des sapeurs-pompiers au 4 rue mouillard à lyon 9 pour un feu de chambre au 2eme étage d\'un batiment de 4 étages. un appartement totalement détruit, inhabitable, les trois locataires (1 adulte et 2 enfants) ont été transportés à hfme. la chambre de l\'appartement contigüe (3 personnes) et celle de l\'appartement superposé (1 personne) ont été condamnées pour la nuit. astreinte sacvl avisée, autorités informées. christophe pel',
|
||||
140 => 'info astreinte dsp : intervention des sapeurs-pompiers rue d\'ypres à lyon 4, pour une pollution aquatique dans la saone. déversement de peinture dans les égouts. reconnaissance et prélèvements effectués. sp, police, service assainissement sur les lieux christophe pel',
|
||||
141 => 'info astreinte dsp : intervention des sp 2 avenue rosa parks à lyon 9 pour un feu de balcon au r+5 d\'un immeuble r+7. aucun blessés. la personne de l\'appartement sinistrée se reloge par ses propres moyens. pas de dégats structurels. autorités informées. amélie collet.',
|
||||
142 => 'info astreinte dsp : intervention des sp au 19/21 rue du fort du temple lyon 2 pour chute d\'éléments de facade. purge des éléments menacants effectuée par sp. métropole mandatée pour nettoiement de voirie. autorités informées. r coste-chareyre',
|
||||
143 => 'info astreinte dsp : intervention du sdmis pour des enduits de facade tombés sur la vp au 3 quai de bondy lyon 5 - purge des éléments menacant par les pompiers - syndic de l\'immeuble sur place qui fait le nécessaire pour la mise en sécurité. autorités informées. j lavergne info astreinte dsp:intervention des pompiers pour chute d éléments de corniches sur le trottoir au 5 rue bonnefoi lyon 3.. pas de blessé.. mise en place d un périmètre de sécurité par le service voirie.. autorités informées.. j. lavergne info astreinte dsp : intervention des pompiers pour une alarme incendie en défaut dans la résidence étudiante harmonie au 28 rue harmonie lyon 3.. réarmement impossible : mise en place d un agent de sécurité qualifié ssiap pour veiller toute la nuit.. autorités informées. j. lavergne info astreinte dsp: intervention des pompiers et de la police judiciaire pour un incendie, certainement d origine criminel dans une mosquée au 63 rue delandine- 28 cours bayard à lyon 2.. dégats situés au niveau de la porte d\'entrée.. responsable du site sur place.. une personne légèrement incommodé par les fumées.. autorités informées. j. lavergne info astreinte dsp :intervention en cours des pompiers au 3 rue santos dumont lyon 8, pour une grosse fuite d\'eau sur l alimentation générale du batiment au 2ème étage... une dizaine d appartements impactés par la fuite.. copropriété récente, syndic sur les lieux.. pour le moment, aucun relogement de prévu.. autorités informées. j. lavergne',
|
||||
144 => 'info astreinte dsp : intervention sapeurs-pompiers au 24 rue jacquard pour un mur en pisé gorgé d\'eau menacant. mur situé dans la cage d\'escalier menant au 1er étage d\'un immeuble de 4 étages. coupure d\'eau effectuée sur l\'ensemble, pas de victimes, évacuation du batiment. 9 appartements impactés, 15 personnes évacuées. 7 personnes relogées par la mairie à la villa villmanzy (une famille de 5p et un couple) et 8 personnes relogées par leur propre moyen. propriétaire et bureau d\'étude, sur les lieux, procèdent au travaux de mise en sécurité (15j environ). autorités informées.',
|
||||
145 => 'info astreinte dsp : intervention sp en cours au gs champvert, lyon 5, 231 avenue barhelemy buyer pour intoxication collective. une classe de 12 élèves + professeur présentant des maux de tetes, non blessés, impactés par la découverte d\'une substance chimique en cours d\'identification. autorités informées christophe pel',
|
||||
146 => 'info astreinte dsp : intervention sp pour un effondrement de corniches au 11 rue dumont d\'urville à lyon 4. batiment en simple rdc à vocation de garage. mise en sécurité effectuée par les pompiers, les services de la métropole procèdent au nettoyage et balisage de la zone. régie lery présente sur place. autorités informées. christophe pel / amélie collet',
|
||||
147 => 'info astreinte dsp : interventions des sapeurs-pompiers rue vuillerme à lyon 2 pour un accident d\'un policier municipal (47 ans),en patrouille, ayant chuté seul en moto. agent médicalisé sur place par le smur pour des douleurs au dos et à la jambe, puis transporté sur l\'hopital edouard herriot. astreinte cabinet du maire informée. christophe pel',
|
||||
148 => 'info astreinte dsp : point sinistre 5/7 montée bonafous lyon 4. intervention toujours en cours des sp avec de nombreux dégats dont effondrement de plancher. pas de blessé. les habitants sont pris en charge avec hébergement chez famille et hotel vilmanzy. intervention complexe dans les pentes de la x-rousse qui se poursuit. nicole bouillod info astreinte dsp - suite incendie lyon 4: feu toujours en cours, rdc et r+1 en cours d\'extinction. equipe sp sd sur place, effondrement partiel de l\'immeuble. 43 personnes évacués, besoin en relogement en cours d\'évaluation. mm. rech, durand et montet-jourdran sur les lieux. info complémentaire à suivre. alexandra dussud info astreinte dsp - suite incendie au 7 montée bonafous lyon 4. batiment au n7 inhabitable et inaccessible car ensemble des niveaux effondrés, 14 personnes relogées par vdl, autres occupants pris en charge par des proches, procédure de péril à prévoir. n6 à 14 en vis à vis totalement évacués en raison du risque d\'effondrement de la facade, 8 personnes relogées par vdl, autres par leurs propres moyens. coupure de courant du secteur par enedis, 300 foyers impactés. opération sp toujours en cours. autorités informées. alexandra dussud',
|
||||
149 => 'info astreinte dsp : point situation intervention 7 montée bonafous, lyon 4 : opération d\'extinction toujours en cours liée à la complexité de la configuration du site et du déficit en eau. la métropole fait intervenir une entreprise pour la fermeture de la montée aux véhicules et aux piétons. opération dpsvl terminée pour ce soir. un point de situation doit etre fait demain matin. christophe pel',
|
||||
150 => 'info astreinte dsp : procédure gaz renforcée en cours pour fuite dans construction au 6 rue bon pasteur lyon 1. gaz barré sur vp. mise en place d\'un périmètre de sécurité. autorités informées. amélie collet.',
|
||||
151 => 'info astreinte dsp : suite intervention au 10 rue des verriers à lyon 7ème. effondrement du r+1 cette nuit. intervention des sapeurs-pompiers pour levée de doute sur la structure. interdiction d\'accès au batiment et sécurisation du site non modifiées par cet effondrement. la métropole a été avisée pour le lancement d\'une procédure de péril. la croix rouge francaise a pris contact avec les occupants évacués et en charge les premières nécessité pour le week-end. autorités informées christophe pel',
|
||||
152 => 'info astreinte dsp accident dans la montée de choulans dans le sens de la descente. un camion c\'est reversé sur un piéton qui est décédé. il s\'agirait d\'un étudiant. un témoin et le chauffeur du camion choqués sont pris en charge par les services de secours. un gros dispositif est en place christian appietto',
|
||||
153 => 'info astreinte dsp accident de la circulation boulevard stalingrad lyon 6. 4 urgences absolues dont un bébé de 2 mois et 1 pronostique vital engagé (homme 30 ans). le conducteur de 16 ans est placé en garde à vue par la police. adrien du verger',
|
||||
154 => 'info astreinte dsp accident entre 2 véhicules dont un ville de lyon au 5 rue du jardin des plantes dans le 1er. personnel vdl (service archéologie) légèrement blessé mais non transporté par les pompiers. la voiture a terminé sa course contre la facade et a endommagé l\'entrée d\'un salon de coiffure qui fera l\'objet d\'un arreté d\'interdiction d\'accueillir du public. travaux de sécurisation prévus cet après-midi. autorités informées. adrien du verger',
|
||||
155 => 'info astreinte dsp accident tramway/piéton, 6 avenue francis de préssensé lyon 8 victime en urgence absolue transportée par les pompiers. autorités informées renan debard',
|
||||
156 => 'info astreinte dsp angle 13 cours suchet / rue gilibert lyon 2. une cheminée tombée d\'un batiment r+3 sur vp et sur la terrasse du domino\'s pizza qui fera l\'objet d\'un arreté d\'évacuation. une seconde cheminée est menacante et sera mise en sécurité demain matin par une entreprise mandatée par la régie. un périmètre de sécurité est mis en place à l\'angle des deux rues (rue gilibert barrée) le temps des travaux. autorités informées. adrien du verger',
|
||||
157 => 'info astreinte dsp appel des sp pour l\'effondrement d\'un plafond en briques dans un logement au 1er etage d\'un immeuble d\'habitation sis 3 rue prof bonhomme à lyon 3ème. bien géré par batigère. la famille (2 adultes et un enfant) est évacuée et hébergée dans un hotel à proximité en attendant les mesures complémentaires à partir de lundi. autorités informées. nicole bouillod',
|
||||
158 => 'info astreinte dsp appel des sp pour pgr dans un immeuble d\'habitation (r+9) au 75 rue bataille - lyon 8. le gaz a été barré. actuellement, les sp procèdent à une reconnaissance, afin de permettre la réintégration des occupants du 7, 8 et 9ème étage. autorités informées. jf perez',
|
||||
159 => 'info astreinte dsp appel des sp pour pgr en cours au 25 rue pierre semard - lyon 7, canalisation arrachée lors des travaux, secteur isolé le temps de l\'intervention. autorités informées. jf perez',
|
||||
160 => 'info astreinte dsp appel du cta codis suite à des fissures présentes sur cloison du logement du 4ème étage au 4 rue de nuits - lyon 4ème. evacuation du locataire. le syndic procèdera rapidement à un diagnostic structure. autorités informées. c. appietto et jf perez',
|
||||
161 => 'info astreinte dsp appel du sdmis pour nous informer de la chute d\'éléments de facade au 2/5 rue jean marc bernard à lyon 3. une fissure est visible dans le mur pignon en pizay de terre. après controle le mur est sec le propriétaire sera contacté des demain pour mandater un spécialiste. autorité informées christian appietto',
|
||||
162 => 'info astreinte dsp chute d\'un arbre montée des esses lyon 4 cet arbre déraciné est en appui sur le mur de soutènement et la situation ne présente pas de risque immédiat. dès demain la dev sera informée pour intervention. autorités informées j.f. perez/ c. appietto',
|
||||
163 => 'info astreinte dsp complément d\'information 43 rue sergent michel berthet s\'agissant d\'une famille recomposée, les autres parents vont récupérer les enfants dans la journée. la grand-mère et les enfants sont d\'accord pour teleconsultation psychologique via la plateforme live de la préfecture. autorités informées p. ciarlitti',
|
||||
164 => 'info astreinte dsp complément feu 86 bd lyon 3. feu éteint. opération déblais en cours. pas de relogement ville de lyon ( relogement des occupants par leurs propres moyens).trafic tram t6 interrompu jusqu\'à la fin de l\'intervention. amélie collet.',
|
||||
165 => 'info astreinte dsp crue de la saone en cours, vigilance jaune. fermeture des bas-ports par la police municipale. autorités informées. renan debard',
|
||||
166 => 'info astreinte dsp en prévision des orages et du vent attendus sur lyon, evacuation et fermeture des grands parcs de la ville de lyon. autorités informées renan debard',
|
||||
167 => 'info astreinte dsp en prévision des orages et du vent attendus sur lyon. evacuation et fermeture des grands parcs de la ville de lyon. autorités informées. renan debard',
|
||||
168 => 'info astreinte dsp en raison alerte vent vitesse superieure a 70 km/h fermeture des grands parcs. p. ciarlitti',
|
||||
169 => 'info astreinte dsp evènement de sécurité publique rue villon lyon 8. individu menacant s\'étant échappé du ch le vinatier. il a été interpellé par les forces de police. important dispositif de pompiers et de police déployé. autorités informées renan debard',
|
||||
170 => 'info astreinte dsp fermeture des parcs (pto, gerland, ceriseraie et blandan) assurée par la pm depuis 12h environ compte tenu du vent. autorités informées. adrien du verger',
|
||||
171 => 'info astreinte dsp feu au premier étage d\'un immeuble r+6 situé 23 rue wakatsuki lyon 8. 14 personnes incommodées par les fumées 8 d\'entre elles conduites à l\'hopital. trois appartements évacués 8 personnes prises en charge par grand lyon habitat et relogées à l\'hotel lumière rue villon. pas de problème structurel. monsieur le maire du 8éme sur place autorités informées. christian appietto',
|
||||
172 => 'info astreinte dsp feu d\'appartement 54 rue maryse bastie lyon 8 au r+2 dans batiment r+4 géré par lmh. feu éteint. bilan des victimes: 1 en urgence absolue transportée à heh 15 impliqués vu par sp. 1 appartement détruit et 1 impacté par les fumées. autoritées informéees. message de complément suivra. p.favre',
|
||||
173 => 'info astreinte dsp feu d\'appartement au 32 rue sergent blandan lyon 1er arr. un logement impacté au quatrième étage d\'un immeuble r + 4 . 2 locataires évacués et relogés par leur assurance. pas de dégats structurels . autorités informés renan debard',
|
||||
174 => 'info astreinte dsp feu d\'appartement au 34 rue champagneux à lyon 8ème au r+2, dans un batiment d\'habitation en r+6. 29 évacués en cours de réintégration, 7 blessés transportés dont un en urgence absolue. intervention en cours, autorités informés et se déplacent. p. favre - j. castell',
|
||||
175 => 'info astreinte dsp feu de chambre au troisième étage d\'un immeuble r+6 pas de blessé appartement inhabitable. le relogement de la famille (2 adultes et 4 enfants) est organisé autorités informées christian appietto',
|
||||
176 => 'info astreinte dsp feu de logement au r+9 dans immeuble r+15 au 30 rue e. richerand à lyon 3ème. logement inhabitable, 6 personnes impactées mises à l\'abri, dont une transportée à heh pour des brulures. hébergement à prévoir. autorités informés. nicole bouillod',
|
||||
177 => 'info astreinte dsp feu de maison 86 bd pinel lyon3. maison en r+1. 1 couple d occupant . pas de blessé. feu maitrisé par les pompiers. exctinction toujours en cours. élu d.astreinte se déplace. autorités informées. amélie collet.',
|
||||
178 => 'info astreinte dsp feu de matelas dans une chambre de l\'hopital st jean de dieu (290 route de vienne lyon 8) au 1er étage. incendie éteint par le service de sécurité incendie de l\'hopital. le patient de la chambre a été incommodé par les fumées classée en urgence relative par le samu sur place. les autres patients du service concerné ont été évacués vers un autre batiment. direction de l\'établissement sur les lieux. aucun dégats structurels. autorités informées renan debard',
|
||||
179 => 'info astreinte dsp feu de poteau électrique cette nuit place abbé pierre dans le 9ème. une caméra de surveillance urbaine endommagée. prestataires prévenus pour réparations. autorités informées. adrien du verger',
|
||||
180 => 'info astreinte dsp feu de vl au r-2 d\'un batiment d\'habitation. intervention en cours et de longue durée du a des difficultés d\'accès au foyer. une trentaine de logements évacués. 10 personnes vu par les pompiers dont 3 enfants. aucun transport dans l\'immédiat. message complémentaire suivra. autorités informés. p.favre',
|
||||
181 => 'info astreinte dsp feu sur balcon avec début de propagation à la facade au rez de chaussée d\'un batiment d\'habitation en r+4. 1 appartement impacté par bris de la baie vitrée. pas de blessé. 2 personnes relogées par la famille. sécurisation du site par servimmo mandaté par lyon métropole habitat. autorités informés. p.favre',
|
||||
182 => 'info astreinte dsp groupe scolaire victor hugo - lyon 1er. un platane est tombé dans la cour de l\'école. il est adossé à un batiment mais ne l\'a pas endommagé. la dgtb fait intervenir l\'entreprise chazal demain dans la journée pour prendre en charge l\'arbre. autorités informées. adrien du verger',
|
||||
183 => 'info astreinte dsp importante fuite d\'eau dans un immeuble r+14 au 83 rue phillippe fabia. l\'alimentation en eau de l\'immeuble a été barrée par les sapeurs-pompiers et veolia présents sur les lieux. 60 logements impactés. la régie fera le nécessaire demain matin. autorités informées renan debard',
|
||||
184 => 'info astreinte dsp incendie 1 rue pont cotton 69009 feu d\'appartement au r+1 qui s\'est propagé au r+2 et à la toiture de l\'immeuble. toiture effondrée-15 appartements impactés. 4 personnes évacuées dont 2 relogées par vdl à la villa villemanzy . pas de blessé feu éteint mais sp toujours sur les lieux pour surveillance et deblai. élue d\'astreinte : mme nublat ,présente sur les lieux. reunion technique sur place à prévoir ce lundi matin. autorités informées p. ciarlitti',
|
||||
185 => 'info astreinte dsp incendie au 3ème étage sur balcon qui s\'est propagé à l\'appartement dans immeuble 32 rue professeur joseph nicolas / 99 avenue jean mermoz 69008. 3 occupants de l\'appartement légèrement incommodés par fumée évacuées sur heh. 2 autres occupants de l\'immeuble transportés sur heh pour memes raisons. appartement inhabitable pour les 3 occupants. solution de relogement sera établie à la sortie de l\'hopital en fonction de la situation des 3 personnes. pas de dégats structurels. autorités informées p. ciarlitti',
|
||||
186 => 'info astreinte dsp incident à la station de métro bellecour, explosion d\'un pneu d\'une rame de métro. 1 personne blessée légèrement et transportée par les sapeurs-pompiers. reprise du trafic normal. autorités informées. renan debard',
|
||||
187 => 'info astreinte dsp information des sp pour traitement d\'une petite pollution aux hydrocarbures dans la darse quai rambaud à lyon 2ème secteur confluence. autorités informées nicole bouillod',
|
||||
188 => 'info astreinte dsp information sdmis ce matin vers 5h00 feu de poubelle dans immeuble 41 rue du dauphiné 69003. feu rapidement éteint. 7 personnes évacuées en attente dissipation des fumées. pas de blessé. pas de dégats structurels. tous les ont occupants ont réintégré leur logement. enedis est intervenu pour remettre en service installation électrique endommagée. autorités informées p. ciarlitti',
|
||||
189 => 'info astreinte dsp information sdmis résidence hotelière 43 rue sergent michel berthet 69009 famille 3 adultes + 5 enfants dont mère 40 ans dcd , père 38 ans évacué sur hopital cardiologique. enquete de police en cours. sdmis sollicite vdl pour soutien psychologique des 5 enfants et de leur grand-mère. appel à l\'astreinte de la ddcs à la préfecture. en attente de leur retour. pour l\'instant pas de prise en charge hébergement par la ville. complément d\'information à suivre autorités informées. p. ciarlitti',
|
||||
190 => 'info astreinte dsp inondation en r-2, d\'un immeuble d\'habitation de 6 étages au 4 rue meynis à lyon 3ème. , suite à la montée des eaux de la nappe phréatique. intervention des pompiers pour pompage des eaux.la société servimo, mandatée par le syndic, prend le relais pour l\'assèchement et installation de pompes de relevage. autorités informées, jérémy castell - alexandra dussud',
|
||||
191 => 'info astreinte dsp intervention 48 bd des brotteaux lyon 6. affaissement de plancher au r+1 d\'un immeuble d\'habitation. pas de blessés. un appartement évacué, 2 adultes et 1 nourrisson relogés par la famille. autorites informées pascal favre',
|
||||
192 => 'info astreinte dsp intervention au 12 rue philippe gonnard dans le 1er arrondissement pour plusieurs fissures sur le mur d\'un immeuble d\'habitation r+3. 5 logements évacués par un arreté d\'évacuation,1 personne relogée par sa famille et 2 personnes en attente de prise de contact pour le relogement. le reste des logements sont inoccupés depuis le confinement. un etaiement d\'urgence a été réalisé par les sapeurs-pompiers, les travaux de consolidation seront mis en oeuvres des demain. autorités informées renan debard',
|
||||
193 => 'info astreinte dsp intervention au 16 rue mazagran lyon 7 dans un appartement au 4ème étage d\'un immeuble r+8. casserole laissée sur le feu ayant entrainé un départ de feu dans la cuisine. 1 homme de 28 ans (le locataire) intoxiqué par les fumées et transporté en urgence relative à st luc st jo. aucun dégats structurels. pas de relogement. autorités informées renan debard',
|
||||
194 => 'info astreinte dsp intervention au 2 rue georges gouy lyon 7 pour de multiples fissures sur batiment d\'habitation r+1. après vérification avec un ingénieur structure, il n y a pas danger sur la stabilité du bati. autorités informées renan debard',
|
||||
195 => 'info astreinte dsp intervention au 30 rue pré-gaudry lyon 7 pour un feu dans un local poubelle d\'une crèche privée au rdc d\'un immeuble de bureau r+4. pas de victimes, ni de dégats structurels. autorités informées. renan debard',
|
||||
196 => 'info astreinte dsp intervention au 8 rue bugeaud lyon 6 pour une fuite d\'eau sur une canalisation d un immeuble r+6. fuite réparée par eau du grand lyon. aucun impact sur les logements. pas de dégats structurels. autorités informées renan debard',
|
||||
197 => 'info astreinte dsp intervention avec sdmis + pn + pm 29 rue de crimee 69001 pour chute élément de toiture ayant endommagé un véhicule en stationnement. purge des éléments menacants par sp. déplacement par pm et fourrière de 3 véhicules. syndic sur place pour prise en compte des travaux de réparation. pas de blessé. pas d\'évacuation. autorités informées p. ciarlitti',
|
||||
198 => 'info astreinte dsp intervention des pompiers au 3 rue de tourville dans le 7ème. fuite d\'eau provenant d\'un chantier barrée par leurs soins. 2 logements impactés, syndic sera prévenu demain pour effectuer des vérifications électriques. pas de désordre structurel, pas d\'évacuation. adrien du verger',
|
||||
199 => 'info astreinte dsp intervention des sp au 31 rue saint jean pour un feu dans un trappe électrique sur la vp. feu maitrisé. autorités informées renan debard',
|
||||
200 => 'info astreinte dsp intervention des sp à la mairie centrale, suite au déclenchement du système de sécurité incendie. après levée de doute du poste de sécurité, un léger dégagement de fumés au niveau d\'une baie de brassage située en sous-sol est constaté. des tests thermiques ont été effectués : pas de points chauds signalés. etablissement sous surveillance en cas de nouveau déclenchement du ssi. autorités informées. jérémy castell',
|
||||
201 => 'info astreinte dsp intervention du sdmis au 110 rue des charmettes lyon 6 pour un blessé par arme à feu. la victime est décédée et l\'arme à feu n\'a pas été retrouvée. enquete de la police en cours. autorités informées renan debard',
|
||||
202 => 'info astreinte dsp intervention pompiers en cours pour rechercher une personne qui a sauté du pont raymond barre. important moyen engagé. autorités informées. p burdillat',
|
||||
203 => 'info astreinte dsp intervention pour une fuite d\'eau sur une colonne montante au 5ème étage d\'un immeuble r+5 au 30 rue claudius pionchon lyon 3. pas de dégats structurels. le bailleur s\'occupe de faire les réparations dans la journée, nécessaires au rétablissement de l\'eau et de l\'électricité dans les 30 logements impactés. autorités informées. renan debard',
|
||||
204 => 'info astreinte dsp intervention rue niepce lyon 4 sur un mouvement de terrain qui a engendré une coulée torrentielle. le quai gillet est fermé à la circulation le temps que la métropole procède au dégagement et au nettoyage de la chaussée. périmètre de sécurité mis en place autour du mouvement de terrain et condamnation des accès à la rue niepce. une commission des balmes sera réunie en urgence demain . pas de victimes pas d\'impact sur les infrastructures. autorités informées. renan debard',
|
||||
205 => 'info astreinte dsp intervention sdmis en cours 112 rue servient 69003 suite à feu d\'isolant de facade sur immeuble commercial en construction. chantier arreté, 80 ouvriers évacués pas de victime. circulation bus tcl et tramway t1 perturbée. autorités informées p. ciarlitti',
|
||||
206 => 'info astreinte dsp intervention sp au 4 rue grognard lyon 4 pour débord de toiture menacant de tomber sur la vp sur un immeuble d\'habitation r+4+comble aménagé. aucune mise en sécurité possible par les sapeurs-pompiers. fermeture de la moitié de la rue au droit du n4 (trottoir+stationnement+moitiée de chaussée) et installation d\'un tunnel pour sécuriser l\'accès au batiment. président du syndic sur les lieux. autorités informées. christophe pel',
|
||||
207 => 'info astreinte dsp intervention sp pour feu électrique parties communes - immeuble 92 rue joliot curie- 69005 incendie limité à la colonne courant faible. pas de blessé, pas d\'évacuation. enedis et grdf remettent en service leurs installations coupées lors de l\'intervention. p. ciarlitti',
|
||||
208 => 'info astreinte dsp intervention sp pour incendie au 5ème étage d\'un immeuble d\'habitation au 35 rue pasteur à lyon 7ème. toiture endommagée. 15 personnes évacuées dont 5 personnes relogées. autorités informées. n. bouillod - jf perez',
|
||||
209 => 'info astreinte dsp la préfecture du rhone a déclenché le niveau 3 du plan canicule. ccas et élue astreinte informés. automate appel activé p. ciarlitti',
|
||||
210 => 'info astreinte dsp le sinistre situé au 44 rue des noyers lyon 5 a détruit 2 vl (dont 1 équipée pour handicapé) dans garages boxés. 60 personnes impliqués. pas de blessés. pas de relogement. dégats apparents sur poutre et plafond du r-2. périmètre de sécurité établi au r-2 et r-1. p.favre',
|
||||
211 => 'info astreinte dsp lyon 3ème - 12 rue pierre bourdan infiltrations d\'eau dans un logement au r+3 d\'un batiment d\'habitation en r+3+combles aménagés. fuite en provenance du logement du dessus à priori. eau barrée par les pompiers, fuite stoppée. le logement impacté n\'a plus d\'électricité. les locataires (2 adultes et 1 enfants) restent dans le logement. lyon métropole habitat prend la suite du dossier. autorités informées. adrien du verger',
|
||||
212 => 'info astreinte dsp lyon 4 - parc popy arbre menacant dans l\'enceinte du parc. de gros troncons sont tombés durant l\'épisode de vent hier. des branches sont encore menacantes. décision prise de fermer le parc jusqu\'à mise en sécurité de l\'arbre par les espaces verts. autorités informées. adrien du verger',
|
||||
213 => 'info astreinte dsp lyon 5ème : 42 rue du commandant charcot feu d\'appartement au dernier étage d\'un batiment d\'habitation en r+5. appartement inhabitable. une famille (2 adultes et 2 enfants) relogée par ses propres moyens. autorités informées. adrien du verger',
|
||||
214 => 'info astreinte dsp lyon 7 - 45 rue d\'anvers feu d\'appartement au r+2 d\'un batiment r+4. appartement squatté sans occupant au moment du sinistre. pas de victimes. opérations de secours terminées. un arreté d\'évacuation sera pris pour l\'appartement détruit ainsi que celui du dessus par précaution. ce dernier est en location airbnb. 3 occupants (2 adultes et 1 nourisson) se relogent dans leur famille. autorités informées. adrien du verger',
|
||||
215 => 'info astreinte dsp message complémentaire: 1 appartement entièrement sinistré. un second impacté par les eaux d\'extinctions. 2 personnes relogés par famille et lmh. l\'ensemble des autres occupants réintègrent. fin des opérations de secours. p.favre',
|
||||
216 => 'info astreinte dsp opération de désamorcage terminée. réintégration de la population quasi terminée. renan debard',
|
||||
217 => 'info astreinte dsp ouverture du gymnase maurice scève lyon 4 sur réquisition préfectorale pour l\'accueil temporaire des migrants du square henon. autorités informées. renan debard',
|
||||
218 => 'info astreinte dsp pgr 4 rue pierre bordeix lyon 7. réseau gaz arraché suite travaux. 230 personnes impactées dont pompiers police et sncf. mise en sécurité réalisée et réparations en cours ( jusqu\'à demain). autorites informées. amélie collet. info astreinte dsp accident sur vp 23 quai raoul carrier lyon 9 impliquant un bus et un vl. désincarcération du conducteur du vl puis transporté sous escorte police à la demande du médecin du samu a heh pavillon h. remise en circulation de la voie par la gendarmerie. autorites informées . amélie collet.',
|
||||
219 => 'info astreinte dsp procédure gaz renforcée dans un immeuble au 19 place bellecour lyon 2. gaz barré par les pompiers pour stopper la fuite. recherche de fuite en cours. traffic tcl perturbé. autorités informées. renan debard',
|
||||
220 => 'info astreinte dsp procédure gaz renforcée sur vp au 49 rue servient lyon 3. fuite sur un compteur de chantier. 12 personnes évacuées temporairement par les pompiers. autorités informées renan debard',
|
||||
221 => 'info astreinte dsp rupture dune canalisation du réseau d\'arrosage automatique de l\'espace vert de la rue ruplinger lyon 1 des infiltrations sont constatées au rez de chaussée de l\'immeuble sis 3 rue adamoli. elles ont cessé peu de temps après la coupure de l\'alimentation du réseau d\'arrosage. christian appietto pas de relogement christian appietto',
|
||||
222 => 'info astreinte dsp signalement cheminée en mauvais état 50b rue salomon reinach - 69007. pompiers ont effectue reconnaissance a l\'échelle. le propriétaire a demande des devis a des entreprises pour démontage de la cheminée. devis doivent etre transmis sous 24h. pas d\'évacuation dans l\'attente des devis. un point de situation sera fait avec le propriétaire sous 48h quant au démarrage des travaux. autorités informées p. ciarlitti',
|
||||
223 => 'info astreinte dsp signalement de l\'officier de permanence du codis pour intervention cette nuit à 2h50 rue du doyen georges chapas lyon 9 pour 7 feus de véhicules simultanés. pas d\'impact sur des batiments. autorités informées. p burdillat',
|
||||
224 => 'info astreinte dsp signalement par les sp pour : - 2 arbres importants tombés sur la rue de saint cyr à lyon 9ème, l\'astreinte voirie a été saisie pour dégager le domaine public. - feu de voiture devant le batiment de l\'institution médico educatif au 1 rue louis bouquet à lyon 9ème, les lieux ne sont occupés et la reconnaissance avec le gardien permet de vérifier l\'absence de danger. autorités informées. nicole bouillod',
|
||||
225 => 'info astreinte dsp suite et fin sinistre 1 rue lavoisier : 8 logements sont évacués et 6 personnes sont relogées par grand lyon habitat (11 personnes concernées par les évacuations en tout). glh fait intervenir servimmo pour condamner certains appartements. une réunion est prévue sur place demain à 14h pour les suites à donner. autorités informées. adrien du verger',
|
||||
226 => 'info astreinte dsp suite info concernant 35 rue pasteur à lyon 7ème. rencontre technique ce matin en présence du syndic, sdmis, sinistrés, ccas et de l\'ingénieur structure. la moitié de la toiture a été détruite. les souches de cheminée n\'ont pas été détériorées. les occupants situés sur la partie gauche de l\'immeuble peuvent réintégrés leur logement. les occupants situés sur la partie droite de l\'immeuble, au droit de la toiture détruite, doivent rester évacués ceci jusqu\'à la mise en place de la bache qui aura lieu fin de cette semaine. le ccas accompagne les sinistrés dans leur démarche de relogement. n. bouillod - jf perez',
|
||||
227 => 'info astreinte dsp suite intervention rue niepce. les sapeurs pompiers et les services d\'assainissement procèdent à des reconnaissances approfondies sur la zone impacté. la commission des balmes se réunit en urgence à 11 h aujourd\'hui. autorités informées. renan debard',
|
||||
228 => 'info astreinte dsp suite événement au 23 rue saint jean lyon 5. 104 logements sont privés d\'électricité. enedis intervient à 17h pour rétablir le réseau dans la soirée. autorités informées renan debard',
|
||||
229 => 'info astreinte dsp suivi intervention pour l\'inondation au groupe scolaire diderot. opération de denoyage terminée par les sapeurs-pompiers. la dgtb assure la poursuite des opérations. renan debard',
|
||||
230 => 'info astreinte dsp trottoir face au 5 rue paul chenavard lyon 1 - explosion d\'un tabouret électrique sous trottoir projection du tampon. 3 personnes en état de choc et une jeune fille transportée aux urgences en observation, urgence relative. enedis sur place pour mise en sécurité des installations. autorités informées',
|
||||
231 => 'info astreinte dsp évacuation maison individuelle sise 1 rue bellevue 69003 en raison présence fissures traversantes dans mur pignon en pisé de terre suite à travaux de démolition sur propriété adjacente. famille occupant les lieux (2 a + 2 e) relogée chez des proches. demande de procédure de péril imminent auprès de la métropole. autorités informées p. ciarlitti',
|
||||
232 => 'info astreinte dsp. appel des sp pour une petite explosion pendant le service de midi dans la cuisine du restaurant le jungle au 2 quai riboud angle rue denuzière à lyon 2ème. aucun blessé. les désordres sont limités dans la cuisine sur le faux-plafond. gaz coupé sur l\'établissement. grdf a procédé à la vérification du branchement qui est ok jusque dans l\'établissement. cause possible : défaut sur les pianos de cuisson. le service des erp suivra le dossier pour la réouverture des lieux. autorités informés. nicole bouillod',
|
||||
233 => 'info astreinte dsp29 rue sgt michel berthet - lyon 9 : batiment de 4 étages. affaissements de planchers dans logements suite à travaux au 1er étage du batiment. les pompiers ont posé des étais pour renforcer ceux qui avaient été installés par l\'entreprise.l\'ensemble de la colonne est évacuée (coté droit de l\'immeuble) par précaution. 16 personnes sont donc relogées (3 foyers) par la régie qui mandate également un ingénieur structure demain matin à 10h.autorités informées.adrien du verger',
|
||||
234 => 'info astreinte dsp: chute d\'éléments de corniche sur vp au musée saint pierre. pas de blessés. purge effectué par sp. mise en place d\'un périmètre de sécurité. autorités informées ainsi que l\'astreinte batiment. p.favre info astreinte dsp: feu de vl dans parc de stationnement au r-2 d\'un ensemble batimentaire comprenant plusieurs immeubles d\'habitation situé entre les rues novel et barbier, lyon 6. 32 personnes évacuées. pas de relogement.dégats structurels apparents. périmètre de sécurité établi au r-2 et r-1. adjoint à la sécurité sur place. autorités informées. p.favre',
|
||||
235 => 'info astreinte dsp: dégagement de fumée important dans batiment d\'habitation au 20 place charles béraudier. foyer non localisé.10 personnes évacuées. une seule famille réside sur place et a pu regagner son logement. pas de dégats. société de gardiennage sur place. fin des opérations de secours à 22h30. autorités informées. p.favre',
|
||||
236 => 'info astreinte dsp: feu d\'appartement au r+7 d\'un batiment d\'habitation en r+8 situé au 13 rue lamothe, lyon 7. le feu a détruit une chambre, un balcon au r+7, et endommagé le balcon et les volets de l\'appartement du r+8 situé au dessus. pas de blesses, pas de désordre structurel. le logement du r+7 a été évacué et les 6 occupants relogés par leur assurance. autorités informées. p.favre',
|
||||
237 => 'info astreinte dsp: feu de chambre au dernier étage (5ème) dans un immeuble d\'habitation au 11 rue moncey, lyon 3. pas de blessés, pas de désordre structurel . 4 personnes relogées par association "entre 2 toits". autorités informées.p.favre',
|
||||
238 => 'info astreinte dsp: feu de vl dans parking d\'habitation au 09 rue des alouettes, lyon 8. pas de blessé. pas de relogement. autorités informées. p.favre',
|
||||
239 => 'info astreinte dsp: intervention en cours du 43 au 59 rue desaix lyon 3 pour inondation de locaux. 150 logements impactés dont 50 chambres d\'hotel ainsi qu\'un erp en pied d\'immeuble. veolia, régie, entreprise de plomberie sur les lieux. pas de désordre structurels, la réparation prendra plusieurs heures. acheminement de pack d\'eau assuré par véolia et régie. autorités informés. p.favre',
|
||||
240 => 'info astreinte dsp: intervention sp en cours au 10 rue du boeuf, lyon 5 pour fuite de gaz sur vp. gaz barré. reconnaissance en cours. autorités informées. p.favre',
|
||||
241 => 'info astreinte dsp: pgr au 63 rue de sèze lyon 6 (proximité mairie du 6ème). intervention en cours. autorités informées. amélie collet',
|
||||
242 => 'info astreinte dsp: procédure gaz renforcée dans immeuble d\'habitation au 84 avenue jean jaurès, lyon 7. relevés significatif dans gaine technique électrique. 9 personnes évacuées. avenue jean jaures coupée entre place jean jaurès et rue chevreul. circulation bus détournée. autorités informés. p.favre',
|
||||
243 => 'info astreinte dsp; intervention avec les sp pour inondation du 2ème sous-sol d\'un immeuble d\'habitation 14-16 rue duguesclin / 19 rue barrème à lyon 6ème. la pompe de relevage est hs suite à un incendie la veille dans un box à proximité. ce sous-sol étant au niveau de la nappe, il y a entre 10 à 30 cm d\'eau. l\'accès est interdit par des affichettes et de la rubalise. alliade habitat gestionnaire du bien est contacté et missionne une entreprise. autorités informées. nicole bouillod',
|
||||
244 => 'info astreinte dsphébergement urgence à la demande du commissariat lyon 9 pour jeune femme en provenance de dijon agressée et violée.hotel réservé b&b tassin pour deux nuitssera mise en relation avec services sociaux pour prise en charge ultérieure autorités informéesp. ciarlitti',
|
||||
245 => 'info préf 43 vigilance orange neige-verglas annoncée samedi 08/02/25 de 00h à 21h plus d\'infos sur vigilance.meteofrance.fr et par mail (surveillez vos spam)',
|
||||
246 => 'info préfecture 43 exercice de securite civile prévu le 05/10/23 sur le barrage de naussac plus d\'information par mail (surveillez vos spam)',
|
||||
247 => 'info préfecture 43 exercice securite civile prévu le 05/10/23 sur le barrage de naussac consultez vos mails (surveillez spam)',
|
||||
248 => 'info préfecture haute-loire vigilance orange pluie-inondation annoncée sur le 43 plus d\'infos sur vigilance.meteofrance.fr et par mail (surveillez vos spam)',
|
||||
249 => 'info préfecture service de prévision des crues : vigilance jaune crue - troncon lignon du velay plus d\'infos sur vigicrues.gouv.fr et mail (surveillez spam)',
|
||||
250 => 'info préfecture service de prévision des crues : vigilance jaune crue - troncon loire vellave plus d\'infos sur vigicrues.gouv.fr et mail (surveillez vos spam)',
|
||||
251 => 'info préfecture vigilance jaune crue activé pour le troncon lignon vellave plus d\'infos sur vigicrues.gouv.fr et par mail (surveillez spam)',
|
||||
252 => 'info préfecture vigilance jaune crue activée pour le troncon lignon du velay. plus d\'infos sur vigicrues.gouv.fr et par mail (surveillez spam)',
|
||||
253 => 'info préfecture vigilance jaune crue activée sur le troncon loire vellave plus d\'infos sur vigicrues.gouv.fr et mail (surveillez vos spam)',
|
||||
254 => 'info préfecture vigilance jaune crue activée sur le troncon loire vellave plus d\'infos sur vigicrues.gouv.fr et par mail (surveillez vos spam)',
|
||||
255 => 'info préfecture vigilance orange crue activée sur le troncon lignon vellave plus d\'infos sur vigicrues.gouv.fr et mail (surveillez spam)',
|
||||
256 => 'info préfecture vigilance orange crue activée sur le troncon loire vellave plus d\'infos sur vigicrues.gouv.fr et par mail (surveillez vos spam)',
|
||||
257 => 'info préfecture vigilance rouge crue activée sur le troncon lignon vellave plus d\'infos sur vigicrues.gouv.fr et par mail (surveillez spam)',
|
||||
258 => 'info préfecture vvigilance rouge crue activée sur le troncon loire vellave plus d\'infos sur vigicrues.gouv.fr et par mail (surveillez vos spam)',
|
||||
259 => 'info: col de la forclaz commune talloires-montmin, collision entre 2 deltaplanes. les 2 impliqués ont ouverts leur parachute de secours, suite reconnaissance de dragon 741, deux personnes indemnes. ltn barral',
|
||||
260 => 'information pref 43 vigilance orange pluie-inondation activée sur le 43. plus d\'infos sur vigilance.meteofrance.fr et par mail (surveillez vos spam)',
|
||||
261 => 'information préfecture 43 : placement en vigilance jaune crue du troncon alagnon. risque de montée rapide des niveaux sous orage. infos sur vigicrues.gouv.fr et mail (surveillez vos spam)',
|
||||
262 => 'information préfecture 43 : placement en vigilance jaune crue du troncon allier brivadois. risque de montée rapide des niveaux sous orage. infos : vigicrues.gouv.fr et mail (surveillez vos spam)',
|
||||
263 => 'information préfecture 43 : placement en vigilance jaune crue du troncon allier brivadois. risque de montée rapide des niveaux sous orage. infos sur vigicrues.gouv.fr et mail (surveillez vos spam)',
|
||||
264 => 'information préfecture 43 : placement en vigilance jaune crue du troncon haut allier. risque de montée rapide des niveaux sous orages. plus d\'infos sur vigicrues.gouv.fr et mail (surveillez spam)',
|
||||
265 => 'information préfecture 43 : placement en vigilance jaune crues du troncon haut allier. risque de montée rapide des niveaux sous orages. plus d\'infos sur vigicrues.gouv.fr et mail (surveillez spam)',
|
||||
266 => 'information préfecture 43 fin de la vigilance jaune crue sur le troncon alagnon-aval',
|
||||
267 => 'information préfecture 43 service de prévision des crues : vigilance jaune crue - troncon alagnon aval infos sur vigicrues.gouv.fr et mail (surveillez vos spam)',
|
||||
268 => 'information préfecture 43 service de prévision des crues : vigilance jaune crue - troncon alagnon infos sur vigicrues.gouv.fr et mail (surveillez vos spam)',
|
||||
269 => 'information préfecture 43 vigilance jaune crue activée sur le troncon alagnon infos sur vigicrues.gouv.fr et mail (surveillez vos spam)',
|
||||
270 => 'information préfecture haute-loire la levée de la vigilance orange canicule annoncée pour ce soir 22h plus d\'infos sur https:/vigilance.meteofrance.fr/',
|
||||
271 => 'information préfecture haute-loire la vigilance orange neige-verglas sera prolongée demain jusqu\'à 18h plus d\'infos sur vigilance.meteofrance.fr',
|
||||
272 => 'information préfecture haute-loire la vigilance orange neige-verglas sera prolongée jusqu\'à demain 18h plus d\'infos sur vigilance.meteofrance.fr',
|
||||
273 => 'information préfecture haute-loire le préfet de haute-loire informe que le département est placé en vigilance rouge canicule à compter de ce mardi 22 aout à partir de midi. plus d\'infos sur vigilance.meteofrance.fr et par mail (surveillez vos spam)',
|
||||
274 => 'information préfecture haute-loire vigilance orange canicule annoncée plus d\'infos sur vigilance.meteofrance.fr et par mail (surveillez vos spam)',
|
||||
275 => 'information préfecture haute-loire vigilance orange canicules annoncée plus d\'infos sur vigilance.meteofrance.fr et par mail (surveillez vos spam)',
|
||||
276 => 'information préfecture haute-loire vigilance orange neige-verglas annoncée plus d\'infos sur vigilance.meteofrance.fr et par mail (surveillez vos spam)',
|
||||
277 => 'information préfecture haute-loire vigilance orange orages annoncée plus d\'infos sur vigilance.meteofrance.fr et par mail (surveillez vos spam)',
|
||||
278 => 'information préfecture haute-loire vigilance orange orages annoncée. plus d\'infos sur vigilance.meteofrance.fr et par mail (surveillez vos spam)',
|
||||
279 => 'information préfecture haute-loire vigilance orange orages à compter d\'aujourd\'hui en milieu d\'après-midi. plus d\'infos sur vigilance.meteofrance.fr et par mail (surveillez vos spam)',
|
||||
280 => 'information préfecture haute-loire vigilance orange orages étendue jusqu\'à 22h plus d\'infos sur vigilance.meteofrance.fr et par mail (surveillez vos spam)',
|
||||
281 => 'information préfecture haute-loire vigilance orange vent annoncée plus d\'infos sur vigilance.meteofrance.fr et par mail (surveillez vos spam)',
|
||||
282 => 'information préfecture haute-loire vigilance orange vents annoncée plus d\'infos sur vigilance.meteofrance.fr et par mail (surveillez vos spam)',
|
||||
283 => 'information préfecture haute-loire vigilance orange vents violents annoncée plus d\'infos sur vigilance.meteofrance.fr et par mail (surveillez vos spam)',
|
||||
284 => 'information préfecture haute-loire vigilance rouge neige-verglas annoncée plus d\'infos sur vigilance.meteofrance.fr et par mail (surveillez vos spam)',
|
||||
285 => 'information préfecture haute-loire épisode de pollution atmosphérique en raison de la persistance de poussières désertiques dans l\'air infos complémentaires par mail (surveillez vos spam)',
|
||||
286 => 'information préfecture service de prévision des crues : vigilance jaune crue - troncon allier brivadois infos : vigicrues.gouv.fr et mail (surveillez vos spam)',
|
||||
287 => 'information préfecture service de prévision des crues : vigilance jaune crue - troncon borne plus d\'infos sur vigicrues.gouv.fr et mail (surveillez spam)',
|
||||
288 => 'information préfecture service de prévision des crues : vigilance jaune crue - troncon haut allier plus d\'infos sur vigicrues.gouv.fr et mail (surveillez spam)',
|
||||
289 => 'information préfecture vigilance jaune crue activée sur le troncon allier brivadois infos : vigicrues.gouv.fr et mail (surveillez vos spam)',
|
||||
290 => 'information préfecture vigilance jaune crue activée sur le troncon allier brivadois plus d\'infos : vigicrues.gouv.fr et par mail (surveillez vos spam)',
|
||||
291 => 'information préfecture vigilance jaune crue activée sur le troncon haut allier plus d\'infos sur vigicrues.gouv.fr et mail (surveillez spam)',
|
||||
292 => 'information préfecture vigilance jaune crue activée sur le troncon haut allier plus d\'infos sur vigicrues.gouv.fr et par mail (surveillez vos spam)',
|
||||
293 => 'information préfecture vigilance rouge crue activée sur le troncon haut allier plus d\'infos sur vigicrues.gouv.fr et par mail (surveillez spam)',
|
||||
294 => 'infos préfet haute-loire vigilance orange pluie-inondation demain à partir de 10h. plus d\'infos sur vigilance.meteofrance.fr et par mail (surveillez vos spam)',
|
||||
295 => 'interdiction de circulation, poids-lourds articulés transport de marchandises rn102 secteur sud du département pj : arreté préfectoral préf43',
|
||||
296 => 'interdiction de circulation, véhicules de transport collectif de plus de 3.5t du vendredi 07 février 2025 22h00 au dimanche 09 février 18h00, sur les nationales 88 et 102 au sud du département de la haute-loire pj : arreté préfectoral préf43',
|
||||
297 => 'interdiction de circulation, véhicules transport de marchandises articulés ptac >3.5 t, rn102 secteur sud du département pj : arreté préfectoral préf43',
|
||||
298 => 'interdiction de circulation, véhicules transport de marchandises articulés, rn88 et rn102 secteur sud du département pj : arreté préfectoral préf43',
|
||||
299 => 'interdiction de circulation, véhicules transport de marchandises ptac >3.5 t articulés, rn88 et rn102 secteur sud du département pj : arreté préfectoral préf43',
|
||||
300 => 'interdiction de circulation, véhicules transport de marchandises ptac >3.5t, puis tous véhicules, sur rn102 secteur sud du département pj : arreté préfectoral préf43',
|
||||
301 => 'interdiction de circulation, véhicules transport de marchandises ptac >7.5 t sur autoroute a75, dans les deux sens de circulation, entre la jonction avec l\'a71 et la limite départementale sud de la lozère. pj : arreté préfectoral préf43',
|
||||
302 => 'interdiction de circulation, véhicules transport de marchandises ptac >7.5 t sur rn88 et rn102 : secteur sud du département. obligation port d\'équipement hivernaux tous véhicules. pj : arreté préfectoral préf43',
|
||||
303 => 'interdiction de circulation, véhicules transport de marchandises ptac >7.5 t sur rn88, secteur nord/est du département dans le sens firminy- le puy-en - velay obligation port d\'équipement hivernaux tous véhicules. pj : arreté préfectoral préf43',
|
||||
304 => 'interdiction de circulation, véhicules transport de marchandises ptac >7.5 t, rn88 et rn102 secteur sud du département pj : arreté préfectoral préf43',
|
||||
305 => 'interdiction de circulation, véhicules transport de marchandises ptac >7.5 t, rn88 secteur nord/est du département (sens le puy en velay-st etienne). pj : arreté préfectoral préf43',
|
||||
306 => 'interdiction de circulation, véhicules transport de marchandises ptac >7.5 t, rn88 secteur sud du département pj : arreté préfectoral préf43',
|
||||
307 => 'interdiction de circulation, véhicules transport de marchandises ptac >7.5 t, rn88 sud du département haute-loire pj : arreté préfectoral préf43',
|
||||
308 => 'interdiction temporaire de circulation de certains pl sur rn102 secteur sud du département voir arreté préfectoral par mail préf43',
|
||||
309 => 'la commune est en vigilance orange pour pluie inondations . le pcs de niveau 3 a été activé. restez disponible en cas de déclenchement du pcs.',
|
||||
310 => 'la mairie tient à la disposition de ceux qui en ont besoin des masques ffp2 à raison de 10 par personnes. ils sont disponibles aux horaires habituels.',
|
||||
311 => 'la pompe du forage fonctionne à nouveau depuis vendredi soir. merci pour vos efforts pour économiser l\'eau ces derniers jours.',
|
||||
312 => 'la préfecture de l\'allier déclenche une vigilance orange, en raison de vents forts, qui vont souffler durant la nuit, du mardi 21 février à 18h00; au mercredi 2',
|
||||
313 => 'la préfecture des hauts-de-seine vous informe : un message d\'alerte concernant le point de situation n 5 vient de vous etre transmis par mail. les communes sont invitées à remplir le point de situation en ligne avant samedi 15h.',
|
||||
314 => 'le pghm de chamonix a trouvé le corps sans vie d\'un francais de 24 ans qui a dévissé sur 300 m en ski de randonnée dans le secteur de bellachat, il a été descendu par choucas à la dz des bois pour etre vu par un médecin.',
|
||||
315 => 'le préfet de la haute-loire informe que le département sera placé en vigilance orange "neige / verglas" à compter de minuit et jusqu\'à neuf heures. plus d\'information sur le site https://vigilance.meteofrance.fr',
|
||||
316 => 'les pluies devraient s\'estomper légèrement, mais une nouvelle crue de l\'aude plus haute qu\'hier est attendue d\'ici midi (due à la fonte des neiges). limitez vos déplacements. la pompe qui alimente le chateau d\'eau est sous l\'eau et ne peut tjrs pas fonctionner. merci de limiter votre consommation d\'eau à son maximum (pas de machines à laver...) pour éviter des restrictions plus importantes.',
|
||||
317 => 'message de test suspicion d\'attentat au palais de justice. confinez-vous jusqu\'à nouvel ordre.',
|
||||
318 => 'nous allons assurer une permanence à la mairie toute la nuit jusqu\'à ce que l\'alerte soit levée. patricia et yvonne vont dormir à la mairie afin d\'assurer cette permanence nocturne. on annonce que le gros des précipitations à venir aura lieu en 2e partie de cette nuit. si la situation devait s\'agraver, nous vous appellerons ou viendrons toquer chez vous si nécessaire. merci de prendre vos dispositions et de vous tenir pret au cas où. hedy',
|
||||
319 => 'nous constatons une consommation anormale d\'eau et un écoulement anormal à la station d\'épuration merci à chacun de vérifier ses installations personnelles car nous soupconnons une fuite importante dans une habitation',
|
||||
320 => 'par arreté municipal du 6/8/25, tous les feux en milieu extérieur sont interdits. ceci inclut les barbecues, meme à proximité des habitations, ainsi que l\'usage de la cigarette en dehors des zones urbaines. merci à chacun de respecter ces règles. voir arreté ci dessous.',
|
||||
321 => 'plusieurs interventions 3 vsav tignes et val d isere se mettre sur dispotel soff ops adc ales',
|
||||
322 => 'point de situation préfecture annecy : déclenchement d\'une tete de détection dans les combles. après reconnaissance ras. les services de la préfecture se chargent de faire passer une entreprise pour la vérification de l\'ensemble des tetes de détection et du ssi. ltne lise-may langeven',
|
||||
323 => 'prolongation jusqu\'à 20h de l\'interdiction de circulation, véhicules articulés de transport de marchandises , rn88 et rn102 sud du 43',
|
||||
324 => 'recherche 1 spv garde 12 j urgent',
|
||||
325 => 'recherche sp pour l astreinte de ce soir',
|
||||
326 => 'renfort feux urbains dans le sud: si dispo appeler csp albertville pour référencement rapidement sous couvert du chef de bo, nous veillerons au poj',
|
||||
327 => 'saint jorioz noyade d\'un homme qui a été vu ivre vers 20h30 au port de saint jorioz. il reste ses vetements sur le bord de l\'eau.engagement vpl, 2 blp, cyno, vsav, sonar',
|
||||
328 => 'suite de l\'intervention de moye, la personne a été retrouvée saine et sauve. après bilan par vsav, la victime sera transportée sur le change site annecy par le vsav. ltn jean-philippe gervex.',
|
||||
329 => 'un épisode pluvio-orageux important est attendu dès ce mercredi soir et jusqu\'à jeudi midi. merci de prendre toutes les mesures nécessaires. le n de la mairie 04 68 74 01 55 restera joignable en cas de nécessité.',
|
||||
330 => 'une coupure d\'eau aura lieu demain mardi, à partir de 8h30, le temps de changer une pièce sur le réseau d\'eau. merci de prendre vos dispositions',
|
||||
331 => 'une fuite importante a été détectée sur le réseau d\'eau. des coupures et des baisses de pressions sont susceptibles d\'avoir lieu toute la journée.',
|
||||
332 => 'urgent, recherchons 3 sp pour armer un vtu pour renfort dans le departement de l\'allier, depart immediat. duree 48h maximum contacter csp chy si dispo',
|
||||
333 => 'ville la grand: feu de 2 caves dans un batiment d\'habitation r+5-1 / 10 appartements impactés / 14 personnes évacuées / 1 intoxiqué / dispositif sinus activé./ inter en cours',
|
||||
);
|
||||
10
save/Keywords.php.save
Normal file
10
save/Keywords.php.save
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'alerte' => ['weight' => 50, 'fuzzy' => true],
|
||||
'population' => ['weight' => 30, 'fuzzy' => true],
|
||||
'immediat' => ['weight' => 20, 'fuzzy' => true],
|
||||
'evacuation' => ['weight' => 40, 'fuzzy' => true]
|
||||
];
|
||||
63
save/Lib/AlertClassifier.php.save
Normal file
63
save/Lib/AlertClassifier.php.save
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Classifier\Lib\Discriminant;
|
||||
|
||||
class AlertClassifier
|
||||
{
|
||||
/** @var array<string,int> */
|
||||
private $dictionary;
|
||||
|
||||
/** @var int */
|
||||
private $threshold;
|
||||
|
||||
/**
|
||||
* @param array<string,int> $dictionary eg: [
|
||||
* 'alerte' => 50, 'population' => 30 ...
|
||||
* ]
|
||||
* @param int $threshold Le score à partir duquel on est "sûr" à 100%
|
||||
*/
|
||||
public function __construct(array $dictionary, int $threshold = 100)
|
||||
{
|
||||
$this->dictionary = $dictionary;
|
||||
$this->threshold = $threshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $cleanWords
|
||||
* @return float Indice de confiance entre 0 et 1
|
||||
*/
|
||||
public function getConfidenceScore(array $cleanWords): float
|
||||
{
|
||||
$totalScore = 0;
|
||||
|
||||
foreach ($this->dictionary as $keyword => $weight) {
|
||||
$bestMatch = 0;
|
||||
|
||||
foreach ($cleanWords as $word) {
|
||||
$distance = levenshtein($keyword, $word);
|
||||
|
||||
// * Calcul du ratio de similitude (0 à 1)
|
||||
$maxLen = max(strlen($keyword), strlen($word));
|
||||
if ($maxLen === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$similarity = 1 - ($distance / $maxLen);
|
||||
|
||||
// * On ne garde que si c'est très proche (ex: > 80%)
|
||||
if ($similarity > 0.8) {
|
||||
$bestMatch = max($bestMatch, $similarity);
|
||||
}
|
||||
}
|
||||
|
||||
// * Ajout du poids pondéré par la qualité de la correspondance
|
||||
$totalScore += ($bestMatch * $weight);
|
||||
}
|
||||
|
||||
// * Normalisation : on plafonne à 1 (100%)
|
||||
$confidence = $totalScore / $this->threshold;
|
||||
return min(1.0, $confidence);
|
||||
}
|
||||
}
|
||||
141
save/Lib/MessageQualifier.php.save
Normal file
141
save/Lib/MessageQualifier.php.save
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Classifier\Lib;
|
||||
|
||||
use Rubix\ML\Classifiers\GaussianNB;
|
||||
use Rubix\ML\Classifiers\KDNeighbors;
|
||||
use Rubix\ML\Pipeline;
|
||||
use Rubix\ML\PersistentModel;
|
||||
use Rubix\ML\Persisters\Filesystem;
|
||||
use Rubix\ML\Datasets\Labeled;
|
||||
use Rubix\ML\Datasets\Unlabeled;
|
||||
use Rubix\ML\Classifiers\KNearestNeighbors; // Nouveau classificateur
|
||||
use Rubix\ML\Classifiers\NaiveBayes;
|
||||
use Rubix\ML\Kernels\Distance\Cosine;
|
||||
use Rubix\ML\Transformers\TextNormalizer;
|
||||
use Rubix\ML\Transformers\WordCountVectorizer;
|
||||
use Rubix\ML\Transformers\TfIdfTransformer;
|
||||
|
||||
class MessageQualifier
|
||||
{
|
||||
private $estimator;
|
||||
private $modelPath;
|
||||
|
||||
public function __construct(string $modelPath = __DIR__ . '/model.rbx')
|
||||
{
|
||||
$this->modelPath = $modelPath;
|
||||
$persister = new Filesystem($this->modelPath);
|
||||
|
||||
if (file_exists($this->modelPath)) {
|
||||
$this->estimator = PersistentModel::load($persister);
|
||||
} else {
|
||||
// Utilisation de K-NN qui accepte parfaitement les données TF-IDF
|
||||
// $this->estimator = new PersistentModel(
|
||||
// new Pipeline([
|
||||
// new TextNormalizer(),
|
||||
// // new WordCountVectorizer(10000),
|
||||
// new WordCountVectorizer(10000, 1, 2), // 1 = unigrammes (mots), 2 = bigrammes (groupes de 2 mots)
|
||||
// new TfIdfTransformer(),
|
||||
// ], new KNearestNeighbors(3)), // On regarde les 3 messages les plus proches
|
||||
// $persister
|
||||
// );
|
||||
|
||||
// Pourquoi ce changement règle le problème ?
|
||||
|
||||
// Stabilité mathématique : K-NN ne fait pas de division par la variance, il calcule simplement une distance géométrique entre les phrases. Vous n'aurez plus jamais de INF.
|
||||
|
||||
// Distance Cosinus : C'est le secret pour la classification de texte. Au lieu de compter la distance "physique" entre les mots, elle mesure l'angle entre les vecteurs de mots. Elle comprend que "Alerte incendie" et "Alerte feu" sont dans la même direction sémantique.
|
||||
|
||||
// K=5 : En passant à 5 voisins, vous obtenez des indices de confiance plus nuancés (0%, 20%, 40%, 60%, 80%, 100%) au lieu de paliers trop brutaux.
|
||||
|
||||
$this->estimator = new PersistentModel(
|
||||
new Pipeline([
|
||||
new TextNormalizer(),
|
||||
new WordCountVectorizer(10000, 1, 2), // 1 = unigrammes (mots), 2 = bigrammes (groupes de 2 mots)
|
||||
new TfIdfTransformer(),
|
||||
], new KNearestNeighbors(5, false, new Cosine())),
|
||||
$persister
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function train(array $samples, array $labels): void
|
||||
{
|
||||
if (file_exists($this->modelPath)) {
|
||||
unlink($this->modelPath);
|
||||
}
|
||||
|
||||
$dataset = new Labeled($samples, $labels);
|
||||
$this->estimator->train($dataset);
|
||||
$this->estimator->save();
|
||||
echo "Modèle entraîné avec succès.\n";
|
||||
}
|
||||
|
||||
// public function predict(string $message): string
|
||||
// {
|
||||
|
||||
// $dataset = new Unlabeled([$message]);
|
||||
// // Note : En 0.4.x, vérifiez si c'est [$message] ou [[$message]]
|
||||
// // selon si votre message est déjà pré-traité en string.
|
||||
// $predictions = $this->estimator->predict($dataset);
|
||||
// return $predictions[0];
|
||||
// }
|
||||
|
||||
public function predict(string $message): string
|
||||
{
|
||||
$dataset = new Unlabeled([[$message]]);
|
||||
|
||||
// Au lieu de donner juste l'étiquette, proba() donne les scores
|
||||
// Exemple : ['ALERTE' => 0.65, 'INFO' => 0.35]
|
||||
$probabilities = $this->estimator->proba($dataset)[0];
|
||||
|
||||
print_r($probabilities);
|
||||
die;
|
||||
|
||||
$confianceAlerte = $probabilities['ALERTE'] ?? 0;
|
||||
|
||||
// Seuil de décision personnalisé
|
||||
if ($confianceAlerte > 0.60) {
|
||||
return 'ALERTE';
|
||||
} elseif ($confianceAlerte < 0.20) {
|
||||
return 'INFO';
|
||||
} else {
|
||||
return 'DOUTE_HUMAIN'; // Le système n'est pas assez sûr
|
||||
}
|
||||
}
|
||||
|
||||
public function predictWithConfidence(string $message): array
|
||||
{
|
||||
// Rubix ML attend un dataset, même pour une seule ligne
|
||||
$dataset = new Unlabeled([[$message]]);
|
||||
|
||||
// Récupère les probabilités (ex: ['ALERTE' => 0.66, 'INFO' => 0.33])
|
||||
$probabilities = $this->estimator->proba($dataset)[0];
|
||||
|
||||
|
||||
print_r($probabilities);
|
||||
die;
|
||||
|
||||
|
||||
// On récupère la classe qui a le score le plus haut
|
||||
arsort($probabilities); // Trie par score décroissant
|
||||
$label = key($probabilities);
|
||||
$confidence = current($probabilities);
|
||||
|
||||
// Stratégie de décision
|
||||
if ($confidence < 0.60) {
|
||||
$finalLabel = 'DOUTE_HUMAIN';
|
||||
} else {
|
||||
$finalLabel = $label;
|
||||
}
|
||||
|
||||
return [
|
||||
'label' => $finalLabel,
|
||||
'original_label' => $label,
|
||||
'confidence' => $confidence,
|
||||
'scores' => $probabilities
|
||||
];
|
||||
}
|
||||
}
|
||||
55
save/Lib/MessageQualifierShort.php.save
Normal file
55
save/Lib/MessageQualifierShort.php.save
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Classifier\Lib;
|
||||
|
||||
use Rubix\ML\PersistentModel;
|
||||
use Rubix\ML\Pipeline;
|
||||
use Rubix\ML\Transformers\TextNormalizer;
|
||||
use Rubix\ML\Transformers\WordCountVectorizer;
|
||||
use Rubix\ML\Transformers\TfIdfTransformer;
|
||||
use Rubix\ML\Classifiers\NaiveBayes;
|
||||
use Rubix\ML\Persisters\Filesystem;
|
||||
use Rubix\ML\Datasets\Unlabeled;
|
||||
|
||||
class MessageQualifierShort
|
||||
{
|
||||
private $estimator;
|
||||
private $modelPath;
|
||||
|
||||
public function __construct(string $modelPath = __DIR__ . '/model.rbx')
|
||||
{
|
||||
$this->modelPath = $modelPath;
|
||||
|
||||
if (file_exists($this->modelPath)) {
|
||||
$this->estimator = PersistentModel::load(new Filesystem($this->modelPath));
|
||||
} else {
|
||||
// Pipeline optimisée pour le texte
|
||||
$this->estimator = new PersistentModel(
|
||||
new Pipeline([
|
||||
new TextNormalizer(), // Supprime ponctuation, minuscules
|
||||
new WordCountVectorizer(5000, 1, 2), // Unigrammes et Bigrammes (ex: "alerte" et "alerte incendie")
|
||||
new TfIdfTransformer(), // Donne du poids aux mots rares et importants
|
||||
], new NaiveBayes()),
|
||||
new Filesystem($this->modelPath)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function predict(string $message): array
|
||||
{
|
||||
$dataset = new Unlabeled([[$message]]);
|
||||
$probabilities = $this->estimator->proba($dataset)[0];
|
||||
|
||||
arsort($probabilities);
|
||||
$label = key($probabilities);
|
||||
$confidence = current($probabilities);
|
||||
|
||||
return [
|
||||
'label' => $label,
|
||||
'confidence' => $confidence,
|
||||
'all_scores' => $probabilities
|
||||
];
|
||||
}
|
||||
}
|
||||
131
save/Lib/StringClassifier.php.save
Normal file
131
save/Lib/StringClassifier.php.save
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Classifier\Lib;
|
||||
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\Console\Input\ArgvInput;
|
||||
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||
|
||||
class StringClassifier
|
||||
{
|
||||
const OUTPUT_DIR = __DIR__ . '/../output';
|
||||
const GOOD_FILE = self::OUTPUT_DIR . '/positive.php';
|
||||
const BAD_FILE = self::OUTPUT_DIR . '/negative.php';
|
||||
const IGNORE_FILE = self::OUTPUT_DIR . '/ignored.php'; // Nouveau fichier
|
||||
|
||||
/** @var string[] */
|
||||
private $strings = [];
|
||||
|
||||
/** @var SymfonyStyle */
|
||||
private $io;
|
||||
|
||||
/** @var array{good: string[], bad: string[], ignored: string[]} */
|
||||
private $results = ['good' => [], 'bad' => [], 'ignored' => []];
|
||||
|
||||
public function __construct(array $strings)
|
||||
{
|
||||
$this->io = new SymfonyStyle(new ArgvInput(), new ConsoleOutput());
|
||||
|
||||
$this->loadExistingData();
|
||||
|
||||
$cleaned = array_unique(array_map(function (string $value): string {
|
||||
return preg_replace('/\s+/', ' ', trim(mb_strtolower($value)));
|
||||
}, $strings));
|
||||
|
||||
$alreadyDone = array_merge(
|
||||
$this->results['good'],
|
||||
$this->results['bad'],
|
||||
$this->results['ignored']
|
||||
);
|
||||
|
||||
$this->strings = array_diff($cleaned, $alreadyDone);
|
||||
|
||||
if (!is_dir(self::OUTPUT_DIR)) {
|
||||
mkdir(self::OUTPUT_DIR, 0777, true);
|
||||
}
|
||||
}
|
||||
|
||||
private function loadExistingData(): void
|
||||
{
|
||||
$files = [
|
||||
'good' => self::GOOD_FILE,
|
||||
'bad' => self::BAD_FILE,
|
||||
'ignored' => self::IGNORE_FILE
|
||||
];
|
||||
|
||||
foreach ($files as $key => $path) {
|
||||
if (file_exists($path)) {
|
||||
$this->results[$key] = include $path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function runQuestions(): void
|
||||
{
|
||||
$count = count($this->strings);
|
||||
if ($count === 0) {
|
||||
$this->io->success("Tous les messages fournis sont déjà labellisés ou ignorés !");
|
||||
return;
|
||||
}
|
||||
|
||||
$this->io->title('Labellisation des données (Mode Résilient)');
|
||||
$this->io->note([
|
||||
"Appuyez sur 'i' pour écarter un message définitivement.",
|
||||
"Appuyez sur 'q' pour sauvegarder et quitter."
|
||||
]);
|
||||
|
||||
$this->io->progressStart($count);
|
||||
|
||||
foreach ($this->strings as $string) {
|
||||
$this->io->newLine(2);
|
||||
$this->io->text("<info>Message :</info> $string");
|
||||
|
||||
$answer = $this->io->choice(
|
||||
'Action pour ce message ?',
|
||||
[
|
||||
'y' => 'Oui (Alerte)',
|
||||
'n' => 'Non (Autre)',
|
||||
'i' => 'Ignorer (Passer)',
|
||||
'q' => 'Quitter et Sauvegarder'
|
||||
],
|
||||
'n'
|
||||
);
|
||||
|
||||
if ($answer === 'q') {
|
||||
$this->io->note("Interruption demandée...");
|
||||
break;
|
||||
}
|
||||
|
||||
if ($answer === 'y') {
|
||||
$this->results['good'][] = $string;
|
||||
} elseif ($answer === 'i') {
|
||||
$this->results['ignored'][] = $string;
|
||||
} else {
|
||||
$this->results['bad'][] = $string;
|
||||
}
|
||||
|
||||
$this->io->progressAdvance();
|
||||
}
|
||||
|
||||
$this->io->progressFinish();
|
||||
$this->saveResults();
|
||||
|
||||
$this->io->success("Sauvegarde effectuée. Ignorés : " . count($this->results['ignored']));
|
||||
}
|
||||
|
||||
private function saveResults(): void
|
||||
{
|
||||
$this->exportToFile(self::GOOD_FILE, $this->results['good']);
|
||||
$this->exportToFile(self::BAD_FILE, $this->results['bad']);
|
||||
$this->exportToFile(self::IGNORE_FILE, $this->results['ignored']);
|
||||
}
|
||||
|
||||
private function exportToFile(string $path, array $data): void
|
||||
{
|
||||
sort($data);
|
||||
$content = "<?php\n\nreturn " . var_export($data, true) . ";\n";
|
||||
file_put_contents($path, $content);
|
||||
}
|
||||
}
|
||||
52
save/Lib/TextNormalizer.php.save
Normal file
52
save/Lib/TextNormalizer.php.save
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Classifier\Lib;
|
||||
|
||||
use Phpml\Transformer;
|
||||
|
||||
class TextNormalizer implements Transformer
|
||||
{
|
||||
public function fit(array $samples, ?array $targets = null): void
|
||||
{
|
||||
// Pas d'apprentissage nécessaire pour ce transformateur
|
||||
}
|
||||
|
||||
public function transform(array &$samples, ?array &$targets = null): void
|
||||
{
|
||||
foreach ($samples as &$sample) {
|
||||
$sample = $this->normalize($sample);
|
||||
}
|
||||
}
|
||||
|
||||
private function normalize(string $value): string
|
||||
{
|
||||
$output = $this->fromUt8ToPlainText($value);
|
||||
$output = $this->safelyRemoveEmptyLines($output);
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
private function fromUt8ToPlainText(string $value): string
|
||||
{
|
||||
// * Supprimer les balises
|
||||
$output = strip_tags($value);
|
||||
|
||||
// * Convertir les entités html (ex: & devient &)
|
||||
$output = html_entity_decode($output, ENT_QUOTES | ENT_HTML5, 'UTF-8');
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
private function safelyRemoveEmptyLines(string $value): string
|
||||
{
|
||||
// * Remplace les lignes ne contenant que des espaces/tabs par une chaîne vide
|
||||
$result = preg_replace('/^[\s\t]*[\r\n]+/m', '', $value);
|
||||
|
||||
// * Remplace les sauts de lignes avec un `\n` unique
|
||||
$result = preg_replace('/\R/', "\n", $result);
|
||||
|
||||
return $result ?? $value;
|
||||
}
|
||||
}
|
||||
16
save/TokenIzer.php.save
Normal file
16
save/TokenIzer.php.save
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use Phpml\Tokenization\Tokenizer;
|
||||
|
||||
class WhitespaceLowerTokenizer implements Tokenizer
|
||||
{
|
||||
public function tokenize(string $text): array
|
||||
{
|
||||
$substrings = preg_split('/[\pZ\pC]+/u', $text, -1, PREG_SPLIT_NO_EMPTY);
|
||||
if ($substrings === false) {
|
||||
throw new InvalidArgumentException('preg_split failed on: ' . $text);
|
||||
}
|
||||
|
||||
return array_map('mb_strtolower', $substrings);
|
||||
}
|
||||
}
|
||||
16
save/classifyData.php.save
Normal file
16
save/classifyData.php.save
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Classifier\Lib\DataSanitizer;
|
||||
use Classifier\Lib\StringClassifier;
|
||||
|
||||
require_once __DIR__ . '/vendor/autoload.php';
|
||||
require_once __DIR__ . '/Lib/DataSanitizer.php';
|
||||
require_once __DIR__ . '/Lib/StringClassifier.php';
|
||||
|
||||
$sanitizer = new DataSanitizer();
|
||||
$sourcestrings = $sanitizer->getSanitizedStrings();
|
||||
|
||||
$stringClassifier = new StringClassifier($sourcestrings);
|
||||
$stringClassifier->runQuestions();
|
||||
100
save/ml.php.save
Normal file
100
save/ml.php.save
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
<?php
|
||||
|
||||
require __DIR__ . '/vendor/autoload.php';
|
||||
|
||||
use Phpml\Classification\SVC;
|
||||
use Phpml\FeatureExtraction\TfIdfTransformer;
|
||||
use Phpml\FeatureExtraction\TokenCountVectorizer;
|
||||
use Phpml\Tokenization\WhitespaceTokenizer;
|
||||
use Phpml\SupportVectorMachine\Kernel;
|
||||
use Phpml\ModelManager;
|
||||
|
||||
require __DIR__ . '/TokenIzer.php';
|
||||
|
||||
// 1. Vos données d'entraînement
|
||||
// $samples = [
|
||||
// 'Je suis très heureux',
|
||||
// 'C\'est fantastique',
|
||||
// 'Je suis triste',
|
||||
// 'C\'est horrible'
|
||||
// ];
|
||||
// $labels = ['positif', 'positif', 'négatif', 'négatif'];
|
||||
|
||||
// $messageTest = <<<'EOT'
|
||||
// Bonjour, je vends mon iPhone 12 Pro Max 256 Go en excellent état, avec tous les accessoires d'origine. Prix : 900€. Contactez-moi pour plus d'informations.
|
||||
// EOT;
|
||||
$messageTest = <<<'EOT'
|
||||
Alerte : un incendie s'est déclaré dans un immeuble du centre-ville. Les pompiers sont sur place et maîtrisent la situation. Aucune victime n'est à déplorer pour le moment, mais les autorités recommandent d'éviter le secteur. Nous vous tiendrons informés de l'évolution de la situation.
|
||||
EOT;
|
||||
|
||||
$samples = [];
|
||||
$labels = [];
|
||||
|
||||
$files = [
|
||||
__DIR__ . '/output/positive.php',
|
||||
__DIR__ . '/output/negative.php',
|
||||
];
|
||||
|
||||
foreach ($files as $file) {
|
||||
$texts = require $file;
|
||||
foreach ($texts as $text) {
|
||||
$samples[] = $text;
|
||||
$labels[] = basename($file, '.php');
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Transformer le texte en vecteurs (nombres) compréhensibles par la machine
|
||||
$vectorizer = new TokenCountVectorizer(new WhitespaceLowerTokenizer());
|
||||
$vectorizer->fit($samples);
|
||||
$vectorizer->transform($samples);
|
||||
|
||||
// 3. Entraîner le classifier
|
||||
$classifier = new SVC(Kernel::SIGMOID, 10000);
|
||||
$classifier->train($samples, $labels);
|
||||
|
||||
// 4. Prédire
|
||||
$newSample = [$messageTest];
|
||||
$vectorizer->transform($newSample);
|
||||
echo $classifier->predict($newSample)[0]; // Affiche "négatif"
|
||||
|
||||
// 5. Sauvegarder le modèle
|
||||
$filepath = __DIR__ . '/model.phpml';
|
||||
$modelManager = new ModelManager();
|
||||
$modelManager->saveToFile($classifier, $filepath);
|
||||
|
||||
// 6. Charger le modèle
|
||||
$restoredClassifier = $modelManager->restoreFromFile($filepath);
|
||||
echo "\n" . 'Prédiction avec le modèle chargé : ' . $restoredClassifier->predict($newSample)[0] . "\n";
|
||||
|
||||
/// --- TEST ---
|
||||
|
||||
$samples = [];
|
||||
$labels = [];
|
||||
|
||||
foreach ($files as $file) {
|
||||
$texts = require $file;
|
||||
foreach ($texts as $text) {
|
||||
$samples[] = $text;
|
||||
$labels[] = basename($file, '.php');
|
||||
}
|
||||
}
|
||||
|
||||
// --- Étape A : Vectorisation (Comptage) ---
|
||||
$vectorizer = new TokenCountVectorizer(new WhitespaceLowerTokenizer());
|
||||
$vectorizer->fit($samples);
|
||||
$vectorizer->transform($samples);
|
||||
|
||||
// --- Étape B : Transformation TF-IDF ---
|
||||
$transformer = new TfIdfTransformer();
|
||||
$transformer->fit($samples); // Calcule l'importance des mots sur tout le corpus
|
||||
$transformer->transform($samples); // Applique le calcul aux échantillons
|
||||
|
||||
// --- Étape C : Entraînement ---
|
||||
$classifier = new SVC(Kernel::RBF, 10000);
|
||||
$classifier->train($samples, $labels);
|
||||
|
||||
// --- Étape D : Prédiction ---
|
||||
$newSample = [$messageTest];
|
||||
$vectorizer->transform($newSample);
|
||||
$transformer->transform($newSample);
|
||||
echo $classifier->predict($newSample)[0]; // Affiche "positif"
|
||||
BIN
save/model.phpml.save
Normal file
BIN
save/model.phpml.save
Normal file
Binary file not shown.
152
save/modernClassifier.php.save
Normal file
152
save/modernClassifier.php.save
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Classifier\Lib\MessageQualifier;
|
||||
use Classifier\Lib\MessageQualifierShort;
|
||||
use Classifier\Lib\TextNormalizer;
|
||||
use TextAnalysis\Tokenizers\GeneralTokenizer;
|
||||
use TextAnalysis\Filters\StopWordsFilter;
|
||||
|
||||
require_once __DIR__ . '/vendor/autoload.php';
|
||||
// require_once __DIR__ . '/Lib/MessageQualifier.php';
|
||||
require_once __DIR__ . '/Lib/MessageQualifierShort.php';
|
||||
require_once __DIR__ . '/Lib/TextNormalizer.php';
|
||||
|
||||
// Le message à tester
|
||||
// $message = "Bonjour, incendie signalé dans la commune, veuillez évacuer immédiatement !";
|
||||
// $message = "Bonjour, le montant de votre allocation logement a changé. Merci de vous rapprocher de la CAF et de procéder au paiement du montant du dès que possible.";
|
||||
// $message = "
|
||||
// Objet : Nouveauté - votre avis d’échéance bientôt en ligne
|
||||
|
||||
// Cher client,
|
||||
|
||||
// À compter de septembre, fini le papier ! Votre avis d’échéance ne sera plus envoyé par courrier, mais sera désormais disponible chaque mois dans la rubrique Mes documents de votre espace client.
|
||||
|
||||
// Une solution plus rapide, plus pratique et plus respectueuse de l’environnement !
|
||||
|
||||
// Pour profiter pleinement de ce nouveau service, pensez à :
|
||||
|
||||
// Mettre à jour votre adresse e-mail et votre numéro de téléphone dans votre profil
|
||||
// Activer les notifications de l’application pour rester informé en temps réel
|
||||
|
||||
// Ce changement vous permet de gagner en autonomie, de réduire les délais de réception et de contribuer à une démarche durable.
|
||||
|
||||
// Merci de votre confiance !
|
||||
|
||||
// L’équipe SIDR
|
||||
// ";
|
||||
// NOK
|
||||
// $message = "Bonjour, une inondation a été signalée dans la commune, veuillez évacuer immédiatement !";
|
||||
// $message = "
|
||||
// Ici la société BUTAGAZ, située route du bois rochers, à Le Douhet.
|
||||
|
||||
// ATTENTION, CECI N'EST PAS UN EXERCICE, ATTENTION, CECI N'EST PAS UN EXERCICE, ATTENTION, CECI N'EST PAS UN EXERCICE.
|
||||
|
||||
// Nous avons déclenché le P O I, suite à un incident survenu sur le site à XX h XX.
|
||||
|
||||
// Le sinistre est situé au niveau ZONE.
|
||||
|
||||
// Le produit impliqué est PRODUIT.
|
||||
|
||||
// Nous avons mis en oeuvre les moyens nécessaires pour limiter les effets.
|
||||
|
||||
// Nous déplorons NOMBRE victimes, mais cette information pourrait évoluer.
|
||||
|
||||
// A ce stade, la demande de mise en oeuvre du P P I , n’est pas à exclure.
|
||||
|
||||
// Pour nous contacter, le numéro de téléphone à utiliser est le : 05.46.97.78.99, le : 05.46.97.78.99.
|
||||
|
||||
// Il n'est pas nécessaire de nous rappeler afin de confirmer la bonne réception de ce message.
|
||||
|
||||
// La ligne téléphonique doit rester disponible pour la gestion de l'événement.
|
||||
|
||||
// Tapez simplement 1, lorsque cela vous sera demandé.
|
||||
|
||||
// ATTENTION, CECI N'EST PAS UN EXERCICE, ATTENTION, CECI N'EST PAS UN EXERCICE, ATTENTION, CECI N'EST PAS UN EXERCICE.
|
||||
// ";
|
||||
$message = "Attention attentat, un attentat a été signalé dans la commune, merci de rester chez vous et d'éviter les déplacements !";
|
||||
|
||||
// 1. Nettoyage (Votre code existant)
|
||||
$tokens = (new GeneralTokenizer())->tokenize(mb_strtolower($message));
|
||||
|
||||
(new TextNormalizer())->transform($tokens);
|
||||
|
||||
// J'ai ajouté quelques stop words pertinents pour vos alertes
|
||||
// $tokens = (new StopWordsFilter([
|
||||
// 'le',
|
||||
// 'la',
|
||||
// 'de',
|
||||
// 'du',
|
||||
// 'les',
|
||||
// 'des',
|
||||
// 'un',
|
||||
// 'une',
|
||||
// 'et',
|
||||
// 'ou',
|
||||
// 'mais',
|
||||
// 'donc',
|
||||
// 'or',
|
||||
// 'ni',
|
||||
// 'car',
|
||||
// 'je',
|
||||
// 'tu',
|
||||
// 'il',
|
||||
// 'elle',
|
||||
// 'nous',
|
||||
// 'vous',
|
||||
// 'ils',
|
||||
// 'elles',
|
||||
// 'ce',
|
||||
// 'cet',
|
||||
// 'cette',
|
||||
// 'pour',
|
||||
// 'sur',
|
||||
// 'dans'
|
||||
// ]))->transform($tokens);
|
||||
|
||||
// var_dump($tokens);
|
||||
// die;
|
||||
|
||||
// 2. Reconversion en chaîne de caractères (String)
|
||||
// Rubix ML a besoin d'une phrase, pas d'un tableau de mots.
|
||||
$cleanedMessage = implode(' ', $tokens);
|
||||
// Exemple de résultat : "bonjour exercice alerte inondation commune veuillez evacuer"
|
||||
|
||||
// 3. Prédiction
|
||||
// $classifier = new MessageQualifier();
|
||||
$classifier = new MessageQualifierShort();
|
||||
|
||||
try {
|
||||
|
||||
$message = "Attention attentat dans la zone industrielle !";
|
||||
|
||||
// 1. Priorité absolue : Mots-clés critiques (Hard-coded)
|
||||
// $motsCritiques = ['attentat', 'fusillade', 'évacuer'];
|
||||
// foreach ($motsCritiques as $mot) {
|
||||
// if (mb_stripos($message, $mot) !== false) {
|
||||
// die("ALERTE CRITIQUE DÉTECTÉE (Mot-clé)");
|
||||
// }
|
||||
// }
|
||||
|
||||
// 2. Si aucun mot critique, on demande au ML de nuancer
|
||||
$result = $classifier->predict($message);
|
||||
|
||||
if ($result['label'] === 'ALERTE' && $result['confidence'] > 0.7) {
|
||||
echo "Alerte probable confirmed par ML.";
|
||||
} else {
|
||||
echo "Simple information.";
|
||||
}
|
||||
|
||||
// $prediction = $classifier->predict($cleanedMessage);
|
||||
|
||||
// // 4. Logique métier
|
||||
// if ($prediction['label'] === 'ALERTE') {
|
||||
// echo "CECI EST UNE ALERTE ! Envoi sur canal prioritaire (SMS/Sirène).";
|
||||
// } else {
|
||||
// echo "Ceci est une information. Envoi sur canal secondaire (Email/App/Panneau).";
|
||||
// }
|
||||
} catch (\Exception $e) {
|
||||
// Si le fichier model.rbx n'existe pas
|
||||
echo "Erreur : Le modèle n'a pas été entraîné. Lancez train.php d'abord.";
|
||||
}
|
||||
35
save/negative.php.save
Normal file
35
save/negative.php.save
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
<<<'EOD'
|
||||
Votre avis d'échéance d'un montant de (%champ libre) € a été envoyé. Vous pouvez dès à présent le régler par téléphone au 0970289235.
|
||||
EOD,
|
||||
<<<'EOD'
|
||||
Bonjour, sauf erreur votre compte présente un solde débiteur. Merci de régulariser au plus vite sur zapay.fr, au 0970289235 ou sur votre application mobile SIDR
|
||||
EOD,
|
||||
<<<'EOD'
|
||||
Bonjour, sauf erreur votre compte présente un solde débiteur. Merci de régulariser au plus vite sur zapay.fr, au 0970289235 ou sur votre application mobile SIDR
|
||||
EOD,
|
||||
<<<'EOD'
|
||||
Plus que quelques jours pour gagner un iPhone 14.
|
||||
Télécharger vite l'application SIDR
|
||||
EOD,
|
||||
<<<'EOD'
|
||||
LA SIDR I BOUGE
|
||||
"Les Orientales I Change"
|
||||
Mercredi 09oct 24, aura lieu l'inauguration du LCR.
|
||||
A l'occasion, venez participer aux divers animations dès 14h00.
|
||||
EOD,
|
||||
<<<'EOD'
|
||||
Objet : Nouveauté - votre avis d’échéance bientôt en ligne
|
||||
Cher client,
|
||||
À compter de septembre, fini le papier ! Votre avis d’échéance ne sera plus envoyé par courrier, mais sera désormais disponible chaque mois dans la rubrique Mes documents de votre espace client.
|
||||
Une solution plus rapide, plus pratique et plus respectueuse de l’environnement !
|
||||
Pour profiter pleinement de ce nouveau service, pensez à :
|
||||
Mettre à jour votre adresse e-mail et votre numéro de téléphone dans votre profil
|
||||
Activer les notifications de l’application pour rester informé en temps réel
|
||||
Ce changement vous permet de gagner en autonomie, de réduire les délais de réception et de contribuer à une démarche durable.
|
||||
Merci de votre confiance !
|
||||
L’équipe SIDR
|
||||
EOD,
|
||||
];
|
||||
89
save/positive.php.save
Normal file
89
save/positive.php.save
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
<<<'EOD'
|
||||
ATTENTION ! De violents épisodes météorologiques (alerte orange METEO FRANCE) sont prévus dans les prochaines heures au droit de votre site.
|
||||
EOD,
|
||||
<<<'EOD'
|
||||
ATTENTION ! De violents épisodes météorologiques (crue de la Seine : hauteur d'eau supérieure à 8,5 mètres à la station Petit-Couronne) sont prévus dans les prochaines heures au droit de votre site.
|
||||
EOD,
|
||||
<<<'EOD'
|
||||
ATTENTION ! De violents épisodes météorologiques (crue du Golo : hauteur d'eau supérieure à 2,5 mètres à la station Volpajola) sont prévus dans les prochaines heures au droit de votre site.
|
||||
EOD,
|
||||
<<<'EOD'
|
||||
Ici la société BUTAGAZ, située Boulevard Maritime, à Petit-Couronne.
|
||||
ATTENTION, CECI EST UN EXERCICE, ATTENTION, CECI EST UN EXERCICE, ATTENTION, CECI EST UN EXERCICE.
|
||||
ATTENTION, CECI N'EST PAS UN EXERCICE, ATTENTION, CECI N'EST PAS UN EXERCICE, ATTENTION, CECI N'EST PAS UN EXERCICE.
|
||||
Nous vous informons de la survenance d’un accident sur notre site, nous vous demandons de ne pas gêner, de faciliter l’accès des secours à notre établissement et de prendre les dispositions suivantes DISPOSITIONS.
|
||||
Il n'est pas nécessaire de nous rappeler afin de confirmer la bonne réception de ce message.
|
||||
La ligne téléphonique doit rester disponible pour la gestion de l'événement.
|
||||
Tapez simplement 1, lorsque cela vous sera demandé.
|
||||
ATTENTION, CECI EST UN EXERCICE, ATTENTION, CECI EST UN EXERCICE, ATTENTION, CECI EST UN EXERCICE.
|
||||
ATTENTION, CECI N'EST PAS UN EXERCICE, ATTENTION, CECI N'EST PAS UN EXERCICE, ATTENTION, CECI N'EST PAS UN EXERCICE.
|
||||
EOD,
|
||||
<<<'EOD'
|
||||
Ici la société BUTAGAZ, située Boulevard Maritime, à Petit-Couronne.
|
||||
ATTENTION, CECI EST UN EXERCICE, ATTENTION, CECI EST UN EXERCICE, ATTENTION, CECI EST UN EXERCICE.
|
||||
ATTENTION, CECI N'EST PAS UN EXERCICE, ATTENTION, CECI N'EST PAS UN EXERCICE, ATTENTION, CECI N'EST PAS UN EXERCICE.
|
||||
Suite au déclenchement de notre P O I, nous vous informons que le sinistre est terminé, nous levons notre P O I .
|
||||
ATTENTION, CECI EST UN EXERCICE, ATTENTION, CECI EST UN EXERCICE, ATTENTION, CECI EST UN EXERCICE.
|
||||
ATTENTION, CECI N'EST PAS UN EXERCICE, ATTENTION, CECI N'EST PAS UN EXERCICE, ATTENTION, CECI N'EST PAS UN EXERCICE.
|
||||
EOD,
|
||||
<<<'EOD'
|
||||
Ici la société BUTAGAZ, située à La Teppe des tremblays, à Sennecey.
|
||||
ATTENTION, CECI N'EST PAS UN EXERCICE, ATTENTION, CECI N'EST PAS UN EXERCICE, ATTENTION, CECI N'EST PAS UN EXERCICE.
|
||||
Nous avons déclenché le P O I, suite à un incident survenu sur le site à XX h XX.
|
||||
Le sinistre est situé au niveau ZONE.
|
||||
Le produit impliqué est PRODUIT.
|
||||
Nous avons mis en oeuvre les moyens nécessaires pour limiter les effets.
|
||||
Nous déplorons NOMBRE victimes, mais cette information pourrait évoluer.
|
||||
A ce stade, la demande de mise en oeuvre du P P I , n’est pas à exclure.
|
||||
Pour nous contacter, le numéro de téléphone à utiliser est le : 03 85 94 19 60, le : 03 85 94 19 60.
|
||||
Il n'est pas nécessaire de nous rappeler afin de confirmer la bonne réception de ce message.
|
||||
La ligne téléphonique doit rester disponible pour la gestion de l'événement.
|
||||
Tapez simplement 1, lorsque cela vous sera demandé.
|
||||
ATTENTION, CECI N'EST PAS UN EXERCICE, ATTENTION, CECI N'EST PAS UN EXERCICE, ATTENTION, CECI N'EST PAS UN EXERCICE.
|
||||
EOD,
|
||||
<<<'EDO'
|
||||
Ici la société BUTAGAZ, située Route Nationale 113, à ROGNAC
|
||||
Attention, ceci est un exercice, Attention, ceci est un exercice, Attention, ceci est un exercice.
|
||||
Nous avons déclenché le P O I, suite à un incident survenu sur le site à XX h XX.
|
||||
Le sinistre est situé au niveau ZONE.
|
||||
Le produit impliqué est PRODUIT.
|
||||
Nous avons mis en oeuvre les moyens nécessaires pour limiter les effets.
|
||||
Nous déplorons NOMBRE victimes, mais cette information pourrait évoluer.
|
||||
A ce stade, la demande de mise en oeuvre du P P I , n’est pas à exclure.
|
||||
Pour nous contacter, le numéro de téléphone à utiliser est le : 04.42.34.81.37, le : 04.42.34.81.37.
|
||||
Il n'est pas nécessaire de nous rappeler afin de confirmer la bonne réception de ce message.
|
||||
La ligne téléphonique doit rester disponible pour la gestion de l'événement.
|
||||
Tapez simplement 1, lorsque cela vous sera demandé.
|
||||
Attention, ceci est un exercice, Attention, ceci est un exercice, Attention, ceci est un exercice.
|
||||
EDO,
|
||||
<<<'EOD'
|
||||
Bonjour,
|
||||
Vous trouverez en PJ la fiche Gravité / Perception complétée dans le cadre de [l'exercice POI / du POI] de notre établissement de ROGNAC.
|
||||
Cordialement,
|
||||
EOD,
|
||||
<<<'EOD'
|
||||
Bonjour,
|
||||
voici en pièce jointe l'objet de l'alerte.
|
||||
Cordialement,
|
||||
EOD,
|
||||
<<<'EOD'
|
||||
Message d'alerte vigilance jaune SMS pour un risque de verglas.
|
||||
Détails en pièce jointe et en mairie.
|
||||
Cordialement
|
||||
EOD,
|
||||
<<<'EOD'
|
||||
Bonjour,
|
||||
Voir pièce jointe l'objet de l'alerte relatif à l'ÉPISODE ORANGE NEIGE VERGLAS.
|
||||
Désactivation du COD.
|
||||
EOD,
|
||||
<<<'EOD'
|
||||
Bonjour,
|
||||
Voir en PJ l'objet de l'alerte relatif à l'épisode ORANGE NEIGE VERGLAS. Désactivation du COD.
|
||||
EOD,
|
||||
<<<'EOD'
|
||||
En raison des intempéries , votre ascenseur a été mis à l'arret à titre preventif. Dès retour au calme, nous mettons tout en oeuvre pour la remise en service.
|
||||
EOD,
|
||||
];
|
||||
31
save/test.php.save
Normal file
31
save/test.php.save
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
require __DIR__ . '/vendor/autoload.php';
|
||||
|
||||
$text = require __DIR__ . '/text.php';
|
||||
$tokens = tokenize($text, \TextAnalysis\Tokenizers\PennTreeBankTokenizer::class);
|
||||
$normalizedTokens = normalize_tokens($tokens, 'mb_strtolower');
|
||||
$freqDist = freq_dist($normalizedTokens);
|
||||
|
||||
$rake = rake($normalizedTokens, 3);
|
||||
$results = $rake->getKeywordScores();
|
||||
|
||||
|
||||
$nb = naive_bayes();
|
||||
$nb->train('mexican', tokenize('taco nacho enchilada burrito'));
|
||||
$nb->train('american', tokenize('hamburger burger fries pop'));
|
||||
$nb->train('alerte', normalize_tokens(tokenize('alerte message population exercice mairie cevezo victimes zone téléphone POI PPI'), 'mb_strtolower'));
|
||||
$nb->train('publicite', tokenize('produit promotion euro'));
|
||||
|
||||
|
||||
|
||||
$prediction = $nb->predict($normalizedTokens);
|
||||
|
||||
|
||||
var_dump(
|
||||
$normalizedTokens,
|
||||
ngrams($normalizedTokens),
|
||||
stem($normalizedTokens),
|
||||
$results,
|
||||
$prediction,
|
||||
);
|
||||
37
save/text.php.save
Normal file
37
save/text.php.save
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
$text = <<<TEXT
|
||||
Ici la société BUTAGAZ, située route du bois rochers, à Le Douhet.
|
||||
Attention, ceci est un exercice, Attention, ceci est un exercice, Attention, ceci est un exercice.
|
||||
Suite au déclenchement de notre P O I, nous vous informons que le sinistre est terminé, nous levons notre P O I .
|
||||
Attention, ceci est un exercice, Attention, ceci est un exercice, Attention, ceci est un exercice.
|
||||
|
||||
|
||||
Ici la société BUTAGAZ, située Route d'Ennordes, à Aubigny sur nère.
|
||||
|
||||
ATTENTION, CECI N'EST PAS UN EXERCICE, ATTENTION, CECI N'EST PAS UN EXERCICE, ATTENTION, CECI N'EST PAS UN EXERCICE.
|
||||
|
||||
Nous avons déclenché le P O I, suite à un incident survenu sur le site à XX h XX.
|
||||
|
||||
Le sinistre est situé au niveau ZONE.
|
||||
|
||||
Le produit impliqué est PRODUIT.
|
||||
|
||||
Nous avons mis en oeuvre les moyens nécessaires pour limiter les effets.
|
||||
|
||||
Nous déplorons NOMBRE victimes, mais cette information pourrait évoluer.
|
||||
|
||||
A ce stade, la demande de mise en oeuvre du P P I , n’est pas à exclure.
|
||||
|
||||
Pour nous contacter, le numéro de téléphone à utiliser est le : 02.48.58.02.77, le : 02.48.58.02.77.
|
||||
|
||||
Il n'est pas nécessaire de nous rappeler afin de confirmer la bonne réception de ce message.
|
||||
|
||||
La ligne téléphonique doit rester disponible pour la gestion de l'événement.
|
||||
|
||||
Tapez simplement 1, lorsque cela vous sera demandé.
|
||||
|
||||
ATTENTION, CECI N'EST PAS UN EXERCICE, ATTENTION, CECI N'EST PAS UN EXERCICE, ATTENTION, CECI N'EST PAS UN EXERCICE.
|
||||
TEXT;
|
||||
|
||||
return $text;
|
||||
48
save/train-short.php.save
Normal file
48
save/train-short.php.save
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
require_once __DIR__ . '/vendor/autoload.php';
|
||||
|
||||
use Classifier\Lib\MessageQualifier;
|
||||
|
||||
require_once __DIR__ . '/Lib/MessageQualifier.php';
|
||||
|
||||
|
||||
$samples = [
|
||||
// --- Catégorie ALERTE ---
|
||||
["Urgent : Incendie majeur détecté zone industrielle. Évacuez."],
|
||||
["Alerte inondation : la rivière déborde, montez dans les étages."],
|
||||
["Alerte attentat : restez confinés chez vous, évitez les déplacements."],
|
||||
["Fuite de gaz signalée rue de la Paix. Périmètre de sécurité en cours."],
|
||||
["ALERTE : Risque d'effondrement bâtiment mairie. Ne pas approcher."],
|
||||
["Incident chimique usine Sud. Fermez les fenêtres et bouchez les aérations."],
|
||||
|
||||
// --- Catégorie INFO (Le "bruit" quotidien) ---
|
||||
["Le ramassage des ordures sera décalé à mardi prochain."],
|
||||
["Inauguration de la nouvelle bibliothèque ce samedi à 14h."],
|
||||
["Information : Travaux sur la voirie prévus du 12 au 15 mars."],
|
||||
["La coupure d'eau est terminée, merci de votre patience."],
|
||||
["Rappel : Pensez à inscrire vos enfants à la cantine scolaire."],
|
||||
["Le montant de votre allocation a été mis à jour dans votre espace."],
|
||||
["Ceci est un test technique du système d'alerte, aucune action requise."],
|
||||
];
|
||||
|
||||
$labels = [
|
||||
'ALERTE',
|
||||
'ALERTE',
|
||||
'ALERTE',
|
||||
'ALERTE',
|
||||
'ALERTE',
|
||||
'ALERTE',
|
||||
'INFO',
|
||||
'INFO',
|
||||
'INFO',
|
||||
'INFO',
|
||||
'INFO',
|
||||
'INFO',
|
||||
'INFO'
|
||||
];
|
||||
|
||||
$classifier = new MessageQualifier();
|
||||
$classifier->train($samples, $labels);
|
||||
|
||||
echo "Le cerveau de l'IA est prêt !";
|
||||
26
save/train.php.save
Normal file
26
save/train.php.save
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
require_once 'vendor/autoload.php';
|
||||
|
||||
use Classifier\Lib\MessageQualifier;
|
||||
|
||||
require_once __DIR__ . '/Lib/MessageQualifier.php';
|
||||
|
||||
|
||||
$keywordsAlertes = require_once __DIR__ . '/data/keywords.php';
|
||||
|
||||
$samples = [];
|
||||
$labels = [];
|
||||
|
||||
$keywordsAlertes['ALERTE'] = array_merge($keywordsAlertes['ALERTE'], require_once __DIR__ . '/output/positive.php');
|
||||
$keywordsAlertes['INFO'] = array_merge($keywordsAlertes['INFO'], require_once __DIR__ . '/output/negative.php');
|
||||
|
||||
foreach ($keywordsAlertes as $category => $messages) {
|
||||
foreach ($messages as $msg) {
|
||||
$samples[] = [$msg];
|
||||
$labels[] = $category;
|
||||
}
|
||||
}
|
||||
|
||||
$classifier = new MessageQualifier();
|
||||
$classifier->train($samples, $labels);
|
||||
66
testAlgo.php
Normal file
66
testAlgo.php
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Classifier\Lib\Discriminant\AlertAnalyzer;
|
||||
use Classifier\Lib\Discriminant\BlackList;
|
||||
use Classifier\Lib\Discriminant\WhiteList;
|
||||
use Classifier\Lib\Enum\MessageType;
|
||||
use Classifier\Lib\MessageClassifier;
|
||||
use Classifier\Lib\Model\MessageQualifier;
|
||||
use Classifier\Lib\Utils\StringCleaner;
|
||||
|
||||
require_once __DIR__ . '/vendor/autoload.php';
|
||||
require_once __DIR__ . '/Lib/index.php';
|
||||
|
||||
$message = <<<'EOT'
|
||||
SAN NICOLAO SEISME RESSENTI: ABRITEZ VOUS SOUS UN MEUBLE SOLIDE OU DANS UN ESPACE DEGAGE A L'EXTERIEUR INFO FB/INSTA + PREF2B+SIS2B
|
||||
|
||||
EOT;
|
||||
|
||||
// Seuil pour le dictionnaire
|
||||
$threshold = 100;
|
||||
|
||||
$modelPath = __DIR__ . '/model.rbx';
|
||||
|
||||
// Stop words : Mots à ignorer pour le nettoyage des messages
|
||||
$stopWords = require __DIR__ . '/data/stopwords.php';
|
||||
$strCleaner = new StringCleaner($stopWords);
|
||||
|
||||
// Liste noire : Priorité absolue pour tuer les faux positifs
|
||||
$blackList = new BlackList(require __DIR__ . '/data/blacklist.php', $strCleaner);
|
||||
|
||||
// Liste blanche : Mots clés avec poids pour le dictionnaire fuzzy
|
||||
$whiteList = new WhiteList(require __DIR__ . '/data/whitelist.php', $strCleaner);
|
||||
|
||||
/**
|
||||
* ! TYPE D'ALERTE PAR DEFAUT EN CAS DE DOUTE
|
||||
*/
|
||||
$defaultAlertType = MessageType::ALERTE();
|
||||
|
||||
$analyzer = new AlertAnalyzer($whiteList, $blackList, $strCleaner, $threshold);
|
||||
$qualifier = new MessageQualifier($modelPath);
|
||||
|
||||
// * Combinaison des deux approches Dictionnaire et machine learning
|
||||
$master = new MessageClassifier(
|
||||
$analyzer,
|
||||
$qualifier,
|
||||
$defaultAlertType
|
||||
);
|
||||
|
||||
try {
|
||||
$result = $master->classify($message);
|
||||
|
||||
echo "--- RÉSULTAT DE L'ANALYSE ---\n";
|
||||
echo "Message : " . substr($message, 0, 100) . "...\n";
|
||||
echo "Décision : " . $result->decision->getValue() . "\n";
|
||||
echo "Machine : " . ($result->machineDecision ? $result->machineDecision->getValue() : 'N/A') . "\n";
|
||||
echo "Méthode : " . $result->method->getValue() . "\n";
|
||||
echo "Confiance: " . round($result->confidence * 100, 2) . "%\n";
|
||||
|
||||
echo "Détails : " . implode(', ', array_map(function (object $d) {
|
||||
return $d->word . " (" . round($d->score * 100, 2) . "%)";
|
||||
}, $result->getDetails())) . "\n";
|
||||
} catch (\Exception $e) {
|
||||
echo "Erreur système : " . $e->getMessage();
|
||||
}
|
||||
23
vendor/amphp/amp/LICENSE
vendored
Normal file
23
vendor/amphp/amp/LICENSE
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-2019 amphp
|
||||
Copyright (c) 2016 PHP Asynchronous Interoperability Group
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
69
vendor/amphp/amp/composer.json
vendored
Normal file
69
vendor/amphp/amp/composer.json
vendored
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
{
|
||||
"name": "amphp/amp",
|
||||
"homepage": "https://amphp.org/amp",
|
||||
"description": "A non-blocking concurrency framework for PHP applications.",
|
||||
"keywords": [
|
||||
"async",
|
||||
"asynchronous",
|
||||
"concurrency",
|
||||
"promise",
|
||||
"awaitable",
|
||||
"future",
|
||||
"non-blocking",
|
||||
"event",
|
||||
"event-loop"
|
||||
],
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Daniel Lowrey",
|
||||
"email": "rdlowrey@php.net"
|
||||
},
|
||||
{
|
||||
"name": "Aaron Piotrowski",
|
||||
"email": "aaron@trowski.com"
|
||||
},
|
||||
{
|
||||
"name": "Bob Weinand",
|
||||
"email": "bobwei9@hotmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Niklas Keller",
|
||||
"email": "me@kelunik.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-json": "*",
|
||||
"amphp/phpunit-util": "^1",
|
||||
"amphp/php-cs-fixer-config": "dev-master",
|
||||
"react/promise": "^2",
|
||||
"phpunit/phpunit": "^7 | ^8 | ^9",
|
||||
"vimeo/psalm": "^3.12",
|
||||
"jetbrains/phpstorm-stubs": "^2019.3"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Amp\\": "lib"
|
||||
},
|
||||
"files": [
|
||||
"lib/functions.php",
|
||||
"lib/Internal/functions.php"
|
||||
]
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Amp\\Test\\": "test"
|
||||
}
|
||||
},
|
||||
"support": {
|
||||
"issues": "https://github.com/amphp/amp/issues",
|
||||
"irc": "irc://irc.freenode.org/amphp"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "@php -dzend.assertions=1 -dassert.exception=1 ./vendor/bin/phpunit",
|
||||
"code-style": "@php ./vendor/bin/php-cs-fixer fix"
|
||||
}
|
||||
}
|
||||
80
vendor/amphp/amp/lib/CallableMaker.php
vendored
Normal file
80
vendor/amphp/amp/lib/CallableMaker.php
vendored
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
namespace Amp;
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
if (\PHP_VERSION_ID < 70100) {
|
||||
/** @psalm-suppress DuplicateClass */
|
||||
trait CallableMaker
|
||||
{
|
||||
/** @var \ReflectionClass */
|
||||
private static $__reflectionClass;
|
||||
|
||||
/** @var \ReflectionMethod[] */
|
||||
private static $__reflectionMethods = [];
|
||||
|
||||
/**
|
||||
* Creates a callable from a protected or private instance method that may be invoked by callers requiring a
|
||||
* publicly invokable callback.
|
||||
*
|
||||
* @param string $method Instance method name.
|
||||
*
|
||||
* @return callable
|
||||
*
|
||||
* @psalm-suppress MixedInferredReturnType
|
||||
*/
|
||||
private function callableFromInstanceMethod(string $method): callable
|
||||
{
|
||||
if (!isset(self::$__reflectionMethods[$method])) {
|
||||
if (self::$__reflectionClass === null) {
|
||||
self::$__reflectionClass = new \ReflectionClass(self::class);
|
||||
}
|
||||
self::$__reflectionMethods[$method] = self::$__reflectionClass->getMethod($method);
|
||||
}
|
||||
|
||||
return self::$__reflectionMethods[$method]->getClosure($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a callable from a protected or private static method that may be invoked by methods requiring a
|
||||
* publicly invokable callback.
|
||||
*
|
||||
* @param string $method Static method name.
|
||||
*
|
||||
* @return callable
|
||||
*
|
||||
* @psalm-suppress MixedInferredReturnType
|
||||
*/
|
||||
private static function callableFromStaticMethod(string $method): callable
|
||||
{
|
||||
if (!isset(self::$__reflectionMethods[$method])) {
|
||||
if (self::$__reflectionClass === null) {
|
||||
self::$__reflectionClass = new \ReflectionClass(self::class);
|
||||
}
|
||||
self::$__reflectionMethods[$method] = self::$__reflectionClass->getMethod($method);
|
||||
}
|
||||
|
||||
return self::$__reflectionMethods[$method]->getClosure();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/** @psalm-suppress DuplicateClass */
|
||||
trait CallableMaker
|
||||
{
|
||||
/**
|
||||
* @deprecated Use \Closure::fromCallable() instead of this method in PHP 7.1.
|
||||
*/
|
||||
private function callableFromInstanceMethod(string $method): callable
|
||||
{
|
||||
return \Closure::fromCallable([$this, $method]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use \Closure::fromCallable() instead of this method in PHP 7.1.
|
||||
*/
|
||||
private static function callableFromStaticMethod(string $method): callable
|
||||
{
|
||||
return \Closure::fromCallable([self::class, $method]);
|
||||
}
|
||||
}
|
||||
} // @codeCoverageIgnoreEnd
|
||||
49
vendor/amphp/amp/lib/CancellationToken.php
vendored
Normal file
49
vendor/amphp/amp/lib/CancellationToken.php
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
namespace Amp;
|
||||
|
||||
/**
|
||||
* Cancellation tokens are simple objects that allow registering handlers to subscribe to cancellation requests.
|
||||
*/
|
||||
interface CancellationToken
|
||||
{
|
||||
/**
|
||||
* Subscribes a new handler to be invoked on a cancellation request.
|
||||
*
|
||||
* This handler might be invoked immediately in case the token has already been cancelled. Returned generators will
|
||||
* automatically be run as coroutines. Any unhandled exceptions will be throw into the event loop.
|
||||
*
|
||||
* @param callable(CancelledException) $callback Callback to be invoked on a cancellation request. Will receive a
|
||||
* `CancelledException` as first argument that may be used to fail the operation's promise.
|
||||
*
|
||||
* @return string Identifier that can be used to cancel the subscription.
|
||||
*/
|
||||
public function subscribe(callable $callback): string;
|
||||
|
||||
/**
|
||||
* Unsubscribes a previously registered handler.
|
||||
*
|
||||
* The handler will no longer be called as long as this method isn't invoked from a subscribed callback.
|
||||
*
|
||||
* @param string $id
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function unsubscribe(string $id);
|
||||
|
||||
/**
|
||||
* Returns whether cancellation has been requested yet.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isRequested(): bool;
|
||||
|
||||
/**
|
||||
* Throws the `CancelledException` if cancellation has been requested, otherwise does nothing.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws CancelledException
|
||||
*/
|
||||
public function throwIfRequested();
|
||||
}
|
||||
164
vendor/amphp/amp/lib/CancellationTokenSource.php
vendored
Normal file
164
vendor/amphp/amp/lib/CancellationTokenSource.php
vendored
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
<?php
|
||||
|
||||
namespace Amp;
|
||||
|
||||
use React\Promise\PromiseInterface as ReactPromise;
|
||||
use function Amp\Promise\rethrow;
|
||||
|
||||
/**
|
||||
* A cancellation token source provides a mechanism to cancel operations.
|
||||
*
|
||||
* Cancellation of operation works by creating a cancellation token source and passing the corresponding token when
|
||||
* starting the operation. To cancel the operation, invoke `CancellationTokenSource::cancel()`.
|
||||
*
|
||||
* Any operation can decide what to do on a cancellation request, it has "don't care" semantics. An operation SHOULD be
|
||||
* aborted, but MAY continue. Example: A DNS client might continue to receive and cache the response, as the query has
|
||||
* been sent anyway. An HTTP client would usually close a connection, but might not do so in case a response is close to
|
||||
* be fully received to reuse the connection.
|
||||
*
|
||||
* **Example**
|
||||
*
|
||||
* ```php
|
||||
* $tokenSource = new CancellationTokenSource;
|
||||
* $token = $tokenSource->getToken();
|
||||
*
|
||||
* $response = yield $httpClient->request("https://example.com/stream", $token);
|
||||
* $responseBody = $response->getBody();
|
||||
*
|
||||
* while (($chunk = yield $response->read()) !== null) {
|
||||
* // consume $chunk
|
||||
*
|
||||
* if ($noLongerInterested) {
|
||||
* $cancellationTokenSource->cancel();
|
||||
* break;
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @see CancellationToken
|
||||
* @see CancelledException
|
||||
*/
|
||||
final class CancellationTokenSource
|
||||
{
|
||||
/** @var CancellationToken */
|
||||
private $token;
|
||||
|
||||
/** @var callable|null */
|
||||
private $onCancel;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$onCancel = null;
|
||||
|
||||
$this->token = new class($onCancel) implements CancellationToken {
|
||||
/** @var string */
|
||||
private $nextId = "a";
|
||||
|
||||
/** @var callable[] */
|
||||
private $callbacks = [];
|
||||
|
||||
/** @var \Throwable|null */
|
||||
private $exception;
|
||||
|
||||
/**
|
||||
* @param mixed $onCancel
|
||||
* @param-out callable $onCancel
|
||||
*/
|
||||
public function __construct(&$onCancel)
|
||||
{
|
||||
/** @psalm-suppress MissingClosureReturnType We still support PHP 7.0 */
|
||||
$onCancel = function (\Throwable $exception) {
|
||||
$this->exception = $exception;
|
||||
|
||||
$callbacks = $this->callbacks;
|
||||
$this->callbacks = [];
|
||||
|
||||
foreach ($callbacks as $callback) {
|
||||
$this->invokeCallback($callback);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable $callback
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function invokeCallback(callable $callback)
|
||||
{
|
||||
// No type declaration to prevent exception outside the try!
|
||||
try {
|
||||
/** @var mixed $result */
|
||||
$result = $callback($this->exception);
|
||||
|
||||
if ($result instanceof \Generator) {
|
||||
/** @psalm-var \Generator<mixed, Promise|ReactPromise|(Promise|ReactPromise)[], mixed, mixed> $result */
|
||||
$result = new Coroutine($result);
|
||||
}
|
||||
|
||||
if ($result instanceof Promise || $result instanceof ReactPromise) {
|
||||
rethrow($result);
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
Loop::defer(static function () use ($exception) {
|
||||
throw $exception;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public function subscribe(callable $callback): string
|
||||
{
|
||||
$id = $this->nextId;
|
||||
\PHP_VERSION_ID >= 80300 ? $this->nextId = \str_increment($this->nextId) : ++$this->nextId;
|
||||
|
||||
if ($this->exception) {
|
||||
$this->invokeCallback($callback);
|
||||
} else {
|
||||
$this->callbacks[$id] = $callback;
|
||||
}
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
public function unsubscribe(string $id)
|
||||
{
|
||||
unset($this->callbacks[$id]);
|
||||
}
|
||||
|
||||
public function isRequested(): bool
|
||||
{
|
||||
return isset($this->exception);
|
||||
}
|
||||
|
||||
public function throwIfRequested()
|
||||
{
|
||||
if (isset($this->exception)) {
|
||||
throw $this->exception;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$this->onCancel = $onCancel;
|
||||
}
|
||||
|
||||
public function getToken(): CancellationToken
|
||||
{
|
||||
return $this->token;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Throwable|null $previous Exception to be used as the previous exception to CancelledException.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function cancel(?\Throwable $previous = null)
|
||||
{
|
||||
if ($this->onCancel === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$onCancel = $this->onCancel;
|
||||
$this->onCancel = null;
|
||||
$onCancel(new CancelledException($previous));
|
||||
}
|
||||
}
|
||||
17
vendor/amphp/amp/lib/CancelledException.php
vendored
Normal file
17
vendor/amphp/amp/lib/CancelledException.php
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace Amp;
|
||||
|
||||
/**
|
||||
* Will be thrown in case an operation is cancelled.
|
||||
*
|
||||
* @see CancellationToken
|
||||
* @see CancellationTokenSource
|
||||
*/
|
||||
class CancelledException extends \Exception
|
||||
{
|
||||
public function __construct(?\Throwable $previous = null)
|
||||
{
|
||||
parent::__construct("The operation was cancelled", 0, $previous);
|
||||
}
|
||||
}
|
||||
88
vendor/amphp/amp/lib/CombinedCancellationToken.php
vendored
Normal file
88
vendor/amphp/amp/lib/CombinedCancellationToken.php
vendored
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
|
||||
namespace Amp;
|
||||
|
||||
final class CombinedCancellationToken implements CancellationToken
|
||||
{
|
||||
/** @var array{0: CancellationToken, 1: string}[] */
|
||||
private $tokens = [];
|
||||
|
||||
/** @var string */
|
||||
private $nextId = "a";
|
||||
|
||||
/** @var callable[] */
|
||||
private $callbacks = [];
|
||||
|
||||
/** @var CancelledException|null */
|
||||
private $exception;
|
||||
|
||||
public function __construct(CancellationToken ...$tokens)
|
||||
{
|
||||
$thatException = &$this->exception;
|
||||
$thatCallbacks = &$this->callbacks;
|
||||
|
||||
foreach ($tokens as $token) {
|
||||
$id = $token->subscribe(static function (CancelledException $exception) use (&$thatException, &$thatCallbacks) {
|
||||
$thatException = $exception;
|
||||
|
||||
$callbacks = $thatCallbacks;
|
||||
$thatCallbacks = [];
|
||||
|
||||
foreach ($callbacks as $callback) {
|
||||
asyncCall($callback, $thatException);
|
||||
}
|
||||
});
|
||||
|
||||
$this->tokens[] = [$token, $id];
|
||||
}
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
foreach ($this->tokens as list($token, $id)) {
|
||||
/** @var CancellationToken $token */
|
||||
$token->unsubscribe($id);
|
||||
}
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function subscribe(callable $callback): string
|
||||
{
|
||||
$id = $this->nextId;
|
||||
\PHP_VERSION_ID >= 80300 ? $this->nextId = \str_increment($this->nextId) : ++$this->nextId;
|
||||
|
||||
if ($this->exception) {
|
||||
asyncCall($callback, $this->exception);
|
||||
} else {
|
||||
$this->callbacks[$id] = $callback;
|
||||
}
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function unsubscribe(string $id)
|
||||
{
|
||||
unset($this->callbacks[$id]);
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function isRequested(): bool
|
||||
{
|
||||
foreach ($this->tokens as list($token)) {
|
||||
if ($token->isRequested()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function throwIfRequested()
|
||||
{
|
||||
foreach ($this->tokens as list($token)) {
|
||||
$token->throwIfRequested();
|
||||
}
|
||||
}
|
||||
}
|
||||
160
vendor/amphp/amp/lib/Coroutine.php
vendored
Normal file
160
vendor/amphp/amp/lib/Coroutine.php
vendored
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
<?php
|
||||
|
||||
namespace Amp;
|
||||
|
||||
use React\Promise\PromiseInterface as ReactPromise;
|
||||
|
||||
/**
|
||||
* Creates a promise from a generator function yielding promises.
|
||||
*
|
||||
* When a promise is yielded, execution of the generator is interrupted until the promise is resolved. A success
|
||||
* value is sent into the generator, while a failure reason is thrown into the generator. Using a coroutine,
|
||||
* asynchronous code can be written without callbacks and be structured like synchronous code.
|
||||
*
|
||||
* @template-covariant TReturn
|
||||
* @template-implements Promise<TReturn>
|
||||
*/
|
||||
final class Coroutine implements Promise
|
||||
{
|
||||
use Internal\Placeholder;
|
||||
|
||||
/**
|
||||
* Attempts to transform the non-promise yielded from the generator into a promise, otherwise returns an instance
|
||||
* `Amp\Failure` failed with an instance of `Amp\InvalidYieldError`.
|
||||
*
|
||||
* @param mixed $yielded Non-promise yielded from generator.
|
||||
* @param \Generator $generator No type for performance, we already know the type.
|
||||
*
|
||||
* @return Promise
|
||||
*/
|
||||
private static function transform($yielded, $generator): Promise
|
||||
{
|
||||
$exception = null; // initialize here, see https://github.com/vimeo/psalm/issues/2951
|
||||
|
||||
try {
|
||||
if (\is_array($yielded)) {
|
||||
return Promise\all($yielded);
|
||||
}
|
||||
|
||||
if ($yielded instanceof ReactPromise) {
|
||||
return Promise\adapt($yielded);
|
||||
}
|
||||
|
||||
// No match, continue to returning Failure below.
|
||||
} catch (\Throwable $exception) {
|
||||
// Conversion to promise failed, fall-through to returning Failure below.
|
||||
}
|
||||
|
||||
return new Failure(new InvalidYieldError(
|
||||
$generator,
|
||||
\sprintf(
|
||||
"Unexpected yield; Expected an instance of %s or %s or an array of such instances",
|
||||
Promise::class,
|
||||
ReactPromise::class
|
||||
),
|
||||
$exception
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Generator $generator
|
||||
* @psalm-param \Generator<mixed,Promise|ReactPromise|array<array-key,
|
||||
* Promise|ReactPromise>,mixed,Promise<TReturn>|ReactPromise|TReturn> $generator
|
||||
*/
|
||||
public function __construct(\Generator $generator)
|
||||
{
|
||||
try {
|
||||
$yielded = $generator->current();
|
||||
|
||||
if (!$yielded instanceof Promise) {
|
||||
if (!$generator->valid()) {
|
||||
$this->resolve($generator->getReturn());
|
||||
return;
|
||||
}
|
||||
|
||||
$yielded = self::transform($yielded, $generator);
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
$this->fail($exception);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Throwable|null $e Exception to be thrown into the generator.
|
||||
* @param mixed $v Value to be sent into the generator.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @psalm-suppress MissingClosureParamType
|
||||
* @psalm-suppress MissingClosureReturnType
|
||||
*/
|
||||
$onResolve = function (?\Throwable $e, $v) use ($generator, &$onResolve) {
|
||||
/** @var bool $immediate Used to control iterative coroutine continuation. */
|
||||
static $immediate = true;
|
||||
|
||||
/** @var \Throwable|null $exception Promise failure reason when executing next coroutine step, null at all other times. */
|
||||
static $exception;
|
||||
|
||||
/** @var mixed $value Promise success value when executing next coroutine step, null at all other times. */
|
||||
static $value;
|
||||
|
||||
$exception = $e;
|
||||
/** @psalm-suppress MixedAssignment */
|
||||
$value = $v;
|
||||
|
||||
if (!$immediate) {
|
||||
$immediate = true;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
try {
|
||||
do {
|
||||
if ($exception) {
|
||||
// Throw exception at current execution point.
|
||||
$yielded = $generator->throw($exception);
|
||||
} else {
|
||||
// Send the new value and execute to next yield statement.
|
||||
$yielded = $generator->send($value);
|
||||
}
|
||||
|
||||
if (!$yielded instanceof Promise) {
|
||||
if (!$generator->valid()) {
|
||||
$this->resolve($generator->getReturn());
|
||||
$onResolve = null;
|
||||
return;
|
||||
}
|
||||
|
||||
$yielded = self::transform($yielded, $generator);
|
||||
}
|
||||
|
||||
$immediate = false;
|
||||
$yielded->onResolve($onResolve);
|
||||
} while ($immediate);
|
||||
|
||||
$immediate = true;
|
||||
} catch (\Throwable $exception) {
|
||||
$this->fail($exception);
|
||||
$onResolve = null;
|
||||
} finally {
|
||||
$exception = null;
|
||||
$value = null;
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
Loop::defer(static function () use ($e) {
|
||||
throw $e;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
$yielded->onResolve($onResolve);
|
||||
|
||||
unset($generator, $yielded, $onResolve);
|
||||
} catch (\Throwable $e) {
|
||||
Loop::defer(static function () use ($e) {
|
||||
throw $e;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
76
vendor/amphp/amp/lib/Deferred.php
vendored
Normal file
76
vendor/amphp/amp/lib/Deferred.php
vendored
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
|
||||
namespace Amp;
|
||||
|
||||
/**
|
||||
* Deferred is a container for a promise that is resolved using the resolve() and fail() methods of this object.
|
||||
* The contained promise may be accessed using the promise() method. This object should not be part of a public
|
||||
* API, but used internally to create and resolve a promise.
|
||||
*
|
||||
* @template TValue
|
||||
*/
|
||||
final class Deferred
|
||||
{
|
||||
/** @var Promise<TValue> Has public resolve and fail methods. */
|
||||
private $resolver;
|
||||
|
||||
/** @var Promise<TValue> Hides placeholder methods */
|
||||
private $promise;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->resolver = new class implements Promise {
|
||||
use Internal\Placeholder {
|
||||
resolve as public;
|
||||
fail as public;
|
||||
isResolved as public;
|
||||
}
|
||||
};
|
||||
|
||||
$this->promise = new Internal\PrivatePromise($this->resolver);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Promise<TValue>
|
||||
*/
|
||||
public function promise(): Promise
|
||||
{
|
||||
return $this->promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fulfill the promise with the given value.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @psalm-param TValue|Promise<TValue> $value
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function resolve($value = null)
|
||||
{
|
||||
/** @psalm-suppress UndefinedInterfaceMethod */
|
||||
$this->resolver->resolve($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fails the promise the the given reason.
|
||||
*
|
||||
* @param \Throwable $reason
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function fail(\Throwable $reason)
|
||||
{
|
||||
/** @psalm-suppress UndefinedInterfaceMethod */
|
||||
$this->resolver->fail($reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool True if the promise has been resolved.
|
||||
*/
|
||||
public function isResolved(): bool
|
||||
{
|
||||
return $this->resolver->isResolved();
|
||||
}
|
||||
}
|
||||
58
vendor/amphp/amp/lib/Delayed.php
vendored
Normal file
58
vendor/amphp/amp/lib/Delayed.php
vendored
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
namespace Amp;
|
||||
|
||||
/**
|
||||
* Creates a promise that resolves itself with a given value after a number of milliseconds.
|
||||
*
|
||||
* @template-covariant TReturn
|
||||
* @template-implements Promise<TReturn>
|
||||
*/
|
||||
final class Delayed implements Promise
|
||||
{
|
||||
use Internal\Placeholder;
|
||||
|
||||
/** @var string|null Event loop watcher identifier. */
|
||||
private $watcher;
|
||||
|
||||
/**
|
||||
* @param int $time Milliseconds before succeeding the promise.
|
||||
* @param TReturn $value Succeed the promise with this value.
|
||||
*/
|
||||
public function __construct(int $time, $value = null)
|
||||
{
|
||||
$this->watcher = Loop::delay($time, function () use ($value) {
|
||||
$this->watcher = null;
|
||||
$this->resolve($value);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* References the internal watcher in the event loop, keeping the loop running while this promise is pending.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function reference(): self
|
||||
{
|
||||
if ($this->watcher !== null) {
|
||||
Loop::reference($this->watcher);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unreferences the internal watcher in the event loop, allowing the loop to stop while this promise is pending if
|
||||
* no other events are pending in the loop.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function unreference(): self
|
||||
{
|
||||
if ($this->watcher !== null) {
|
||||
Loop::unreference($this->watcher);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
84
vendor/amphp/amp/lib/Emitter.php
vendored
Normal file
84
vendor/amphp/amp/lib/Emitter.php
vendored
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
<?php
|
||||
|
||||
namespace Amp;
|
||||
|
||||
/**
|
||||
* Emitter is a container for an iterator that can emit values using the emit() method and completed using the
|
||||
* complete() and fail() methods of this object. The contained iterator may be accessed using the iterate()
|
||||
* method. This object should not be part of a public API, but used internally to create and emit values to an
|
||||
* iterator.
|
||||
*
|
||||
* @template TValue
|
||||
*/
|
||||
final class Emitter
|
||||
{
|
||||
/** @var Iterator<TValue> Has public emit, complete, and fail methods. */
|
||||
private $emitter;
|
||||
|
||||
/** @var Iterator<TValue> Hides producer methods. */
|
||||
private $iterator;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->emitter = new class implements Iterator {
|
||||
use Internal\Producer {
|
||||
emit as public;
|
||||
complete as public;
|
||||
fail as public;
|
||||
}
|
||||
};
|
||||
|
||||
$this->iterator = new Internal\PrivateIterator($this->emitter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Iterator
|
||||
* @psalm-return Iterator<TValue>
|
||||
*/
|
||||
public function iterate(): Iterator
|
||||
{
|
||||
return $this->iterator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits a value to the iterator.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @psalm-param TValue $value
|
||||
*
|
||||
* @return Promise
|
||||
* @psalm-return Promise<null>
|
||||
* @psalm-suppress MixedInferredReturnType
|
||||
* @psalm-suppress MixedReturnStatement
|
||||
*/
|
||||
public function emit($value): Promise
|
||||
{
|
||||
/** @psalm-suppress UndefinedInterfaceMethod */
|
||||
return $this->emitter->emit($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Completes the iterator.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function complete()
|
||||
{
|
||||
/** @psalm-suppress UndefinedInterfaceMethod */
|
||||
$this->emitter->complete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fails the iterator with the given reason.
|
||||
*
|
||||
* @param \Throwable $reason
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function fail(\Throwable $reason)
|
||||
{
|
||||
/** @psalm-suppress UndefinedInterfaceMethod */
|
||||
$this->emitter->fail($reason);
|
||||
}
|
||||
}
|
||||
52
vendor/amphp/amp/lib/Failure.php
vendored
Normal file
52
vendor/amphp/amp/lib/Failure.php
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
namespace Amp;
|
||||
|
||||
use React\Promise\PromiseInterface as ReactPromise;
|
||||
|
||||
/**
|
||||
* Creates a failed promise using the given exception.
|
||||
*
|
||||
* @template-covariant TValue
|
||||
* @template-implements Promise<TValue>
|
||||
*/
|
||||
final class Failure implements Promise
|
||||
{
|
||||
/** @var \Throwable $exception */
|
||||
private $exception;
|
||||
|
||||
/**
|
||||
* @param \Throwable $exception Rejection reason.
|
||||
*/
|
||||
public function __construct(\Throwable $exception)
|
||||
{
|
||||
$this->exception = $exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function onResolve(callable $onResolved)
|
||||
{
|
||||
try {
|
||||
/** @var mixed $result */
|
||||
$result = $onResolved($this->exception, null);
|
||||
|
||||
if ($result === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($result instanceof \Generator) {
|
||||
$result = new Coroutine($result);
|
||||
}
|
||||
|
||||
if ($result instanceof Promise || $result instanceof ReactPromise) {
|
||||
Promise\rethrow($result);
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
Loop::defer(static function () use ($exception) {
|
||||
throw $exception;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
187
vendor/amphp/amp/lib/Internal/Placeholder.php
vendored
Normal file
187
vendor/amphp/amp/lib/Internal/Placeholder.php
vendored
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
<?php
|
||||
|
||||
namespace Amp\Internal;
|
||||
|
||||
use Amp\Coroutine;
|
||||
use Amp\Failure;
|
||||
use Amp\Loop;
|
||||
use Amp\Promise;
|
||||
use React\Promise\PromiseInterface as ReactPromise;
|
||||
|
||||
/**
|
||||
* Trait used by Promise implementations. Do not use this trait in your code, instead compose your class from one of
|
||||
* the available classes implementing \Amp\Promise.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
trait Placeholder
|
||||
{
|
||||
/** @var bool */
|
||||
private $resolved = false;
|
||||
|
||||
/** @var mixed */
|
||||
private $result;
|
||||
|
||||
/** @var ResolutionQueue|null|callable(\Throwable|null, mixed): (Promise|\React\Promise\PromiseInterface|\Generator<mixed,
|
||||
* Promise|\React\Promise\PromiseInterface|array<array-key, Promise|\React\Promise\PromiseInterface>, mixed,
|
||||
* mixed>|null)|callable(\Throwable|null, mixed): void */
|
||||
private $onResolved;
|
||||
|
||||
/** @var null|array */
|
||||
private $resolutionTrace;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function onResolve(callable $onResolved)
|
||||
{
|
||||
if ($this->resolved) {
|
||||
if ($this->result instanceof Promise) {
|
||||
$this->result->onResolve($onResolved);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
/** @var mixed $result */
|
||||
$result = $onResolved(null, $this->result);
|
||||
|
||||
if ($result === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($result instanceof \Generator) {
|
||||
$result = new Coroutine($result);
|
||||
}
|
||||
|
||||
if ($result instanceof Promise || $result instanceof ReactPromise) {
|
||||
Promise\rethrow($result);
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
Loop::defer(static function () use ($exception) {
|
||||
throw $exception;
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (null === $this->onResolved) {
|
||||
$this->onResolved = $onResolved;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$this->onResolved instanceof ResolutionQueue) {
|
||||
/** @psalm-suppress InternalClass */
|
||||
$this->onResolved = new ResolutionQueue($this->onResolved);
|
||||
}
|
||||
|
||||
/** @psalm-suppress InternalMethod */
|
||||
$this->onResolved->push($onResolved);
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
try {
|
||||
$this->result = null;
|
||||
} catch (\Throwable $e) {
|
||||
Loop::defer(static function () use ($e) {
|
||||
throw $e;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws \Error Thrown if the promise has already been resolved.
|
||||
*/
|
||||
private function resolve($value = null)
|
||||
{
|
||||
if ($this->resolved) {
|
||||
$message = "Promise has already been resolved";
|
||||
|
||||
if (isset($this->resolutionTrace)) {
|
||||
$trace = formatStacktrace($this->resolutionTrace);
|
||||
$message .= ". Previous resolution trace:\n\n{$trace}\n\n";
|
||||
} else {
|
||||
// @codeCoverageIgnoreStart
|
||||
$message .= ", define environment variable AMP_DEBUG or const AMP_DEBUG = true and enable assertions "
|
||||
. "for a stacktrace of the previous resolution.";
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
throw new \Error($message);
|
||||
}
|
||||
|
||||
\assert((function () {
|
||||
$env = \getenv("AMP_DEBUG") ?: "0";
|
||||
if (($env !== "0" && $env !== "false") || (\defined("AMP_DEBUG") && \AMP_DEBUG)) {
|
||||
$trace = \debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||
\array_shift($trace); // remove current closure
|
||||
$this->resolutionTrace = $trace;
|
||||
}
|
||||
|
||||
return true;
|
||||
})());
|
||||
|
||||
if ($value instanceof ReactPromise) {
|
||||
$value = Promise\adapt($value);
|
||||
}
|
||||
|
||||
$this->resolved = true;
|
||||
$this->result = $value;
|
||||
|
||||
if ($this->onResolved === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$onResolved = $this->onResolved;
|
||||
$this->onResolved = null;
|
||||
|
||||
if ($this->result instanceof Promise) {
|
||||
$this->result->onResolve($onResolved);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
/** @var mixed $result */
|
||||
$result = $onResolved(null, $this->result);
|
||||
$onResolved = null; // allow garbage collection of $onResolved, to catch any exceptions from destructors
|
||||
|
||||
if ($result === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($result instanceof \Generator) {
|
||||
$result = new Coroutine($result);
|
||||
}
|
||||
|
||||
if ($result instanceof Promise || $result instanceof ReactPromise) {
|
||||
Promise\rethrow($result);
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
Loop::defer(static function () use ($exception) {
|
||||
throw $exception;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Throwable $reason Failure reason.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function fail(\Throwable $reason)
|
||||
{
|
||||
$this->resolve(new Failure($reason));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool True if the placeholder has been resolved.
|
||||
*/
|
||||
private function isResolved(): bool
|
||||
{
|
||||
return $this->resolved;
|
||||
}
|
||||
}
|
||||
45
vendor/amphp/amp/lib/Internal/PrivateIterator.php
vendored
Normal file
45
vendor/amphp/amp/lib/Internal/PrivateIterator.php
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
namespace Amp\Internal;
|
||||
|
||||
use Amp\Iterator;
|
||||
use Amp\Promise;
|
||||
|
||||
/**
|
||||
* Wraps an Iterator instance that has public methods to emit, complete, and fail into an object that only allows
|
||||
* access to the public API methods.
|
||||
*
|
||||
* @template-covariant TValue
|
||||
* @template-implements Iterator<TValue>
|
||||
*/
|
||||
final class PrivateIterator implements Iterator
|
||||
{
|
||||
/** @var Iterator<TValue> */
|
||||
private $iterator;
|
||||
|
||||
/**
|
||||
* @param Iterator $iterator
|
||||
*
|
||||
* @psalm-param Iterator<TValue> $iterator
|
||||
*/
|
||||
public function __construct(Iterator $iterator)
|
||||
{
|
||||
$this->iterator = $iterator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Promise<bool>
|
||||
*/
|
||||
public function advance(): Promise
|
||||
{
|
||||
return $this->iterator->advance();
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-return TValue
|
||||
*/
|
||||
public function getCurrent()
|
||||
{
|
||||
return $this->iterator->getCurrent();
|
||||
}
|
||||
}
|
||||
25
vendor/amphp/amp/lib/Internal/PrivatePromise.php
vendored
Normal file
25
vendor/amphp/amp/lib/Internal/PrivatePromise.php
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace Amp\Internal;
|
||||
|
||||
use Amp\Promise;
|
||||
|
||||
/**
|
||||
* Wraps a Promise instance that has public methods to resolve and fail the promise into an object that only allows
|
||||
* access to the public API methods.
|
||||
*/
|
||||
final class PrivatePromise implements Promise
|
||||
{
|
||||
/** @var Promise */
|
||||
private $promise;
|
||||
|
||||
public function __construct(Promise $promise)
|
||||
{
|
||||
$this->promise = $promise;
|
||||
}
|
||||
|
||||
public function onResolve(callable $onResolved)
|
||||
{
|
||||
$this->promise->onResolve($onResolved);
|
||||
}
|
||||
}
|
||||
212
vendor/amphp/amp/lib/Internal/Producer.php
vendored
Normal file
212
vendor/amphp/amp/lib/Internal/Producer.php
vendored
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
<?php
|
||||
|
||||
namespace Amp\Internal;
|
||||
|
||||
use Amp\Deferred;
|
||||
use Amp\Failure;
|
||||
use Amp\Promise;
|
||||
use Amp\Success;
|
||||
use React\Promise\PromiseInterface as ReactPromise;
|
||||
|
||||
/**
|
||||
* Trait used by Iterator implementations. Do not use this trait in your code, instead compose your class from one of
|
||||
* the available classes implementing \Amp\Iterator.
|
||||
* Note that it is the responsibility of the user of this trait to ensure that listeners have a chance to listen first
|
||||
* before emitting values.
|
||||
*
|
||||
* @internal
|
||||
* @template-covariant TValue
|
||||
*/
|
||||
trait Producer
|
||||
{
|
||||
/** @var Promise|null */
|
||||
private $complete;
|
||||
|
||||
/** @var mixed[] */
|
||||
private $values = [];
|
||||
|
||||
/** @var Deferred[] */
|
||||
private $backPressure = [];
|
||||
|
||||
/** @var int */
|
||||
private $consumePosition = -1;
|
||||
|
||||
/** @var int */
|
||||
private $emitPosition = -1;
|
||||
|
||||
/** @var Deferred|null */
|
||||
private $waiting;
|
||||
|
||||
/** @var null|array */
|
||||
private $resolutionTrace;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return Promise<bool>
|
||||
*/
|
||||
public function advance(): Promise
|
||||
{
|
||||
if ($this->waiting !== null) {
|
||||
throw new \Error("The prior promise returned must resolve before invoking this method again");
|
||||
}
|
||||
|
||||
unset($this->values[$this->consumePosition]);
|
||||
|
||||
$position = ++$this->consumePosition;
|
||||
|
||||
if (\array_key_exists($position, $this->values)) {
|
||||
\assert(isset($this->backPressure[$position]));
|
||||
$deferred = $this->backPressure[$position];
|
||||
unset($this->backPressure[$position]);
|
||||
$deferred->resolve();
|
||||
|
||||
return new Success(true);
|
||||
}
|
||||
|
||||
if ($this->complete) {
|
||||
return $this->complete;
|
||||
}
|
||||
|
||||
$this->waiting = new Deferred;
|
||||
|
||||
return $this->waiting->promise();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return TValue
|
||||
*/
|
||||
public function getCurrent()
|
||||
{
|
||||
if (empty($this->values) && $this->complete) {
|
||||
throw new \Error("The iterator has completed");
|
||||
}
|
||||
|
||||
if (!\array_key_exists($this->consumePosition, $this->values)) {
|
||||
throw new \Error("Promise returned from advance() must resolve before calling this method");
|
||||
}
|
||||
|
||||
return $this->values[$this->consumePosition];
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits a value from the iterator. The returned promise is resolved once the emitted value has been consumed.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return Promise
|
||||
* @psalm-return Promise<null>
|
||||
*
|
||||
* @throws \Error If the iterator has completed.
|
||||
*/
|
||||
private function emit($value): Promise
|
||||
{
|
||||
if ($this->complete) {
|
||||
throw new \Error("Iterators cannot emit values after calling complete");
|
||||
}
|
||||
|
||||
if ($value instanceof ReactPromise) {
|
||||
$value = Promise\adapt($value);
|
||||
}
|
||||
|
||||
if ($value instanceof Promise) {
|
||||
$deferred = new Deferred;
|
||||
$value->onResolve(function ($e, $v) use ($deferred) {
|
||||
if ($this->complete) {
|
||||
$deferred->fail(
|
||||
new \Error("The iterator was completed before the promise result could be emitted")
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($e) {
|
||||
$this->fail($e);
|
||||
$deferred->fail($e);
|
||||
return;
|
||||
}
|
||||
|
||||
$deferred->resolve($this->emit($v));
|
||||
});
|
||||
|
||||
return $deferred->promise();
|
||||
}
|
||||
|
||||
$position = ++$this->emitPosition;
|
||||
|
||||
$this->values[$position] = $value;
|
||||
|
||||
if ($this->waiting !== null) {
|
||||
$waiting = $this->waiting;
|
||||
$this->waiting = null;
|
||||
$waiting->resolve(true);
|
||||
return new Success; // Consumer was already waiting for a new value, so back-pressure is unnecessary.
|
||||
}
|
||||
|
||||
$this->backPressure[$position] = $pressure = new Deferred;
|
||||
|
||||
return $pressure->promise();
|
||||
}
|
||||
|
||||
/**
|
||||
* Completes the iterator.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws \Error If the iterator has already been completed.
|
||||
*/
|
||||
private function complete()
|
||||
{
|
||||
if ($this->complete) {
|
||||
$message = "Iterator has already been completed";
|
||||
|
||||
if (isset($this->resolutionTrace)) {
|
||||
$trace = formatStacktrace($this->resolutionTrace);
|
||||
$message .= ". Previous completion trace:\n\n{$trace}\n\n";
|
||||
} else {
|
||||
// @codeCoverageIgnoreStart
|
||||
$message .= ", define environment variable AMP_DEBUG or const AMP_DEBUG = true and enable assertions "
|
||||
. "for a stacktrace of the previous resolution.";
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
throw new \Error($message);
|
||||
}
|
||||
|
||||
\assert((function () {
|
||||
$env = \getenv("AMP_DEBUG") ?: "0";
|
||||
if (($env !== "0" && $env !== "false") || (\defined("AMP_DEBUG") && \AMP_DEBUG)) {
|
||||
$trace = \debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||
\array_shift($trace); // remove current closure
|
||||
$this->resolutionTrace = $trace;
|
||||
}
|
||||
|
||||
return true;
|
||||
})());
|
||||
|
||||
$this->complete = new Success(false);
|
||||
|
||||
if ($this->waiting !== null) {
|
||||
$waiting = $this->waiting;
|
||||
$this->waiting = null;
|
||||
$waiting->resolve($this->complete);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Throwable $exception
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function fail(\Throwable $exception)
|
||||
{
|
||||
$this->complete = new Failure($exception);
|
||||
|
||||
if ($this->waiting !== null) {
|
||||
$waiting = $this->waiting;
|
||||
$this->waiting = null;
|
||||
$waiting->resolve($this->complete);
|
||||
}
|
||||
}
|
||||
}
|
||||
90
vendor/amphp/amp/lib/Internal/ResolutionQueue.php
vendored
Normal file
90
vendor/amphp/amp/lib/Internal/ResolutionQueue.php
vendored
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
|
||||
namespace Amp\Internal;
|
||||
|
||||
use Amp\Coroutine;
|
||||
use Amp\Loop;
|
||||
use Amp\Promise;
|
||||
use React\Promise\PromiseInterface as ReactPromise;
|
||||
|
||||
/**
|
||||
* Stores a set of functions to be invoked when a promise is resolved.
|
||||
*
|
||||
* @internal
|
||||
* @psalm-internal Amp\Internal
|
||||
*/
|
||||
class ResolutionQueue
|
||||
{
|
||||
/** @var array<array-key, callable(\Throwable|null, mixed): (Promise|\React\Promise\PromiseInterface|\Generator<mixed,
|
||||
* Promise|\React\Promise\PromiseInterface|array<array-key, Promise|\React\Promise\PromiseInterface>, mixed,
|
||||
* mixed>|null) | callable(\Throwable|null, mixed): void> */
|
||||
private $queue = [];
|
||||
|
||||
/**
|
||||
* @param callable|null $callback Initial callback to add to queue.
|
||||
*
|
||||
* @psalm-param null|callable(\Throwable|null, mixed): (Promise|\React\Promise\PromiseInterface|\Generator<mixed,
|
||||
* Promise|\React\Promise\PromiseInterface|array<array-key, Promise|\React\Promise\PromiseInterface>, mixed,
|
||||
* mixed>|null) | callable(\Throwable|null, mixed): void $callback
|
||||
*/
|
||||
public function __construct(?callable $callback = null)
|
||||
{
|
||||
if ($callback !== null) {
|
||||
$this->push($callback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unrolls instances of self to avoid blowing up the call stack on resolution.
|
||||
*
|
||||
* @param callable $callback
|
||||
*
|
||||
* @psalm-param callable(\Throwable|null, mixed): (Promise|\React\Promise\PromiseInterface|\Generator<mixed,
|
||||
* Promise|\React\Promise\PromiseInterface|array<array-key, Promise|\React\Promise\PromiseInterface>, mixed,
|
||||
* mixed>|null) | callable(\Throwable|null, mixed): void $callback
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function push(callable $callback)
|
||||
{
|
||||
if ($callback instanceof self) {
|
||||
$this->queue = \array_merge($this->queue, $callback->queue);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->queue[] = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls each callback in the queue, passing the provided values to the function.
|
||||
*
|
||||
* @param \Throwable|null $exception
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __invoke($exception, $value)
|
||||
{
|
||||
foreach ($this->queue as $callback) {
|
||||
try {
|
||||
$result = $callback($exception, $value);
|
||||
|
||||
if ($result === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($result instanceof \Generator) {
|
||||
$result = new Coroutine($result);
|
||||
}
|
||||
|
||||
if ($result instanceof Promise || $result instanceof ReactPromise) {
|
||||
Promise\rethrow($result);
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
Loop::defer(static function () use ($exception) {
|
||||
throw $exception;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
117
vendor/amphp/amp/lib/Internal/functions.php
vendored
Normal file
117
vendor/amphp/amp/lib/Internal/functions.php
vendored
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
<?php
|
||||
|
||||
namespace Amp\Internal;
|
||||
|
||||
/**
|
||||
* Formats a stacktrace obtained via `debug_backtrace()`.
|
||||
*
|
||||
* @param array<array{file?: string, line: int, type?: string, class: string, function: string}> $trace Output of
|
||||
* `debug_backtrace()`.
|
||||
*
|
||||
* @return string Formatted stacktrace.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @internal
|
||||
*/
|
||||
function formatStacktrace(array $trace): string
|
||||
{
|
||||
return \implode("\n", \array_map(static function ($e, $i) {
|
||||
$line = "#{$i} ";
|
||||
|
||||
if (isset($e["file"])) {
|
||||
$line .= "{$e['file']}:{$e['line']} ";
|
||||
}
|
||||
|
||||
if (isset($e["type"])) {
|
||||
$line .= $e["class"] . $e["type"];
|
||||
}
|
||||
|
||||
return $line . $e["function"] . "()";
|
||||
}, $trace, \array_keys($trace)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a `TypeError` with a standardized error message.
|
||||
*
|
||||
* @param string[] $expected Expected types.
|
||||
* @param mixed $given Given value.
|
||||
*
|
||||
* @return \TypeError
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
function createTypeError(array $expected, $given): \TypeError
|
||||
{
|
||||
$givenType = \is_object($given) ? \sprintf("instance of %s", \get_class($given)) : \gettype($given);
|
||||
|
||||
if (\count($expected) === 1) {
|
||||
$expectedType = "Expected the following type: " . \array_pop($expected);
|
||||
} else {
|
||||
$expectedType = "Expected one of the following types: " . \implode(", ", $expected);
|
||||
}
|
||||
|
||||
return new \TypeError("{$expectedType}; {$givenType} given");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current time relative to an arbitrary point in time.
|
||||
*
|
||||
* @return int Time in milliseconds.
|
||||
*/
|
||||
function getCurrentTime(): int
|
||||
{
|
||||
/** @var int|null $startTime */
|
||||
static $startTime;
|
||||
/** @var int|null $nextWarning */
|
||||
static $nextWarning;
|
||||
|
||||
if (\PHP_INT_SIZE === 4) {
|
||||
// @codeCoverageIgnoreStart
|
||||
if ($startTime === null) {
|
||||
$startTime = \PHP_VERSION_ID >= 70300 ? \hrtime(false)[0] : \time();
|
||||
$nextWarning = \PHP_INT_MAX - 86400 * 7;
|
||||
}
|
||||
|
||||
if (\PHP_VERSION_ID >= 70300) {
|
||||
list($seconds, $nanoseconds) = \hrtime(false);
|
||||
$seconds -= $startTime;
|
||||
|
||||
if ($seconds >= $nextWarning) {
|
||||
$timeToOverflow = (\PHP_INT_MAX - $seconds * 1000) / 1000;
|
||||
\trigger_error(
|
||||
"getCurrentTime() will overflow in $timeToOverflow seconds, please restart the process before that. " .
|
||||
"You're using a 32 bit version of PHP, so time will overflow about every 24 days. Regular restarts are required.",
|
||||
\E_USER_WARNING
|
||||
);
|
||||
|
||||
/** @psalm-suppress PossiblyNullOperand */
|
||||
$nextWarning += 600; // every 10 minutes
|
||||
}
|
||||
|
||||
return (int) ($seconds * 1000 + $nanoseconds / 1000000);
|
||||
}
|
||||
|
||||
$seconds = \microtime(true) - $startTime;
|
||||
if ($seconds >= $nextWarning) {
|
||||
$timeToOverflow = (\PHP_INT_MAX - $seconds * 1000) / 1000;
|
||||
\trigger_error(
|
||||
"getCurrentTime() will overflow in $timeToOverflow seconds, please restart the process before that. " .
|
||||
"You're using a 32 bit version of PHP, so time will overflow about every 24 days. Regular restarts are required.",
|
||||
\E_USER_WARNING
|
||||
);
|
||||
|
||||
/** @psalm-suppress PossiblyNullOperand */
|
||||
$nextWarning += 600; // every 10 minutes
|
||||
}
|
||||
|
||||
return (int) ($seconds * 1000);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
if (\PHP_VERSION_ID >= 70300) {
|
||||
list($seconds, $nanoseconds) = \hrtime(false);
|
||||
return (int) ($seconds * 1000 + $nanoseconds / 1000000);
|
||||
}
|
||||
|
||||
return (int) (\microtime(true) * 1000);
|
||||
}
|
||||
39
vendor/amphp/amp/lib/InvalidYieldError.php
vendored
Normal file
39
vendor/amphp/amp/lib/InvalidYieldError.php
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
namespace Amp;
|
||||
|
||||
class InvalidYieldError extends \Error
|
||||
{
|
||||
/**
|
||||
* @param \Generator $generator
|
||||
* @param string $prefix
|
||||
* @param \Throwable|null $previous
|
||||
*/
|
||||
public function __construct(\Generator $generator, string $prefix, ?\Throwable $previous = null)
|
||||
{
|
||||
$yielded = $generator->current();
|
||||
$prefix .= \sprintf(
|
||||
"; %s yielded at key %s",
|
||||
\is_object($yielded) ? \get_class($yielded) : \gettype($yielded),
|
||||
\var_export($generator->key(), true)
|
||||
);
|
||||
|
||||
if (!$generator->valid()) {
|
||||
parent::__construct($prefix, 0, $previous);
|
||||
return;
|
||||
}
|
||||
|
||||
$reflGen = new \ReflectionGenerator($generator);
|
||||
$exeGen = $reflGen->getExecutingGenerator();
|
||||
if ($isSubgenerator = ($exeGen !== $generator)) {
|
||||
$reflGen = new \ReflectionGenerator($exeGen);
|
||||
}
|
||||
|
||||
parent::__construct(\sprintf(
|
||||
"%s on line %s in %s",
|
||||
$prefix,
|
||||
$reflGen->getExecutingLine(),
|
||||
$reflGen->getExecutingFile()
|
||||
), 0, $previous);
|
||||
}
|
||||
}
|
||||
34
vendor/amphp/amp/lib/Iterator.php
vendored
Normal file
34
vendor/amphp/amp/lib/Iterator.php
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Amp;
|
||||
|
||||
/**
|
||||
* Defines an asynchronous iterator over a set of values that is designed to be used within a coroutine.
|
||||
*
|
||||
* @template-covariant TValue
|
||||
*/
|
||||
interface Iterator
|
||||
{
|
||||
/**
|
||||
* Succeeds with true if an emitted value is available by calling getCurrent() or false if the iterator has
|
||||
* resolved. If the iterator fails, the returned promise will fail with the same exception.
|
||||
*
|
||||
* @return Promise
|
||||
* @psalm-return Promise<bool>
|
||||
*
|
||||
* @throws \Error If the prior promise returned from this method has not resolved.
|
||||
* @throws \Throwable The exception used to fail the iterator.
|
||||
*/
|
||||
public function advance(): Promise;
|
||||
|
||||
/**
|
||||
* Gets the last emitted value or throws an exception if the iterator has completed.
|
||||
*
|
||||
* @return mixed Value emitted from the iterator.
|
||||
* @psalm-return TValue
|
||||
*
|
||||
* @throws \Error If the iterator has resolved or advance() was not called before calling this method.
|
||||
* @throws \Throwable The exception used to fail the iterator.
|
||||
*/
|
||||
public function getCurrent();
|
||||
}
|
||||
44
vendor/amphp/amp/lib/LazyPromise.php
vendored
Normal file
44
vendor/amphp/amp/lib/LazyPromise.php
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace Amp;
|
||||
|
||||
/**
|
||||
* Creates a promise that calls $promisor only when the result of the promise is requested (i.e. onResolve() is called
|
||||
* on the promise). $promisor can return a promise or any value. If $promisor throws an exception, the promise fails
|
||||
* with that exception. If $promisor returns a Generator, it will be run as a coroutine.
|
||||
*/
|
||||
final class LazyPromise implements Promise
|
||||
{
|
||||
/** @var callable|null */
|
||||
private $promisor;
|
||||
|
||||
/** @var Promise|null */
|
||||
private $promise;
|
||||
|
||||
/**
|
||||
* @param callable $promisor Function which starts an async operation, returning a Promise (or any value).
|
||||
* Generators will be run as a coroutine.
|
||||
*/
|
||||
public function __construct(callable $promisor)
|
||||
{
|
||||
$this->promisor = $promisor;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function onResolve(callable $onResolved)
|
||||
{
|
||||
if ($this->promise === null) {
|
||||
\assert($this->promisor !== null);
|
||||
|
||||
$provider = $this->promisor;
|
||||
$this->promisor = null;
|
||||
$this->promise = call($provider);
|
||||
}
|
||||
|
||||
\assert($this->promise !== null);
|
||||
|
||||
$this->promise->onResolve($onResolved);
|
||||
}
|
||||
}
|
||||
456
vendor/amphp/amp/lib/Loop.php
vendored
Normal file
456
vendor/amphp/amp/lib/Loop.php
vendored
Normal file
|
|
@ -0,0 +1,456 @@
|
|||
<?php
|
||||
|
||||
namespace Amp;
|
||||
|
||||
use Amp\Loop\Driver;
|
||||
use Amp\Loop\DriverFactory;
|
||||
use Amp\Loop\InvalidWatcherError;
|
||||
use Amp\Loop\UnsupportedFeatureException;
|
||||
use Amp\Loop\Watcher;
|
||||
|
||||
/**
|
||||
* Accessor to allow global access to the event loop.
|
||||
*
|
||||
* @see \Amp\Loop\Driver
|
||||
*/
|
||||
final class Loop
|
||||
{
|
||||
/**
|
||||
* @var Driver
|
||||
*/
|
||||
private static $driver;
|
||||
|
||||
/**
|
||||
* Disable construction as this is a static class.
|
||||
*/
|
||||
private function __construct()
|
||||
{
|
||||
// intentionally left blank
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the driver to be used for `Loop::run()`.
|
||||
*
|
||||
* @param Driver $driver
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function set(Driver $driver)
|
||||
{
|
||||
try {
|
||||
self::$driver = new class extends Driver {
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function activate(array $watchers)
|
||||
{
|
||||
throw new \Error("Can't activate watcher during garbage collection.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function dispatch(bool $blocking)
|
||||
{
|
||||
throw new \Error("Can't dispatch during garbage collection.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function deactivate(Watcher $watcher)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public function getHandle()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
\gc_collect_cycles();
|
||||
} finally {
|
||||
self::$driver = $driver;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the event loop and optionally execute a callback within the scope of it.
|
||||
*
|
||||
* The loop MUST continue to run until it is either stopped explicitly, no referenced watchers exist anymore, or an
|
||||
* exception is thrown that cannot be handled. Exceptions that cannot be handled are exceptions thrown from an
|
||||
* error handler or exceptions that would be passed to an error handler but none exists to handle them.
|
||||
*
|
||||
* @param callable|null $callback The callback to execute.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function run(?callable $callback = null)
|
||||
{
|
||||
if ($callback) {
|
||||
self::$driver->defer($callback);
|
||||
}
|
||||
|
||||
self::$driver->run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the event loop.
|
||||
*
|
||||
* When an event loop is stopped, it continues with its current tick and exits the loop afterwards. Multiple calls
|
||||
* to stop MUST be ignored and MUST NOT raise an exception.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function stop()
|
||||
{
|
||||
self::$driver->stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Defer the execution of a callback.
|
||||
*
|
||||
* The deferred callable MUST be executed before any other type of watcher in a tick. Order of enabling MUST be
|
||||
* preserved when executing the callbacks.
|
||||
*
|
||||
* The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called)
|
||||
* right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled.
|
||||
*
|
||||
* @param callable(string $watcherId, mixed $data) $callback The callback to defer. The `$watcherId` will be
|
||||
* invalidated before the callback call.
|
||||
* @param mixed $data Arbitrary data given to the callback function as the `$data` parameter.
|
||||
*
|
||||
* @return string An unique identifier that can be used to cancel, enable or disable the watcher.
|
||||
*/
|
||||
public static function defer(callable $callback, $data = null): string
|
||||
{
|
||||
return self::$driver->defer($callback, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delay the execution of a callback.
|
||||
*
|
||||
* The delay is a minimum and approximate, accuracy is not guaranteed. Order of calls MUST be determined by which
|
||||
* timers expire first, but timers with the same expiration time MAY be executed in any order.
|
||||
*
|
||||
* The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called)
|
||||
* right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled.
|
||||
*
|
||||
* @param int $delay The amount of time, in milliseconds, to delay the execution for.
|
||||
* @param callable(string $watcherId, mixed $data) $callback The callback to delay. The `$watcherId` will be
|
||||
* invalidated before the callback call.
|
||||
* @param mixed $data Arbitrary data given to the callback function as the `$data` parameter.
|
||||
*
|
||||
* @return string An unique identifier that can be used to cancel, enable or disable the watcher.
|
||||
*/
|
||||
public static function delay(int $delay, callable $callback, $data = null): string
|
||||
{
|
||||
return self::$driver->delay($delay, $callback, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Repeatedly execute a callback.
|
||||
*
|
||||
* The interval between executions is a minimum and approximate, accuracy is not guaranteed. Order of calls MUST be
|
||||
* determined by which timers expire first, but timers with the same expiration time MAY be executed in any order.
|
||||
* The first execution is scheduled after the first interval period.
|
||||
*
|
||||
* The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called)
|
||||
* right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled.
|
||||
*
|
||||
* @param int $interval The time interval, in milliseconds, to wait between executions.
|
||||
* @param callable(string $watcherId, mixed $data) $callback The callback to repeat.
|
||||
* @param mixed $data Arbitrary data given to the callback function as the `$data` parameter.
|
||||
*
|
||||
* @return string An unique identifier that can be used to cancel, enable or disable the watcher.
|
||||
*/
|
||||
public static function repeat(int $interval, callable $callback, $data = null): string
|
||||
{
|
||||
return self::$driver->repeat($interval, $callback, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a callback when a stream resource becomes readable or is closed for reading.
|
||||
*
|
||||
* Warning: Closing resources locally, e.g. with `fclose`, might not invoke the callback. Be sure to `cancel` the
|
||||
* watcher when closing the resource locally. Drivers MAY choose to notify the user if there are watchers on invalid
|
||||
* resources, but are not required to, due to the high performance impact. Watchers on closed resources are
|
||||
* therefore undefined behavior.
|
||||
*
|
||||
* Multiple watchers on the same stream MAY be executed in any order.
|
||||
*
|
||||
* The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called)
|
||||
* right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled.
|
||||
*
|
||||
* @param resource $stream The stream to monitor.
|
||||
* @param callable(string $watcherId, resource $stream, mixed $data) $callback The callback to execute.
|
||||
* @param mixed $data Arbitrary data given to the callback function as the `$data` parameter.
|
||||
*
|
||||
* @return string An unique identifier that can be used to cancel, enable or disable the watcher.
|
||||
*/
|
||||
public static function onReadable($stream, callable $callback, $data = null): string
|
||||
{
|
||||
return self::$driver->onReadable($stream, $callback, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a callback when a stream resource becomes writable or is closed for writing.
|
||||
*
|
||||
* Warning: Closing resources locally, e.g. with `fclose`, might not invoke the callback. Be sure to `cancel` the
|
||||
* watcher when closing the resource locally. Drivers MAY choose to notify the user if there are watchers on invalid
|
||||
* resources, but are not required to, due to the high performance impact. Watchers on closed resources are
|
||||
* therefore undefined behavior.
|
||||
*
|
||||
* Multiple watchers on the same stream MAY be executed in any order.
|
||||
*
|
||||
* The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called)
|
||||
* right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled.
|
||||
*
|
||||
* @param resource $stream The stream to monitor.
|
||||
* @param callable(string $watcherId, resource $stream, mixed $data) $callback The callback to execute.
|
||||
* @param mixed $data Arbitrary data given to the callback function as the `$data` parameter.
|
||||
*
|
||||
* @return string An unique identifier that can be used to cancel, enable or disable the watcher.
|
||||
*/
|
||||
public static function onWritable($stream, callable $callback, $data = null): string
|
||||
{
|
||||
return self::$driver->onWritable($stream, $callback, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a callback when a signal is received.
|
||||
*
|
||||
* Warning: Installing the same signal on different instances of this interface is deemed undefined behavior.
|
||||
* Implementations MAY try to detect this, if possible, but are not required to. This is due to technical
|
||||
* limitations of the signals being registered globally per process.
|
||||
*
|
||||
* Multiple watchers on the same signal MAY be executed in any order.
|
||||
*
|
||||
* The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called)
|
||||
* right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled.
|
||||
*
|
||||
* @param int $signo The signal number to monitor.
|
||||
* @param callable(string $watcherId, int $signo, mixed $data) $callback The callback to execute.
|
||||
* @param mixed $data Arbitrary data given to the callback function as the $data parameter.
|
||||
*
|
||||
* @return string An unique identifier that can be used to cancel, enable or disable the watcher.
|
||||
*
|
||||
* @throws UnsupportedFeatureException If signal handling is not supported.
|
||||
*/
|
||||
public static function onSignal(int $signo, callable $callback, $data = null): string
|
||||
{
|
||||
return self::$driver->onSignal($signo, $callback, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable a watcher to be active starting in the next tick.
|
||||
*
|
||||
* Watchers MUST immediately be marked as enabled, but only be activated (i.e. callbacks can be called) right before
|
||||
* the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled.
|
||||
*
|
||||
* @param string $watcherId The watcher identifier.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws InvalidWatcherError If the watcher identifier is invalid.
|
||||
*/
|
||||
public static function enable(string $watcherId)
|
||||
{
|
||||
self::$driver->enable($watcherId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable a watcher immediately.
|
||||
*
|
||||
* A watcher MUST be disabled immediately, e.g. if a defer watcher disables a later defer watcher, the second defer
|
||||
* watcher isn't executed in this tick.
|
||||
*
|
||||
* Disabling a watcher MUST NOT invalidate the watcher. Calling this function MUST NOT fail, even if passed an
|
||||
* invalid watcher.
|
||||
*
|
||||
* @param string $watcherId The watcher identifier.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function disable(string $watcherId)
|
||||
{
|
||||
if (\PHP_VERSION_ID < 70200 && !isset(self::$driver)) {
|
||||
// Prior to PHP 7.2, self::$driver may be unset during destruct.
|
||||
// See https://github.com/amphp/amp/issues/212.
|
||||
return;
|
||||
}
|
||||
|
||||
self::$driver->disable($watcherId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel a watcher.
|
||||
*
|
||||
* This will detatch the event loop from all resources that are associated to the watcher. After this operation the
|
||||
* watcher is permanently invalid. Calling this function MUST NOT fail, even if passed an invalid watcher.
|
||||
*
|
||||
* @param string $watcherId The watcher identifier.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function cancel(string $watcherId)
|
||||
{
|
||||
if (\PHP_VERSION_ID < 70200 && !isset(self::$driver)) {
|
||||
// Prior to PHP 7.2, self::$driver may be unset during destruct.
|
||||
// See https://github.com/amphp/amp/issues/212.
|
||||
return;
|
||||
}
|
||||
|
||||
self::$driver->cancel($watcherId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reference a watcher.
|
||||
*
|
||||
* This will keep the event loop alive whilst the watcher is still being monitored. Watchers have this state by
|
||||
* default.
|
||||
*
|
||||
* @param string $watcherId The watcher identifier.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws InvalidWatcherError If the watcher identifier is invalid.
|
||||
*/
|
||||
public static function reference(string $watcherId)
|
||||
{
|
||||
self::$driver->reference($watcherId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unreference a watcher.
|
||||
*
|
||||
* The event loop should exit the run method when only unreferenced watchers are still being monitored. Watchers
|
||||
* are all referenced by default.
|
||||
*
|
||||
* @param string $watcherId The watcher identifier.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function unreference(string $watcherId)
|
||||
{
|
||||
if (\PHP_VERSION_ID < 70200 && !isset(self::$driver)) {
|
||||
// Prior to PHP 7.2, self::$driver may be unset during destruct.
|
||||
// See https://github.com/amphp/amp/issues/212.
|
||||
return;
|
||||
}
|
||||
|
||||
self::$driver->unreference($watcherId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current loop time in millisecond increments. Note this value does not necessarily correlate to
|
||||
* wall-clock time, rather the value returned is meant to be used in relative comparisons to prior values returned
|
||||
* by this method (intervals, expiration calculations, etc.) and is only updated once per loop tick.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function now(): int
|
||||
{
|
||||
return self::$driver->now();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores information in the loop bound registry.
|
||||
*
|
||||
* Stored information is package private. Packages MUST NOT retrieve the stored state of other packages. Packages
|
||||
* MUST use their namespace as prefix for keys. They may do so by using `SomeClass::class` as key.
|
||||
*
|
||||
* If packages want to expose loop bound state to consumers other than the package, they SHOULD provide a dedicated
|
||||
* interface for that purpose instead of sharing the storage key.
|
||||
*
|
||||
* @param string $key The namespaced storage key.
|
||||
* @param mixed $value The value to be stored.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function setState(string $key, $value)
|
||||
{
|
||||
self::$driver->setState($key, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets information stored bound to the loop.
|
||||
*
|
||||
* Stored information is package private. Packages MUST NOT retrieve the stored state of other packages. Packages
|
||||
* MUST use their namespace as prefix for keys. They may do so by using `SomeClass::class` as key.
|
||||
*
|
||||
* If packages want to expose loop bound state to consumers other than the package, they SHOULD provide a dedicated
|
||||
* interface for that purpose instead of sharing the storage key.
|
||||
*
|
||||
* @param string $key The namespaced storage key.
|
||||
*
|
||||
* @return mixed The previously stored value or `null` if it doesn't exist.
|
||||
*/
|
||||
public static function getState(string $key)
|
||||
{
|
||||
return self::$driver->getState($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a callback to be executed when an error occurs.
|
||||
*
|
||||
* The callback receives the error as the first and only parameter. The return value of the callback gets ignored.
|
||||
* If it can't handle the error, it MUST throw the error. Errors thrown by the callback or during its invocation
|
||||
* MUST be thrown into the `run` loop and stop the driver.
|
||||
*
|
||||
* Subsequent calls to this method will overwrite the previous handler.
|
||||
*
|
||||
* @param callable(\Throwable $error)|null $callback The callback to execute. `null` will clear the
|
||||
* current handler.
|
||||
*
|
||||
* @return callable(\Throwable $error)|null The previous handler, `null` if there was none.
|
||||
*/
|
||||
public static function setErrorHandler(?callable $callback = null)
|
||||
{
|
||||
return self::$driver->setErrorHandler($callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an associative array of information about the event loop driver.
|
||||
*
|
||||
* The returned array MUST contain the following data describing the driver's currently registered watchers:
|
||||
*
|
||||
* [
|
||||
* "defer" => ["enabled" => int, "disabled" => int],
|
||||
* "delay" => ["enabled" => int, "disabled" => int],
|
||||
* "repeat" => ["enabled" => int, "disabled" => int],
|
||||
* "on_readable" => ["enabled" => int, "disabled" => int],
|
||||
* "on_writable" => ["enabled" => int, "disabled" => int],
|
||||
* "on_signal" => ["enabled" => int, "disabled" => int],
|
||||
* "enabled_watchers" => ["referenced" => int, "unreferenced" => int],
|
||||
* "running" => bool
|
||||
* ];
|
||||
*
|
||||
* Implementations MAY optionally add more information in the array but at minimum the above `key => value` format
|
||||
* MUST always be provided.
|
||||
*
|
||||
* @return array Statistics about the loop in the described format.
|
||||
*/
|
||||
public static function getInfo(): array
|
||||
{
|
||||
return self::$driver->getInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the event loop driver that is in scope.
|
||||
*
|
||||
* @return Driver
|
||||
*/
|
||||
public static function get(): Driver
|
||||
{
|
||||
return self::$driver;
|
||||
}
|
||||
}
|
||||
|
||||
// Default factory, don't move this to a file loaded by the composer "files" autoload mechanism, otherwise custom
|
||||
// implementations might have issues setting a default loop, because it's overridden by us then.
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
Loop::set((new DriverFactory)->create());
|
||||
// @codeCoverageIgnoreEnd
|
||||
755
vendor/amphp/amp/lib/Loop/Driver.php
vendored
Normal file
755
vendor/amphp/amp/lib/Loop/Driver.php
vendored
Normal file
|
|
@ -0,0 +1,755 @@
|
|||
<?php
|
||||
|
||||
namespace Amp\Loop;
|
||||
|
||||
use Amp\Coroutine;
|
||||
use Amp\Promise;
|
||||
use React\Promise\PromiseInterface as ReactPromise;
|
||||
use function Amp\Promise\rethrow;
|
||||
|
||||
/**
|
||||
* Event loop driver which implements all basic operations to allow interoperability.
|
||||
*
|
||||
* Watchers (enabled or new watchers) MUST immediately be marked as enabled, but only be activated (i.e. callbacks can
|
||||
* be called) right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled.
|
||||
*
|
||||
* All registered callbacks MUST NOT be called from a file with strict types enabled (`declare(strict_types=1)`).
|
||||
*/
|
||||
abstract class Driver
|
||||
{
|
||||
// Don't use 1e3 / 1e6, they result in a float instead of int
|
||||
const MILLISEC_PER_SEC = 1000;
|
||||
const MICROSEC_PER_SEC = 1000000;
|
||||
|
||||
/** @var string */
|
||||
private $nextId = "a";
|
||||
|
||||
/** @var Watcher[] */
|
||||
private $watchers = [];
|
||||
|
||||
/** @var Watcher[] */
|
||||
private $enableQueue = [];
|
||||
|
||||
/** @var Watcher[] */
|
||||
private $deferQueue = [];
|
||||
|
||||
/** @var Watcher[] */
|
||||
private $nextTickQueue = [];
|
||||
|
||||
/** @var callable(\Throwable):void|null */
|
||||
private $errorHandler;
|
||||
|
||||
/** @var bool */
|
||||
private $running = false;
|
||||
|
||||
/** @var array */
|
||||
private $registry = [];
|
||||
|
||||
/**
|
||||
* Run the event loop.
|
||||
*
|
||||
* One iteration of the loop is called one "tick". A tick covers the following steps:
|
||||
*
|
||||
* 1. Activate watchers created / enabled in the last tick / before `run()`.
|
||||
* 2. Execute all enabled defer watchers.
|
||||
* 3. Execute all due timer, pending signal and actionable stream callbacks, each only once per tick.
|
||||
*
|
||||
* The loop MUST continue to run until it is either stopped explicitly, no referenced watchers exist anymore, or an
|
||||
* exception is thrown that cannot be handled. Exceptions that cannot be handled are exceptions thrown from an
|
||||
* error handler or exceptions that would be passed to an error handler but none exists to handle them.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$this->running = true;
|
||||
|
||||
try {
|
||||
while ($this->running) {
|
||||
if ($this->isEmpty()) {
|
||||
return;
|
||||
}
|
||||
$this->tick();
|
||||
}
|
||||
} finally {
|
||||
$this->stop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool True if no enabled and referenced watchers remain in the loop.
|
||||
*/
|
||||
private function isEmpty(): bool
|
||||
{
|
||||
foreach ($this->watchers as $watcher) {
|
||||
if ($watcher->enabled && $watcher->referenced) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a single tick of the event loop.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function tick()
|
||||
{
|
||||
if (empty($this->deferQueue)) {
|
||||
$this->deferQueue = $this->nextTickQueue;
|
||||
} else {
|
||||
$this->deferQueue = \array_merge($this->deferQueue, $this->nextTickQueue);
|
||||
}
|
||||
$this->nextTickQueue = [];
|
||||
|
||||
$this->activate($this->enableQueue);
|
||||
$this->enableQueue = [];
|
||||
|
||||
foreach ($this->deferQueue as $watcher) {
|
||||
if (!isset($this->deferQueue[$watcher->id])) {
|
||||
continue; // Watcher disabled by another defer watcher.
|
||||
}
|
||||
|
||||
unset($this->watchers[$watcher->id], $this->deferQueue[$watcher->id]);
|
||||
|
||||
try {
|
||||
/** @var mixed $result */
|
||||
$result = ($watcher->callback)($watcher->id, $watcher->data);
|
||||
|
||||
if ($result === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($result instanceof \Generator) {
|
||||
$result = new Coroutine($result);
|
||||
}
|
||||
|
||||
if ($result instanceof Promise || $result instanceof ReactPromise) {
|
||||
rethrow($result);
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
$this->error($exception);
|
||||
}
|
||||
}
|
||||
|
||||
/** @psalm-suppress RedundantCondition */
|
||||
$this->dispatch(empty($this->nextTickQueue) && empty($this->enableQueue) && $this->running && !$this->isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates (enables) all the given watchers.
|
||||
*
|
||||
* @param Watcher[] $watchers
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
abstract protected function activate(array $watchers);
|
||||
|
||||
/**
|
||||
* Dispatches any pending read/write, timer, and signal events.
|
||||
*
|
||||
* @param bool $blocking
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
abstract protected function dispatch(bool $blocking);
|
||||
|
||||
/**
|
||||
* Stop the event loop.
|
||||
*
|
||||
* When an event loop is stopped, it continues with its current tick and exits the loop afterwards. Multiple calls
|
||||
* to stop MUST be ignored and MUST NOT raise an exception.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function stop()
|
||||
{
|
||||
$this->running = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defer the execution of a callback.
|
||||
*
|
||||
* The deferred callable MUST be executed before any other type of watcher in a tick. Order of enabling MUST be
|
||||
* preserved when executing the callbacks.
|
||||
*
|
||||
* The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called)
|
||||
* right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled.
|
||||
*
|
||||
* @param callable (string $watcherId, mixed $data) $callback The callback to defer. The `$watcherId` will be
|
||||
* invalidated before the callback call.
|
||||
* @param mixed $data Arbitrary data given to the callback function as the `$data` parameter.
|
||||
*
|
||||
* @return string An unique identifier that can be used to cancel, enable or disable the watcher.
|
||||
*/
|
||||
public function defer(callable $callback, $data = null): string
|
||||
{
|
||||
/** @psalm-var Watcher<null> $watcher */
|
||||
$watcher = new Watcher;
|
||||
$watcher->type = Watcher::DEFER;
|
||||
$watcher->id = $this->nextId();
|
||||
$watcher->callback = $callback;
|
||||
$watcher->data = $data;
|
||||
|
||||
$this->watchers[$watcher->id] = $watcher;
|
||||
$this->nextTickQueue[$watcher->id] = $watcher;
|
||||
|
||||
return $watcher->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delay the execution of a callback.
|
||||
*
|
||||
* The delay is a minimum and approximate, accuracy is not guaranteed. Order of calls MUST be determined by which
|
||||
* timers expire first, but timers with the same expiration time MAY be executed in any order.
|
||||
*
|
||||
* The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called)
|
||||
* right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled.
|
||||
*
|
||||
* @param int $delay The amount of time, in milliseconds, to delay the execution for.
|
||||
* @param callable (string $watcherId, mixed $data) $callback The callback to delay. The `$watcherId` will be
|
||||
* invalidated before the callback call.
|
||||
* @param mixed $data Arbitrary data given to the callback function as the `$data` parameter.
|
||||
*
|
||||
* @return string An unique identifier that can be used to cancel, enable or disable the watcher.
|
||||
*/
|
||||
public function delay(int $delay, callable $callback, $data = null): string
|
||||
{
|
||||
if ($delay < 0) {
|
||||
throw new \Error("Delay must be greater than or equal to zero");
|
||||
}
|
||||
|
||||
/** @psalm-var Watcher<int> $watcher */
|
||||
$watcher = new Watcher;
|
||||
$watcher->type = Watcher::DELAY;
|
||||
$watcher->id = $this->nextId();
|
||||
$watcher->callback = $callback;
|
||||
$watcher->value = $delay;
|
||||
$watcher->expiration = $this->now() + $delay;
|
||||
$watcher->data = $data;
|
||||
|
||||
$this->watchers[$watcher->id] = $watcher;
|
||||
$this->enableQueue[$watcher->id] = $watcher;
|
||||
|
||||
return $watcher->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Repeatedly execute a callback.
|
||||
*
|
||||
* The interval between executions is a minimum and approximate, accuracy is not guaranteed. Order of calls MUST be
|
||||
* determined by which timers expire first, but timers with the same expiration time MAY be executed in any order.
|
||||
* The first execution is scheduled after the first interval period.
|
||||
*
|
||||
* The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called)
|
||||
* right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled.
|
||||
*
|
||||
* @param int $interval The time interval, in milliseconds, to wait between executions.
|
||||
* @param callable (string $watcherId, mixed $data) $callback The callback to repeat.
|
||||
* @param mixed $data Arbitrary data given to the callback function as the `$data` parameter.
|
||||
*
|
||||
* @return string An unique identifier that can be used to cancel, enable or disable the watcher.
|
||||
*/
|
||||
public function repeat(int $interval, callable $callback, $data = null): string
|
||||
{
|
||||
if ($interval < 0) {
|
||||
throw new \Error("Interval must be greater than or equal to zero");
|
||||
}
|
||||
|
||||
/** @psalm-var Watcher<int> $watcher */
|
||||
$watcher = new Watcher;
|
||||
$watcher->type = Watcher::REPEAT;
|
||||
$watcher->id = $this->nextId();
|
||||
$watcher->callback = $callback;
|
||||
$watcher->value = $interval;
|
||||
$watcher->expiration = $this->now() + $interval;
|
||||
$watcher->data = $data;
|
||||
|
||||
$this->watchers[$watcher->id] = $watcher;
|
||||
$this->enableQueue[$watcher->id] = $watcher;
|
||||
|
||||
return $watcher->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a callback when a stream resource becomes readable or is closed for reading.
|
||||
*
|
||||
* Warning: Closing resources locally, e.g. with `fclose`, might not invoke the callback. Be sure to `cancel` the
|
||||
* watcher when closing the resource locally. Drivers MAY choose to notify the user if there are watchers on invalid
|
||||
* resources, but are not required to, due to the high performance impact. Watchers on closed resources are
|
||||
* therefore undefined behavior.
|
||||
*
|
||||
* Multiple watchers on the same stream MAY be executed in any order.
|
||||
*
|
||||
* The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called)
|
||||
* right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled.
|
||||
*
|
||||
* @param resource $stream The stream to monitor.
|
||||
* @param callable (string $watcherId, resource $stream, mixed $data) $callback The callback to execute.
|
||||
* @param mixed $data Arbitrary data given to the callback function as the `$data` parameter.
|
||||
*
|
||||
* @return string An unique identifier that can be used to cancel, enable or disable the watcher.
|
||||
*/
|
||||
public function onReadable($stream, callable $callback, $data = null): string
|
||||
{
|
||||
/** @psalm-var Watcher<resource> $watcher */
|
||||
$watcher = new Watcher;
|
||||
$watcher->type = Watcher::READABLE;
|
||||
$watcher->id = $this->nextId();
|
||||
$watcher->callback = $callback;
|
||||
$watcher->value = $stream;
|
||||
$watcher->data = $data;
|
||||
|
||||
$this->watchers[$watcher->id] = $watcher;
|
||||
$this->enableQueue[$watcher->id] = $watcher;
|
||||
|
||||
return $watcher->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a callback when a stream resource becomes writable or is closed for writing.
|
||||
*
|
||||
* Warning: Closing resources locally, e.g. with `fclose`, might not invoke the callback. Be sure to `cancel` the
|
||||
* watcher when closing the resource locally. Drivers MAY choose to notify the user if there are watchers on invalid
|
||||
* resources, but are not required to, due to the high performance impact. Watchers on closed resources are
|
||||
* therefore undefined behavior.
|
||||
*
|
||||
* Multiple watchers on the same stream MAY be executed in any order.
|
||||
*
|
||||
* The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called)
|
||||
* right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled.
|
||||
*
|
||||
* @param resource $stream The stream to monitor.
|
||||
* @param callable (string $watcherId, resource $stream, mixed $data) $callback The callback to execute.
|
||||
* @param mixed $data Arbitrary data given to the callback function as the `$data` parameter.
|
||||
*
|
||||
* @return string An unique identifier that can be used to cancel, enable or disable the watcher.
|
||||
*/
|
||||
public function onWritable($stream, callable $callback, $data = null): string
|
||||
{
|
||||
/** @psalm-var Watcher<resource> $watcher */
|
||||
$watcher = new Watcher;
|
||||
$watcher->type = Watcher::WRITABLE;
|
||||
$watcher->id = $this->nextId();
|
||||
$watcher->callback = $callback;
|
||||
$watcher->value = $stream;
|
||||
$watcher->data = $data;
|
||||
|
||||
$this->watchers[$watcher->id] = $watcher;
|
||||
$this->enableQueue[$watcher->id] = $watcher;
|
||||
|
||||
return $watcher->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a callback when a signal is received.
|
||||
*
|
||||
* Warning: Installing the same signal on different instances of this interface is deemed undefined behavior.
|
||||
* Implementations MAY try to detect this, if possible, but are not required to. This is due to technical
|
||||
* limitations of the signals being registered globally per process.
|
||||
*
|
||||
* Multiple watchers on the same signal MAY be executed in any order.
|
||||
*
|
||||
* The created watcher MUST immediately be marked as enabled, but only be activated (i.e. callback can be called)
|
||||
* right before the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled.
|
||||
*
|
||||
* @param int $signo The signal number to monitor.
|
||||
* @param callable (string $watcherId, int $signo, mixed $data) $callback The callback to execute.
|
||||
* @param mixed $data Arbitrary data given to the callback function as the $data parameter.
|
||||
*
|
||||
* @return string An unique identifier that can be used to cancel, enable or disable the watcher.
|
||||
*
|
||||
* @throws UnsupportedFeatureException If signal handling is not supported.
|
||||
*/
|
||||
public function onSignal(int $signo, callable $callback, $data = null): string
|
||||
{
|
||||
/** @psalm-var Watcher<int> $watcher */
|
||||
$watcher = new Watcher;
|
||||
$watcher->type = Watcher::SIGNAL;
|
||||
$watcher->id = $this->nextId();
|
||||
$watcher->callback = $callback;
|
||||
$watcher->value = $signo;
|
||||
$watcher->data = $data;
|
||||
|
||||
$this->watchers[$watcher->id] = $watcher;
|
||||
$this->enableQueue[$watcher->id] = $watcher;
|
||||
|
||||
return $watcher->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable a watcher to be active starting in the next tick.
|
||||
*
|
||||
* Watchers MUST immediately be marked as enabled, but only be activated (i.e. callbacks can be called) right before
|
||||
* the next tick. Callbacks of watchers MUST NOT be called in the tick they were enabled.
|
||||
*
|
||||
* @param string $watcherId The watcher identifier.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws InvalidWatcherError If the watcher identifier is invalid.
|
||||
*/
|
||||
public function enable(string $watcherId)
|
||||
{
|
||||
if (!isset($this->watchers[$watcherId])) {
|
||||
throw new InvalidWatcherError($watcherId, "Cannot enable an invalid watcher identifier: '{$watcherId}'");
|
||||
}
|
||||
|
||||
$watcher = $this->watchers[$watcherId];
|
||||
|
||||
if ($watcher->enabled) {
|
||||
return; // Watcher already enabled.
|
||||
}
|
||||
|
||||
$watcher->enabled = true;
|
||||
|
||||
switch ($watcher->type) {
|
||||
case Watcher::DEFER:
|
||||
$this->nextTickQueue[$watcher->id] = $watcher;
|
||||
break;
|
||||
|
||||
case Watcher::REPEAT:
|
||||
case Watcher::DELAY:
|
||||
\assert(\is_int($watcher->value));
|
||||
|
||||
$watcher->expiration = $this->now() + $watcher->value;
|
||||
$this->enableQueue[$watcher->id] = $watcher;
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->enableQueue[$watcher->id] = $watcher;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel a watcher.
|
||||
*
|
||||
* This will detach the event loop from all resources that are associated to the watcher. After this operation the
|
||||
* watcher is permanently invalid. Calling this function MUST NOT fail, even if passed an invalid watcher.
|
||||
*
|
||||
* @param string $watcherId The watcher identifier.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function cancel(string $watcherId)
|
||||
{
|
||||
$this->disable($watcherId);
|
||||
unset($this->watchers[$watcherId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable a watcher immediately.
|
||||
*
|
||||
* A watcher MUST be disabled immediately, e.g. if a defer watcher disables a later defer watcher, the second defer
|
||||
* watcher isn't executed in this tick.
|
||||
*
|
||||
* Disabling a watcher MUST NOT invalidate the watcher. Calling this function MUST NOT fail, even if passed an
|
||||
* invalid watcher.
|
||||
*
|
||||
* @param string $watcherId The watcher identifier.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function disable(string $watcherId)
|
||||
{
|
||||
if (!isset($this->watchers[$watcherId])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$watcher = $this->watchers[$watcherId];
|
||||
|
||||
if (!$watcher->enabled) {
|
||||
return; // Watcher already disabled.
|
||||
}
|
||||
|
||||
$watcher->enabled = false;
|
||||
$id = $watcher->id;
|
||||
|
||||
switch ($watcher->type) {
|
||||
case Watcher::DEFER:
|
||||
if (isset($this->nextTickQueue[$id])) {
|
||||
// Watcher was only queued to be enabled.
|
||||
unset($this->nextTickQueue[$id]);
|
||||
} else {
|
||||
unset($this->deferQueue[$id]);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (isset($this->enableQueue[$id])) {
|
||||
// Watcher was only queued to be enabled.
|
||||
unset($this->enableQueue[$id]);
|
||||
} else {
|
||||
$this->deactivate($watcher);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deactivates (disables) the given watcher.
|
||||
*
|
||||
* @param Watcher $watcher
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
abstract protected function deactivate(Watcher $watcher);
|
||||
|
||||
/**
|
||||
* Reference a watcher.
|
||||
*
|
||||
* This will keep the event loop alive whilst the watcher is still being monitored. Watchers have this state by
|
||||
* default.
|
||||
*
|
||||
* @param string $watcherId The watcher identifier.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws InvalidWatcherError If the watcher identifier is invalid.
|
||||
*/
|
||||
public function reference(string $watcherId)
|
||||
{
|
||||
if (!isset($this->watchers[$watcherId])) {
|
||||
throw new InvalidWatcherError($watcherId, "Cannot reference an invalid watcher identifier: '{$watcherId}'");
|
||||
}
|
||||
|
||||
$this->watchers[$watcherId]->referenced = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unreference a watcher.
|
||||
*
|
||||
* The event loop should exit the run method when only unreferenced watchers are still being monitored. Watchers
|
||||
* are all referenced by default.
|
||||
*
|
||||
* @param string $watcherId The watcher identifier.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function unreference(string $watcherId)
|
||||
{
|
||||
if (!isset($this->watchers[$watcherId])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->watchers[$watcherId]->referenced = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores information in the loop bound registry.
|
||||
*
|
||||
* Stored information is package private. Packages MUST NOT retrieve the stored state of other packages. Packages
|
||||
* MUST use their namespace as prefix for keys. They may do so by using `SomeClass::class` as key.
|
||||
*
|
||||
* If packages want to expose loop bound state to consumers other than the package, they SHOULD provide a dedicated
|
||||
* interface for that purpose instead of sharing the storage key.
|
||||
*
|
||||
* @param string $key The namespaced storage key.
|
||||
* @param mixed $value The value to be stored.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
final public function setState(string $key, $value)
|
||||
{
|
||||
if ($value === null) {
|
||||
unset($this->registry[$key]);
|
||||
} else {
|
||||
$this->registry[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets information stored bound to the loop.
|
||||
*
|
||||
* Stored information is package private. Packages MUST NOT retrieve the stored state of other packages. Packages
|
||||
* MUST use their namespace as prefix for keys. They may do so by using `SomeClass::class` as key.
|
||||
*
|
||||
* If packages want to expose loop bound state to consumers other than the package, they SHOULD provide a dedicated
|
||||
* interface for that purpose instead of sharing the storage key.
|
||||
*
|
||||
* @param string $key The namespaced storage key.
|
||||
*
|
||||
* @return mixed The previously stored value or `null` if it doesn't exist.
|
||||
*/
|
||||
final public function getState(string $key)
|
||||
{
|
||||
return isset($this->registry[$key]) ? $this->registry[$key] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a callback to be executed when an error occurs.
|
||||
*
|
||||
* The callback receives the error as the first and only parameter. The return value of the callback gets ignored.
|
||||
* If it can't handle the error, it MUST throw the error. Errors thrown by the callback or during its invocation
|
||||
* MUST be thrown into the `run` loop and stop the driver.
|
||||
*
|
||||
* Subsequent calls to this method will overwrite the previous handler.
|
||||
*
|
||||
* @param callable(\Throwable $error):void|null $callback The callback to execute. `null` will clear the
|
||||
* current handler.
|
||||
*
|
||||
* @return callable(\Throwable $error):void|null The previous handler, `null` if there was none.
|
||||
*/
|
||||
public function setErrorHandler(?callable $callback = null)
|
||||
{
|
||||
$previous = $this->errorHandler;
|
||||
$this->errorHandler = $callback;
|
||||
return $previous;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the error handler with the given exception.
|
||||
*
|
||||
* @param \Throwable $exception The exception thrown from a watcher callback.
|
||||
*
|
||||
* @return void
|
||||
* @throws \Throwable If no error handler has been set.
|
||||
*/
|
||||
protected function error(\Throwable $exception)
|
||||
{
|
||||
if ($this->errorHandler === null) {
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
($this->errorHandler)($exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current loop time in millisecond increments. Note this value does not necessarily correlate to
|
||||
* wall-clock time, rather the value returned is meant to be used in relative comparisons to prior values returned
|
||||
* by this method (intervals, expiration calculations, etc.) and is only updated once per loop tick.
|
||||
*
|
||||
* Extending classes should override this function to return a value cached once per loop tick.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function now(): int
|
||||
{
|
||||
return (int) (\microtime(true) * self::MILLISEC_PER_SEC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the underlying loop handle.
|
||||
*
|
||||
* Example: the `uv_loop` resource for `libuv` or the `EvLoop` object for `libev` or `null` for a native driver.
|
||||
*
|
||||
* Note: This function is *not* exposed in the `Loop` class. Users shall access it directly on the respective loop
|
||||
* instance.
|
||||
*
|
||||
* @return null|object|resource The loop handle the event loop operates on. `null` if there is none.
|
||||
*/
|
||||
abstract public function getHandle();
|
||||
|
||||
/**
|
||||
* Returns the same array of data as getInfo().
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function __debugInfo()
|
||||
{
|
||||
// @codeCoverageIgnoreStart
|
||||
return $this->getInfo();
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an associative array of information about the event loop driver.
|
||||
*
|
||||
* The returned array MUST contain the following data describing the driver's currently registered watchers:
|
||||
*
|
||||
* [
|
||||
* "defer" => ["enabled" => int, "disabled" => int],
|
||||
* "delay" => ["enabled" => int, "disabled" => int],
|
||||
* "repeat" => ["enabled" => int, "disabled" => int],
|
||||
* "on_readable" => ["enabled" => int, "disabled" => int],
|
||||
* "on_writable" => ["enabled" => int, "disabled" => int],
|
||||
* "on_signal" => ["enabled" => int, "disabled" => int],
|
||||
* "enabled_watchers" => ["referenced" => int, "unreferenced" => int],
|
||||
* "running" => bool
|
||||
* ];
|
||||
*
|
||||
* Implementations MAY optionally add more information in the array but at minimum the above `key => value` format
|
||||
* MUST always be provided.
|
||||
*
|
||||
* @return array Statistics about the loop in the described format.
|
||||
*/
|
||||
public function getInfo(): array
|
||||
{
|
||||
$watchers = [
|
||||
"referenced" => 0,
|
||||
"unreferenced" => 0,
|
||||
];
|
||||
|
||||
$defer = $delay = $repeat = $onReadable = $onWritable = $onSignal = [
|
||||
"enabled" => 0,
|
||||
"disabled" => 0,
|
||||
];
|
||||
|
||||
foreach ($this->watchers as $watcher) {
|
||||
switch ($watcher->type) {
|
||||
case Watcher::READABLE:
|
||||
$array = &$onReadable;
|
||||
break;
|
||||
case Watcher::WRITABLE:
|
||||
$array = &$onWritable;
|
||||
break;
|
||||
case Watcher::SIGNAL:
|
||||
$array = &$onSignal;
|
||||
break;
|
||||
case Watcher::DEFER:
|
||||
$array = &$defer;
|
||||
break;
|
||||
case Watcher::DELAY:
|
||||
$array = &$delay;
|
||||
break;
|
||||
case Watcher::REPEAT:
|
||||
$array = &$repeat;
|
||||
break;
|
||||
|
||||
default:
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new \Error("Unknown watcher type");
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
if ($watcher->enabled) {
|
||||
++$array["enabled"];
|
||||
|
||||
if ($watcher->referenced) {
|
||||
++$watchers["referenced"];
|
||||
} else {
|
||||
++$watchers["unreferenced"];
|
||||
}
|
||||
} else {
|
||||
++$array["disabled"];
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
"enabled_watchers" => $watchers,
|
||||
"defer" => $defer,
|
||||
"delay" => $delay,
|
||||
"repeat" => $repeat,
|
||||
"on_readable" => $onReadable,
|
||||
"on_writable" => $onWritable,
|
||||
"on_signal" => $onSignal,
|
||||
"running" => (bool) $this->running,
|
||||
];
|
||||
}
|
||||
|
||||
private function nextId(): string
|
||||
{
|
||||
$nextId = $this->nextId;
|
||||
|
||||
if (\PHP_VERSION_ID >= 80300) {
|
||||
$this->nextId = \str_increment($this->nextId);
|
||||
} else {
|
||||
$this->nextId++;
|
||||
}
|
||||
|
||||
return $nextId;
|
||||
}
|
||||
}
|
||||
73
vendor/amphp/amp/lib/Loop/DriverFactory.php
vendored
Normal file
73
vendor/amphp/amp/lib/Loop/DriverFactory.php
vendored
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
|
||||
namespace Amp\Loop;
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
class DriverFactory
|
||||
{
|
||||
/**
|
||||
* Creates a new loop instance and chooses the best available driver.
|
||||
*
|
||||
* @return Driver
|
||||
*
|
||||
* @throws \Error If an invalid class has been specified via AMP_LOOP_DRIVER
|
||||
*/
|
||||
public function create(): Driver
|
||||
{
|
||||
$driver = (function () {
|
||||
if ($driver = $this->createDriverFromEnv()) {
|
||||
return $driver;
|
||||
}
|
||||
|
||||
if (UvDriver::isSupported()) {
|
||||
return new UvDriver;
|
||||
}
|
||||
|
||||
if (EvDriver::isSupported()) {
|
||||
return new EvDriver;
|
||||
}
|
||||
|
||||
if (EventDriver::isSupported()) {
|
||||
return new EventDriver;
|
||||
}
|
||||
|
||||
return new NativeDriver;
|
||||
})();
|
||||
|
||||
if (\getenv("AMP_DEBUG_TRACE_WATCHERS")) {
|
||||
return new TracingDriver($driver);
|
||||
}
|
||||
|
||||
return $driver;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Driver|null
|
||||
*/
|
||||
private function createDriverFromEnv()
|
||||
{
|
||||
$driver = \getenv("AMP_LOOP_DRIVER");
|
||||
|
||||
if (!$driver) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!\class_exists($driver)) {
|
||||
throw new \Error(\sprintf(
|
||||
"Driver '%s' does not exist.",
|
||||
$driver
|
||||
));
|
||||
}
|
||||
|
||||
if (!\is_subclass_of($driver, Driver::class)) {
|
||||
throw new \Error(\sprintf(
|
||||
"Driver '%s' is not a subclass of '%s'.",
|
||||
$driver,
|
||||
Driver::class
|
||||
));
|
||||
}
|
||||
|
||||
return new $driver;
|
||||
}
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
317
vendor/amphp/amp/lib/Loop/EvDriver.php
vendored
Normal file
317
vendor/amphp/amp/lib/Loop/EvDriver.php
vendored
Normal file
|
|
@ -0,0 +1,317 @@
|
|||
<?php /** @noinspection PhpComposerExtensionStubsInspection */
|
||||
|
||||
namespace Amp\Loop;
|
||||
|
||||
use Amp\Coroutine;
|
||||
use Amp\Promise;
|
||||
use React\Promise\PromiseInterface as ReactPromise;
|
||||
use function Amp\Internal\getCurrentTime;
|
||||
use function Amp\Promise\rethrow;
|
||||
|
||||
class EvDriver extends Driver
|
||||
{
|
||||
/** @var \EvSignal[]|null */
|
||||
private static $activeSignals;
|
||||
|
||||
public static function isSupported(): bool
|
||||
{
|
||||
return \extension_loaded("ev");
|
||||
}
|
||||
|
||||
/** @var \EvLoop */
|
||||
private $handle;
|
||||
/** @var \EvWatcher[] */
|
||||
private $events = [];
|
||||
/** @var callable */
|
||||
private $ioCallback;
|
||||
/** @var callable */
|
||||
private $timerCallback;
|
||||
/** @var callable */
|
||||
private $signalCallback;
|
||||
/** @var \EvSignal[] */
|
||||
private $signals = [];
|
||||
/** @var int Internal timestamp for now. */
|
||||
private $now;
|
||||
/** @var int Loop time offset */
|
||||
private $nowOffset;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->handle = new \EvLoop;
|
||||
$this->nowOffset = getCurrentTime();
|
||||
$this->now = \random_int(0, $this->nowOffset);
|
||||
$this->nowOffset -= $this->now;
|
||||
|
||||
if (self::$activeSignals === null) {
|
||||
self::$activeSignals = &$this->signals;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \EvIO $event
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
$this->ioCallback = function (\EvIO $event) {
|
||||
/** @var Watcher $watcher */
|
||||
$watcher = $event->data;
|
||||
|
||||
try {
|
||||
$result = ($watcher->callback)($watcher->id, $watcher->value, $watcher->data);
|
||||
|
||||
if ($result === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($result instanceof \Generator) {
|
||||
$result = new Coroutine($result);
|
||||
}
|
||||
|
||||
if ($result instanceof Promise || $result instanceof ReactPromise) {
|
||||
rethrow($result);
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
$this->error($exception);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param \EvTimer $event
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
$this->timerCallback = function (\EvTimer $event) {
|
||||
/** @var Watcher $watcher */
|
||||
$watcher = $event->data;
|
||||
|
||||
if ($watcher->type & Watcher::DELAY) {
|
||||
$this->cancel($watcher->id);
|
||||
} elseif ($watcher->value === 0) {
|
||||
// Disable and re-enable so it's not executed repeatedly in the same tick
|
||||
// See https://github.com/amphp/amp/issues/131
|
||||
$this->disable($watcher->id);
|
||||
$this->enable($watcher->id);
|
||||
}
|
||||
|
||||
try {
|
||||
$result = ($watcher->callback)($watcher->id, $watcher->data);
|
||||
|
||||
if ($result === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($result instanceof \Generator) {
|
||||
$result = new Coroutine($result);
|
||||
}
|
||||
|
||||
if ($result instanceof Promise || $result instanceof ReactPromise) {
|
||||
rethrow($result);
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
$this->error($exception);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param \EvSignal $event
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
$this->signalCallback = function (\EvSignal $event) {
|
||||
/** @var Watcher $watcher */
|
||||
$watcher = $event->data;
|
||||
|
||||
try {
|
||||
$result = ($watcher->callback)($watcher->id, $watcher->value, $watcher->data);
|
||||
|
||||
if ($result === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($result instanceof \Generator) {
|
||||
$result = new Coroutine($result);
|
||||
}
|
||||
|
||||
if ($result instanceof Promise || $result instanceof ReactPromise) {
|
||||
rethrow($result);
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
$this->error($exception);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function cancel(string $watcherId)
|
||||
{
|
||||
parent::cancel($watcherId);
|
||||
unset($this->events[$watcherId]);
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
foreach ($this->events as $event) {
|
||||
/** @psalm-suppress all */
|
||||
if ($event !== null) { // Events may have been nulled in extension depending on destruct order.
|
||||
$event->stop();
|
||||
}
|
||||
}
|
||||
|
||||
// We need to clear all references to events manually, see
|
||||
// https://bitbucket.org/osmanov/pecl-ev/issues/31/segfault-in-ev_timer_stop
|
||||
$this->events = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$active = self::$activeSignals;
|
||||
|
||||
\assert($active !== null);
|
||||
|
||||
foreach ($active as $event) {
|
||||
$event->stop();
|
||||
}
|
||||
|
||||
self::$activeSignals = &$this->signals;
|
||||
|
||||
foreach ($this->signals as $event) {
|
||||
$event->start();
|
||||
}
|
||||
|
||||
try {
|
||||
parent::run();
|
||||
} finally {
|
||||
foreach ($this->signals as $event) {
|
||||
$event->stop();
|
||||
}
|
||||
|
||||
self::$activeSignals = &$active;
|
||||
|
||||
foreach ($active as $event) {
|
||||
$event->start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function stop()
|
||||
{
|
||||
$this->handle->stop();
|
||||
parent::stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function now(): int
|
||||
{
|
||||
$this->now = getCurrentTime() - $this->nowOffset;
|
||||
|
||||
return $this->now;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getHandle(): \EvLoop
|
||||
{
|
||||
return $this->handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function dispatch(bool $blocking)
|
||||
{
|
||||
$this->handle->run($blocking ? \Ev::RUN_ONCE : \Ev::RUN_ONCE | \Ev::RUN_NOWAIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function activate(array $watchers)
|
||||
{
|
||||
$this->handle->nowUpdate();
|
||||
$now = $this->now();
|
||||
|
||||
foreach ($watchers as $watcher) {
|
||||
if (!isset($this->events[$id = $watcher->id])) {
|
||||
switch ($watcher->type) {
|
||||
case Watcher::READABLE:
|
||||
\assert(\is_resource($watcher->value));
|
||||
|
||||
$this->events[$id] = $this->handle->io($watcher->value, \Ev::READ, $this->ioCallback, $watcher);
|
||||
break;
|
||||
|
||||
case Watcher::WRITABLE:
|
||||
\assert(\is_resource($watcher->value));
|
||||
|
||||
$this->events[$id] = $this->handle->io(
|
||||
$watcher->value,
|
||||
\Ev::WRITE,
|
||||
$this->ioCallback,
|
||||
$watcher
|
||||
);
|
||||
break;
|
||||
|
||||
case Watcher::DELAY:
|
||||
case Watcher::REPEAT:
|
||||
\assert(\is_int($watcher->value));
|
||||
|
||||
$interval = $watcher->value / self::MILLISEC_PER_SEC;
|
||||
$this->events[$id] = $this->handle->timer(
|
||||
\max(0, ($watcher->expiration - $now) / self::MILLISEC_PER_SEC),
|
||||
($watcher->type & Watcher::REPEAT) ? $interval : 0,
|
||||
$this->timerCallback,
|
||||
$watcher
|
||||
);
|
||||
break;
|
||||
|
||||
case Watcher::SIGNAL:
|
||||
\assert(\is_int($watcher->value));
|
||||
|
||||
$this->events[$id] = $this->handle->signal($watcher->value, $this->signalCallback, $watcher);
|
||||
break;
|
||||
|
||||
default:
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new \Error("Unknown watcher type");
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
} else {
|
||||
$this->events[$id]->start();
|
||||
}
|
||||
|
||||
if ($watcher->type === Watcher::SIGNAL) {
|
||||
/** @psalm-suppress PropertyTypeCoercion */
|
||||
$this->signals[$id] = $this->events[$id];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function deactivate(Watcher $watcher)
|
||||
{
|
||||
if (isset($this->events[$id = $watcher->id])) {
|
||||
$this->events[$id]->stop();
|
||||
|
||||
if ($watcher->type === Watcher::SIGNAL) {
|
||||
unset($this->signals[$id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
367
vendor/amphp/amp/lib/Loop/EventDriver.php
vendored
Normal file
367
vendor/amphp/amp/lib/Loop/EventDriver.php
vendored
Normal file
|
|
@ -0,0 +1,367 @@
|
|||
<?php
|
||||
|
||||
namespace Amp\Loop;
|
||||
|
||||
use Amp\Coroutine;
|
||||
use Amp\Promise;
|
||||
use React\Promise\PromiseInterface as ReactPromise;
|
||||
use function Amp\Internal\getCurrentTime;
|
||||
use function Amp\Promise\rethrow;
|
||||
|
||||
class EventDriver extends Driver
|
||||
{
|
||||
/** @var \Event[]|null */
|
||||
private static $activeSignals;
|
||||
|
||||
/** @var \EventBase */
|
||||
private $handle;
|
||||
|
||||
/** @var \Event[] */
|
||||
private $events = [];
|
||||
|
||||
/** @var callable */
|
||||
private $ioCallback;
|
||||
|
||||
/** @var callable */
|
||||
private $timerCallback;
|
||||
|
||||
/** @var callable */
|
||||
private $signalCallback;
|
||||
|
||||
/** @var \Event[] */
|
||||
private $signals = [];
|
||||
|
||||
/** @var int Internal timestamp for now. */
|
||||
private $now;
|
||||
|
||||
/** @var int Loop time offset */
|
||||
private $nowOffset;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$config = new \EventConfig();
|
||||
if (\DIRECTORY_SEPARATOR !== '\\') {
|
||||
$config->requireFeatures(\EventConfig::FEATURE_FDS);
|
||||
}
|
||||
|
||||
$this->handle = new \EventBase($config);
|
||||
$this->nowOffset = getCurrentTime();
|
||||
$this->now = \random_int(0, $this->nowOffset);
|
||||
$this->nowOffset -= $this->now;
|
||||
|
||||
if (self::$activeSignals === null) {
|
||||
self::$activeSignals = &$this->signals;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $resource
|
||||
* @param $what
|
||||
* @param Watcher $watcher
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
$this->ioCallback = function ($resource, $what, Watcher $watcher) {
|
||||
\assert(\is_resource($watcher->value));
|
||||
|
||||
try {
|
||||
$result = ($watcher->callback)($watcher->id, $watcher->value, $watcher->data);
|
||||
|
||||
if ($result === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($result instanceof \Generator) {
|
||||
$result = new Coroutine($result);
|
||||
}
|
||||
|
||||
if ($result instanceof Promise || $result instanceof ReactPromise) {
|
||||
rethrow($result);
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
$this->error($exception);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param $resource
|
||||
* @param $what
|
||||
* @param Watcher $watcher
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
$this->timerCallback = function ($resource, $what, Watcher $watcher) {
|
||||
\assert(\is_int($watcher->value));
|
||||
|
||||
if ($watcher->type & Watcher::DELAY) {
|
||||
$this->cancel($watcher->id);
|
||||
} else {
|
||||
$this->events[$watcher->id]->add($watcher->value / self::MILLISEC_PER_SEC);
|
||||
}
|
||||
|
||||
try {
|
||||
$result = ($watcher->callback)($watcher->id, $watcher->data);
|
||||
|
||||
if ($result === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($result instanceof \Generator) {
|
||||
$result = new Coroutine($result);
|
||||
}
|
||||
|
||||
if ($result instanceof Promise || $result instanceof ReactPromise) {
|
||||
rethrow($result);
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
$this->error($exception);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param $signum
|
||||
* @param $what
|
||||
* @param Watcher $watcher
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
$this->signalCallback = function ($signum, $what, Watcher $watcher) {
|
||||
try {
|
||||
$result = ($watcher->callback)($watcher->id, $watcher->value, $watcher->data);
|
||||
|
||||
if ($result === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($result instanceof \Generator) {
|
||||
$result = new Coroutine($result);
|
||||
}
|
||||
|
||||
if ($result instanceof Promise || $result instanceof ReactPromise) {
|
||||
rethrow($result);
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
$this->error($exception);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function cancel(string $watcherId)
|
||||
{
|
||||
parent::cancel($watcherId);
|
||||
|
||||
if (isset($this->events[$watcherId])) {
|
||||
$this->events[$watcherId]->free();
|
||||
unset($this->events[$watcherId]);
|
||||
}
|
||||
}
|
||||
|
||||
public static function isSupported(): bool
|
||||
{
|
||||
return \extension_loaded("event");
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
// Unset here, otherwise $event->del() in the loop may fail with a warning, because __destruct order isn't defined.
|
||||
// Related https://github.com/amphp/amp/issues/159.
|
||||
$events = $this->events;
|
||||
$this->events = [];
|
||||
|
||||
foreach ($events as $event) {
|
||||
if ($event !== null) { // Events may have been nulled in extension depending on destruct order.
|
||||
$event->free();
|
||||
}
|
||||
}
|
||||
|
||||
// Manually free the loop handle to fully release loop resources.
|
||||
// See https://github.com/amphp/amp/issues/177.
|
||||
if ($this->handle !== null) {
|
||||
$this->handle->free();
|
||||
$this->handle = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$active = self::$activeSignals;
|
||||
|
||||
\assert($active !== null);
|
||||
|
||||
foreach ($active as $event) {
|
||||
$event->del();
|
||||
}
|
||||
|
||||
self::$activeSignals = &$this->signals;
|
||||
|
||||
foreach ($this->signals as $event) {
|
||||
/** @psalm-suppress TooFewArguments https://github.com/JetBrains/phpstorm-stubs/pull/763 */
|
||||
$event->add();
|
||||
}
|
||||
|
||||
try {
|
||||
parent::run();
|
||||
} finally {
|
||||
foreach ($this->signals as $event) {
|
||||
$event->del();
|
||||
}
|
||||
|
||||
self::$activeSignals = &$active;
|
||||
|
||||
foreach ($active as $event) {
|
||||
/** @psalm-suppress TooFewArguments https://github.com/JetBrains/phpstorm-stubs/pull/763 */
|
||||
$event->add();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function stop()
|
||||
{
|
||||
$this->handle->stop();
|
||||
parent::stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function now(): int
|
||||
{
|
||||
$this->now = getCurrentTime() - $this->nowOffset;
|
||||
|
||||
return $this->now;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getHandle(): \EventBase
|
||||
{
|
||||
return $this->handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function dispatch(bool $blocking)
|
||||
{
|
||||
$this->handle->loop($blocking ? \EventBase::LOOP_ONCE : \EventBase::LOOP_ONCE | \EventBase::LOOP_NONBLOCK);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function activate(array $watchers)
|
||||
{
|
||||
$now = $this->now();
|
||||
|
||||
foreach ($watchers as $watcher) {
|
||||
if (!isset($this->events[$id = $watcher->id])) {
|
||||
switch ($watcher->type) {
|
||||
case Watcher::READABLE:
|
||||
\assert(\is_resource($watcher->value));
|
||||
|
||||
$this->events[$id] = new \Event(
|
||||
$this->handle,
|
||||
$watcher->value,
|
||||
\Event::READ | \Event::PERSIST,
|
||||
$this->ioCallback,
|
||||
$watcher
|
||||
);
|
||||
break;
|
||||
|
||||
case Watcher::WRITABLE:
|
||||
\assert(\is_resource($watcher->value));
|
||||
|
||||
$this->events[$id] = new \Event(
|
||||
$this->handle,
|
||||
$watcher->value,
|
||||
\Event::WRITE | \Event::PERSIST,
|
||||
$this->ioCallback,
|
||||
$watcher
|
||||
);
|
||||
break;
|
||||
|
||||
case Watcher::DELAY:
|
||||
case Watcher::REPEAT:
|
||||
\assert(\is_int($watcher->value));
|
||||
|
||||
$this->events[$id] = new \Event(
|
||||
$this->handle,
|
||||
-1,
|
||||
\Event::TIMEOUT,
|
||||
$this->timerCallback,
|
||||
$watcher
|
||||
);
|
||||
break;
|
||||
|
||||
case Watcher::SIGNAL:
|
||||
\assert(\is_int($watcher->value));
|
||||
|
||||
$this->events[$id] = new \Event(
|
||||
$this->handle,
|
||||
$watcher->value,
|
||||
\Event::SIGNAL | \Event::PERSIST,
|
||||
$this->signalCallback,
|
||||
$watcher
|
||||
);
|
||||
break;
|
||||
|
||||
default:
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new \Error("Unknown watcher type");
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
}
|
||||
|
||||
switch ($watcher->type) {
|
||||
case Watcher::DELAY:
|
||||
case Watcher::REPEAT:
|
||||
\assert(\is_int($watcher->value));
|
||||
|
||||
$interval = \max(0, $watcher->expiration - $now);
|
||||
$this->events[$id]->add($interval > 0 ? $interval / self::MILLISEC_PER_SEC : 0);
|
||||
break;
|
||||
|
||||
case Watcher::SIGNAL:
|
||||
$this->signals[$id] = $this->events[$id];
|
||||
// no break
|
||||
|
||||
default:
|
||||
/** @psalm-suppress TooFewArguments https://github.com/JetBrains/phpstorm-stubs/pull/763 */
|
||||
$this->events[$id]->add();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function deactivate(Watcher $watcher)
|
||||
{
|
||||
if (isset($this->events[$id = $watcher->id])) {
|
||||
$this->events[$id]->del();
|
||||
|
||||
if ($watcher->type === Watcher::SIGNAL) {
|
||||
unset($this->signals[$id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
169
vendor/amphp/amp/lib/Loop/Internal/TimerQueue.php
vendored
Normal file
169
vendor/amphp/amp/lib/Loop/Internal/TimerQueue.php
vendored
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
<?php
|
||||
|
||||
namespace Amp\Loop\Internal;
|
||||
|
||||
use Amp\Loop\Watcher;
|
||||
|
||||
/**
|
||||
* Uses a binary tree stored in an array to implement a heap.
|
||||
*/
|
||||
final class TimerQueue
|
||||
{
|
||||
/** @var Watcher[] */
|
||||
private $data = [];
|
||||
|
||||
/** @var int[] */
|
||||
private $pointers = [];
|
||||
|
||||
/**
|
||||
* @param int $node Rebuild the data array from the given node upward.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function heapifyUp(int $node)
|
||||
{
|
||||
$entry = $this->data[$node];
|
||||
while ($node !== 0 && $entry->expiration < $this->data[$parent = ($node - 1) >> 1]->expiration) {
|
||||
$this->swap($node, $parent);
|
||||
$node = $parent;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $node Rebuild the data array from the given node downward.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function heapifyDown(int $node)
|
||||
{
|
||||
$length = \count($this->data);
|
||||
while (($child = ($node << 1) + 1) < $length) {
|
||||
if ($this->data[$child]->expiration < $this->data[$node]->expiration
|
||||
&& ($child + 1 >= $length || $this->data[$child]->expiration < $this->data[$child + 1]->expiration)
|
||||
) {
|
||||
// Left child is less than parent and right child.
|
||||
$swap = $child;
|
||||
} elseif ($child + 1 < $length && $this->data[$child + 1]->expiration < $this->data[$node]->expiration) {
|
||||
// Right child is less than parent and left child.
|
||||
$swap = $child + 1;
|
||||
} else { // Left and right child are greater than parent.
|
||||
break;
|
||||
}
|
||||
|
||||
$this->swap($node, $swap);
|
||||
$node = $swap;
|
||||
}
|
||||
}
|
||||
|
||||
private function swap(int $left, int $right)
|
||||
{
|
||||
$temp = $this->data[$left];
|
||||
|
||||
$this->data[$left] = $this->data[$right];
|
||||
$this->pointers[$this->data[$right]->id] = $left;
|
||||
|
||||
$this->data[$right] = $temp;
|
||||
$this->pointers[$temp->id] = $right;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts the watcher into the queue. Time complexity: O(log(n)).
|
||||
*
|
||||
* @param Watcher $watcher
|
||||
*
|
||||
* @psalm-param Watcher<int> $watcher
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function insert(Watcher $watcher)
|
||||
{
|
||||
\assert($watcher->expiration !== null);
|
||||
\assert(!isset($this->pointers[$watcher->id]));
|
||||
|
||||
$node = \count($this->data);
|
||||
$this->data[$node] = $watcher;
|
||||
$this->pointers[$watcher->id] = $node;
|
||||
|
||||
$this->heapifyUp($node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given watcher from the queue. Time complexity: O(log(n)).
|
||||
*
|
||||
* @param Watcher $watcher
|
||||
*
|
||||
* @psalm-param Watcher<int> $watcher
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function remove(Watcher $watcher)
|
||||
{
|
||||
$id = $watcher->id;
|
||||
|
||||
if (!isset($this->pointers[$id])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->removeAndRebuild($this->pointers[$id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes and returns the Watcher on top of the heap if it has expired, otherwise null is returned.
|
||||
* Time complexity: O(log(n)).
|
||||
*
|
||||
* @param int $now Current loop time.
|
||||
*
|
||||
* @return Watcher|null Expired watcher at the top of the heap or null if the watcher has not expired.
|
||||
*
|
||||
* @psalm-return Watcher<int>|null
|
||||
*/
|
||||
public function extract(int $now)
|
||||
{
|
||||
if (empty($this->data)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$watcher = $this->data[0];
|
||||
|
||||
if ($watcher->expiration > $now) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->removeAndRebuild(0);
|
||||
|
||||
return $watcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the expiration time value at the top of the heap. Time complexity: O(1).
|
||||
*
|
||||
* @return int|null Expiration time of the watcher at the top of the heap or null if the heap is empty.
|
||||
*/
|
||||
public function peek()
|
||||
{
|
||||
return isset($this->data[0]) ? $this->data[0]->expiration : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $node Remove the given node and then rebuild the data array.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function removeAndRebuild(int $node)
|
||||
{
|
||||
$length = \count($this->data) - 1;
|
||||
$id = $this->data[$node]->id;
|
||||
$left = $this->data[$node] = $this->data[$length];
|
||||
$this->pointers[$left->id] = $node;
|
||||
unset($this->data[$length], $this->pointers[$id]);
|
||||
|
||||
if ($node < $length) { // don't need to do anything if we removed the last element
|
||||
$parent = ($node - 1) >> 1;
|
||||
if ($parent >= 0 && $this->data[$node]->expiration < $this->data[$parent]->expiration) {
|
||||
$this->heapifyUp($node);
|
||||
} else {
|
||||
$this->heapifyDown($node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
32
vendor/amphp/amp/lib/Loop/InvalidWatcherError.php
vendored
Normal file
32
vendor/amphp/amp/lib/Loop/InvalidWatcherError.php
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace Amp\Loop;
|
||||
|
||||
/**
|
||||
* MUST be thrown if any operation (except disable() and cancel()) is attempted with an invalid watcher identifier.
|
||||
*
|
||||
* An invalid watcher identifier is any identifier that is not yet emitted by the driver or cancelled by the user.
|
||||
*/
|
||||
class InvalidWatcherError extends \Error
|
||||
{
|
||||
/** @var string */
|
||||
private $watcherId;
|
||||
|
||||
/**
|
||||
* @param string $watcherId The watcher identifier.
|
||||
* @param string $message The exception message.
|
||||
*/
|
||||
public function __construct(string $watcherId, string $message)
|
||||
{
|
||||
$this->watcherId = $watcherId;
|
||||
parent::__construct($message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string The watcher identifier.
|
||||
*/
|
||||
public function getWatcherId()
|
||||
{
|
||||
return $this->watcherId;
|
||||
}
|
||||
}
|
||||
445
vendor/amphp/amp/lib/Loop/NativeDriver.php
vendored
Normal file
445
vendor/amphp/amp/lib/Loop/NativeDriver.php
vendored
Normal file
|
|
@ -0,0 +1,445 @@
|
|||
<?php
|
||||
|
||||
namespace Amp\Loop;
|
||||
|
||||
use Amp\CallableMaker;
|
||||
use Amp\Coroutine;
|
||||
use Amp\Promise;
|
||||
use React\Promise\PromiseInterface as ReactPromise;
|
||||
use function Amp\Internal\getCurrentTime;
|
||||
use function Amp\Promise\rethrow;
|
||||
|
||||
class NativeDriver extends Driver
|
||||
{
|
||||
use CallableMaker;
|
||||
|
||||
/** @var resource[] */
|
||||
private $readStreams = [];
|
||||
|
||||
/** @var Watcher[][] */
|
||||
private $readWatchers = [];
|
||||
|
||||
/** @var resource[] */
|
||||
private $writeStreams = [];
|
||||
|
||||
/** @var Watcher[][] */
|
||||
private $writeWatchers = [];
|
||||
|
||||
/** @var Internal\TimerQueue */
|
||||
private $timerQueue;
|
||||
|
||||
/** @var Watcher[][] */
|
||||
private $signalWatchers = [];
|
||||
|
||||
/** @var int Internal timestamp for now. */
|
||||
private $now;
|
||||
|
||||
/** @var int Loop time offset */
|
||||
private $nowOffset;
|
||||
|
||||
/** @var bool */
|
||||
private $signalHandling;
|
||||
|
||||
/** @var callable */
|
||||
private $streamSelectErrorHandler;
|
||||
|
||||
/** @var bool */
|
||||
private $streamSelectIgnoreResult = false;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->timerQueue = new Internal\TimerQueue;
|
||||
$this->signalHandling = \extension_loaded("pcntl");
|
||||
$this->nowOffset = getCurrentTime();
|
||||
$this->now = \random_int(0, $this->nowOffset);
|
||||
$this->nowOffset -= $this->now;
|
||||
$this->streamSelectErrorHandler = function ($errno, $message) {
|
||||
// Casing changed in PHP 8 from 'unable' to 'Unable'
|
||||
if (\stripos($message, "stream_select(): unable to select [4]: ") === 0) { // EINTR
|
||||
$this->streamSelectIgnoreResult = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (\strpos($message, 'FD_SETSIZE') !== false) {
|
||||
$message = \str_replace(["\r\n", "\n", "\r"], " ", $message);
|
||||
$pattern = '(stream_select\(\): You MUST recompile PHP with a larger value of FD_SETSIZE. It is set to (\d+), but you have descriptors numbered at least as high as (\d+)\.)';
|
||||
|
||||
if (\preg_match($pattern, $message, $match)) {
|
||||
$helpLink = 'https://amphp.org/amp/event-loop/#implementations';
|
||||
|
||||
$message = 'You have reached the limits of stream_select(). It has a FD_SETSIZE of ' . $match[1]
|
||||
. ', but you have file descriptors numbered at least as high as ' . $match[2] . '. '
|
||||
. "You can install one of the extensions listed on {$helpLink} to support a higher number of "
|
||||
. "concurrent file descriptors. If a large number of open file descriptors is unexpected, you "
|
||||
. "might be leaking file descriptors that aren't closed correctly.";
|
||||
}
|
||||
}
|
||||
|
||||
throw new \Exception($message, $errno);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @throws \Amp\Loop\UnsupportedFeatureException If the pcntl extension is not available.
|
||||
*/
|
||||
public function onSignal(int $signo, callable $callback, $data = null): string
|
||||
{
|
||||
if (!$this->signalHandling) {
|
||||
throw new UnsupportedFeatureException("Signal handling requires the pcntl extension");
|
||||
}
|
||||
|
||||
return parent::onSignal($signo, $callback, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function now(): int
|
||||
{
|
||||
$this->now = getCurrentTime() - $this->nowOffset;
|
||||
|
||||
return $this->now;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getHandle()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $blocking
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws \Throwable
|
||||
*/
|
||||
protected function dispatch(bool $blocking)
|
||||
{
|
||||
$this->selectStreams(
|
||||
$this->readStreams,
|
||||
$this->writeStreams,
|
||||
$blocking ? $this->getTimeout() : 0
|
||||
);
|
||||
|
||||
$now = $this->now();
|
||||
|
||||
while ($watcher = $this->timerQueue->extract($now)) {
|
||||
if ($watcher->type & Watcher::REPEAT) {
|
||||
$watcher->enabled = false; // Trick base class into adding to enable queue when calling enable()
|
||||
$this->enable($watcher->id);
|
||||
} else {
|
||||
$this->cancel($watcher->id);
|
||||
}
|
||||
|
||||
try {
|
||||
// Execute the timer.
|
||||
$result = ($watcher->callback)($watcher->id, $watcher->data);
|
||||
|
||||
if ($result === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($result instanceof \Generator) {
|
||||
$result = new Coroutine($result);
|
||||
}
|
||||
|
||||
if ($result instanceof Promise || $result instanceof ReactPromise) {
|
||||
rethrow($result);
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
$this->error($exception);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->signalHandling) {
|
||||
\pcntl_signal_dispatch();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function activate(array $watchers)
|
||||
{
|
||||
foreach ($watchers as $watcher) {
|
||||
switch ($watcher->type) {
|
||||
case Watcher::READABLE:
|
||||
\assert(\is_resource($watcher->value));
|
||||
|
||||
$streamId = (int) $watcher->value;
|
||||
$this->readWatchers[$streamId][$watcher->id] = $watcher;
|
||||
$this->readStreams[$streamId] = $watcher->value;
|
||||
break;
|
||||
|
||||
case Watcher::WRITABLE:
|
||||
\assert(\is_resource($watcher->value));
|
||||
|
||||
$streamId = (int) $watcher->value;
|
||||
$this->writeWatchers[$streamId][$watcher->id] = $watcher;
|
||||
$this->writeStreams[$streamId] = $watcher->value;
|
||||
break;
|
||||
|
||||
case Watcher::DELAY:
|
||||
case Watcher::REPEAT:
|
||||
\assert(\is_int($watcher->value));
|
||||
$this->timerQueue->insert($watcher);
|
||||
break;
|
||||
|
||||
case Watcher::SIGNAL:
|
||||
\assert(\is_int($watcher->value));
|
||||
|
||||
if (!isset($this->signalWatchers[$watcher->value])) {
|
||||
if (!@\pcntl_signal($watcher->value, $this->callableFromInstanceMethod('handleSignal'))) {
|
||||
$message = "Failed to register signal handler";
|
||||
if ($error = \error_get_last()) {
|
||||
$message .= \sprintf("; Errno: %d; %s", $error["type"], $error["message"]);
|
||||
}
|
||||
throw new \Error($message);
|
||||
}
|
||||
}
|
||||
|
||||
$this->signalWatchers[$watcher->value][$watcher->id] = $watcher;
|
||||
break;
|
||||
|
||||
default:
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new \Error("Unknown watcher type");
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function deactivate(Watcher $watcher)
|
||||
{
|
||||
switch ($watcher->type) {
|
||||
case Watcher::READABLE:
|
||||
$streamId = (int) $watcher->value;
|
||||
unset($this->readWatchers[$streamId][$watcher->id]);
|
||||
if (empty($this->readWatchers[$streamId])) {
|
||||
unset($this->readWatchers[$streamId], $this->readStreams[$streamId]);
|
||||
}
|
||||
break;
|
||||
|
||||
case Watcher::WRITABLE:
|
||||
$streamId = (int) $watcher->value;
|
||||
unset($this->writeWatchers[$streamId][$watcher->id]);
|
||||
if (empty($this->writeWatchers[$streamId])) {
|
||||
unset($this->writeWatchers[$streamId], $this->writeStreams[$streamId]);
|
||||
}
|
||||
break;
|
||||
|
||||
case Watcher::DELAY:
|
||||
case Watcher::REPEAT:
|
||||
$this->timerQueue->remove($watcher);
|
||||
break;
|
||||
|
||||
case Watcher::SIGNAL:
|
||||
\assert(\is_int($watcher->value));
|
||||
|
||||
if (isset($this->signalWatchers[$watcher->value])) {
|
||||
unset($this->signalWatchers[$watcher->value][$watcher->id]);
|
||||
|
||||
if (empty($this->signalWatchers[$watcher->value])) {
|
||||
unset($this->signalWatchers[$watcher->value]);
|
||||
@\pcntl_signal($watcher->value, \SIG_DFL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new \Error("Unknown watcher type");
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param resource[] $read
|
||||
* @param resource[] $write
|
||||
* @param int $timeout
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function selectStreams(array $read, array $write, int $timeout)
|
||||
{
|
||||
$timeout /= self::MILLISEC_PER_SEC;
|
||||
|
||||
if (!empty($read) || !empty($write)) { // Use stream_select() if there are any streams in the loop.
|
||||
if ($timeout >= 0) {
|
||||
$seconds = (int) $timeout;
|
||||
$microseconds = (int) (($timeout - $seconds) * self::MICROSEC_PER_SEC);
|
||||
} else {
|
||||
$seconds = null;
|
||||
$microseconds = null;
|
||||
}
|
||||
|
||||
// Failed connection attempts are indicated via except on Windows
|
||||
// @link https://github.com/reactphp/event-loop/blob/8bd064ce23c26c4decf186c2a5a818c9a8209eb0/src/StreamSelectLoop.php#L279-L287
|
||||
// @link https://docs.microsoft.com/de-de/windows/win32/api/winsock2/nf-winsock2-select
|
||||
$except = null;
|
||||
if (\DIRECTORY_SEPARATOR === '\\') {
|
||||
$except = $write;
|
||||
}
|
||||
|
||||
\set_error_handler($this->streamSelectErrorHandler);
|
||||
|
||||
try {
|
||||
$result = \stream_select($read, $write, $except, $seconds, $microseconds);
|
||||
} finally {
|
||||
\restore_error_handler();
|
||||
}
|
||||
|
||||
if ($this->streamSelectIgnoreResult || $result === 0) {
|
||||
$this->streamSelectIgnoreResult = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$result) {
|
||||
$this->error(new \Exception('Unknown error during stream_select'));
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($read as $stream) {
|
||||
$streamId = (int) $stream;
|
||||
if (!isset($this->readWatchers[$streamId])) {
|
||||
continue; // All read watchers disabled.
|
||||
}
|
||||
|
||||
foreach ($this->readWatchers[$streamId] as $watcher) {
|
||||
if (!isset($this->readWatchers[$streamId][$watcher->id])) {
|
||||
continue; // Watcher disabled by another IO watcher.
|
||||
}
|
||||
|
||||
try {
|
||||
$result = ($watcher->callback)($watcher->id, $stream, $watcher->data);
|
||||
|
||||
if ($result === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($result instanceof \Generator) {
|
||||
$result = new Coroutine($result);
|
||||
}
|
||||
|
||||
if ($result instanceof Promise || $result instanceof ReactPromise) {
|
||||
rethrow($result);
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
$this->error($exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
\assert(\is_array($write)); // See https://github.com/vimeo/psalm/issues/3036
|
||||
|
||||
if ($except) {
|
||||
foreach ($except as $key => $socket) {
|
||||
$write[$key] = $socket;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($write as $stream) {
|
||||
$streamId = (int) $stream;
|
||||
if (!isset($this->writeWatchers[$streamId])) {
|
||||
continue; // All write watchers disabled.
|
||||
}
|
||||
|
||||
foreach ($this->writeWatchers[$streamId] as $watcher) {
|
||||
if (!isset($this->writeWatchers[$streamId][$watcher->id])) {
|
||||
continue; // Watcher disabled by another IO watcher.
|
||||
}
|
||||
|
||||
try {
|
||||
$result = ($watcher->callback)($watcher->id, $stream, $watcher->data);
|
||||
|
||||
if ($result === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($result instanceof \Generator) {
|
||||
$result = new Coroutine($result);
|
||||
}
|
||||
|
||||
if ($result instanceof Promise || $result instanceof ReactPromise) {
|
||||
rethrow($result);
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
$this->error($exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($timeout < 0) { // Only signal watchers are enabled, so sleep indefinitely.
|
||||
\usleep(\PHP_INT_MAX);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($timeout > 0) { // Sleep until next timer expires.
|
||||
\usleep((int) ($timeout * self::MICROSEC_PER_SEC));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int Milliseconds until next timer expires or -1 if there are no pending times.
|
||||
*/
|
||||
private function getTimeout(): int
|
||||
{
|
||||
$expiration = $this->timerQueue->peek();
|
||||
|
||||
if ($expiration === null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
$expiration -= getCurrentTime() - $this->nowOffset;
|
||||
|
||||
return $expiration > 0 ? $expiration : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $signo
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function handleSignal(int $signo)
|
||||
{
|
||||
foreach ($this->signalWatchers[$signo] as $watcher) {
|
||||
if (!isset($this->signalWatchers[$signo][$watcher->id])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$result = ($watcher->callback)($watcher->id, $signo, $watcher->data);
|
||||
|
||||
if ($result === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($result instanceof \Generator) {
|
||||
$result = new Coroutine($result);
|
||||
}
|
||||
|
||||
if ($result instanceof Promise || $result instanceof ReactPromise) {
|
||||
rethrow($result);
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
$this->error($exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
251
vendor/amphp/amp/lib/Loop/TracingDriver.php
vendored
Normal file
251
vendor/amphp/amp/lib/Loop/TracingDriver.php
vendored
Normal file
|
|
@ -0,0 +1,251 @@
|
|||
<?php
|
||||
|
||||
namespace Amp\Loop;
|
||||
|
||||
use function Amp\Internal\formatStacktrace;
|
||||
|
||||
final class TracingDriver extends Driver
|
||||
{
|
||||
/** @var Driver */
|
||||
private $driver;
|
||||
/** @var true[] */
|
||||
private $enabledWatchers = [];
|
||||
/** @var true[] */
|
||||
private $unreferencedWatchers = [];
|
||||
/** @var string[] */
|
||||
private $creationTraces = [];
|
||||
/** @var string[] */
|
||||
private $cancelTraces = [];
|
||||
|
||||
public function __construct(Driver $driver)
|
||||
{
|
||||
$this->driver = $driver;
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
$this->driver->run();
|
||||
}
|
||||
|
||||
public function stop()
|
||||
{
|
||||
$this->driver->stop();
|
||||
}
|
||||
|
||||
public function defer(callable $callback, $data = null): string
|
||||
{
|
||||
$id = $this->driver->defer(function (...$args) use ($callback) {
|
||||
$this->cancel($args[0]);
|
||||
return $callback(...$args);
|
||||
}, $data);
|
||||
|
||||
$this->creationTraces[$id] = formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS));
|
||||
$this->enabledWatchers[$id] = true;
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
public function delay(int $delay, callable $callback, $data = null): string
|
||||
{
|
||||
$id = $this->driver->delay($delay, function (...$args) use ($callback) {
|
||||
$this->cancel($args[0]);
|
||||
return $callback(...$args);
|
||||
}, $data);
|
||||
|
||||
$this->creationTraces[$id] = formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS));
|
||||
$this->enabledWatchers[$id] = true;
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
public function repeat(int $interval, callable $callback, $data = null): string
|
||||
{
|
||||
$id = $this->driver->repeat($interval, $callback, $data);
|
||||
|
||||
$this->creationTraces[$id] = formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS));
|
||||
$this->enabledWatchers[$id] = true;
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
public function onReadable($stream, callable $callback, $data = null): string
|
||||
{
|
||||
$id = $this->driver->onReadable($stream, $callback, $data);
|
||||
|
||||
$this->creationTraces[$id] = formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS));
|
||||
$this->enabledWatchers[$id] = true;
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
public function onWritable($stream, callable $callback, $data = null): string
|
||||
{
|
||||
$id = $this->driver->onWritable($stream, $callback, $data);
|
||||
|
||||
$this->creationTraces[$id] = formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS));
|
||||
$this->enabledWatchers[$id] = true;
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
public function onSignal(int $signo, callable $callback, $data = null): string
|
||||
{
|
||||
$id = $this->driver->onSignal($signo, $callback, $data);
|
||||
|
||||
$this->creationTraces[$id] = formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS));
|
||||
$this->enabledWatchers[$id] = true;
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
public function enable(string $watcherId)
|
||||
{
|
||||
try {
|
||||
$this->driver->enable($watcherId);
|
||||
$this->enabledWatchers[$watcherId] = true;
|
||||
} catch (InvalidWatcherError $e) {
|
||||
throw new InvalidWatcherError(
|
||||
$watcherId,
|
||||
$e->getMessage() . "\r\n\r\n" . $this->getTraces($watcherId)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function cancel(string $watcherId)
|
||||
{
|
||||
$this->driver->cancel($watcherId);
|
||||
|
||||
if (!isset($this->cancelTraces[$watcherId])) {
|
||||
$this->cancelTraces[$watcherId] = formatStacktrace(\debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS));
|
||||
}
|
||||
|
||||
unset($this->enabledWatchers[$watcherId], $this->unreferencedWatchers[$watcherId]);
|
||||
}
|
||||
|
||||
public function disable(string $watcherId)
|
||||
{
|
||||
$this->driver->disable($watcherId);
|
||||
unset($this->enabledWatchers[$watcherId]);
|
||||
}
|
||||
|
||||
public function reference(string $watcherId)
|
||||
{
|
||||
try {
|
||||
$this->driver->reference($watcherId);
|
||||
unset($this->unreferencedWatchers[$watcherId]);
|
||||
} catch (InvalidWatcherError $e) {
|
||||
throw new InvalidWatcherError(
|
||||
$watcherId,
|
||||
$e->getMessage() . "\r\n\r\n" . $this->getTraces($watcherId)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function unreference(string $watcherId)
|
||||
{
|
||||
$this->driver->unreference($watcherId);
|
||||
$this->unreferencedWatchers[$watcherId] = true;
|
||||
}
|
||||
|
||||
public function setErrorHandler(?callable $callback = null)
|
||||
{
|
||||
return $this->driver->setErrorHandler($callback);
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function getHandle()
|
||||
{
|
||||
$this->driver->getHandle();
|
||||
}
|
||||
|
||||
public function dump(): string
|
||||
{
|
||||
$dump = "Enabled, referenced watchers keeping the loop running: ";
|
||||
|
||||
foreach ($this->enabledWatchers as $watcher => $_) {
|
||||
if (isset($this->unreferencedWatchers[$watcher])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$dump .= "Watcher ID: " . $watcher . "\r\n";
|
||||
$dump .= $this->getCreationTrace($watcher);
|
||||
$dump .= "\r\n\r\n";
|
||||
}
|
||||
|
||||
return \rtrim($dump);
|
||||
}
|
||||
|
||||
public function getInfo(): array
|
||||
{
|
||||
return $this->driver->getInfo();
|
||||
}
|
||||
|
||||
public function __debugInfo()
|
||||
{
|
||||
return $this->driver->__debugInfo();
|
||||
}
|
||||
|
||||
public function now(): int
|
||||
{
|
||||
return $this->driver->now();
|
||||
}
|
||||
|
||||
protected function error(\Throwable $exception)
|
||||
{
|
||||
$this->driver->error($exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function activate(array $watchers)
|
||||
{
|
||||
// nothing to do in a decorator
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function dispatch(bool $blocking)
|
||||
{
|
||||
// nothing to do in a decorator
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function deactivate(Watcher $watcher)
|
||||
{
|
||||
// nothing to do in a decorator
|
||||
}
|
||||
|
||||
private function getTraces(string $watcherId): string
|
||||
{
|
||||
return "Creation Trace:\r\n" . $this->getCreationTrace($watcherId) . "\r\n\r\n" .
|
||||
"Cancellation Trace:\r\n" . $this->getCancelTrace($watcherId);
|
||||
}
|
||||
|
||||
private function getCreationTrace(string $watcher): string
|
||||
{
|
||||
if (!isset($this->creationTraces[$watcher])) {
|
||||
return 'No creation trace, yet.';
|
||||
}
|
||||
|
||||
return $this->creationTraces[$watcher];
|
||||
}
|
||||
|
||||
private function getCancelTrace(string $watcher): string
|
||||
{
|
||||
if (!isset($this->cancelTraces[$watcher])) {
|
||||
return 'No cancellation trace, yet.';
|
||||
}
|
||||
|
||||
return $this->cancelTraces[$watcher];
|
||||
}
|
||||
}
|
||||
12
vendor/amphp/amp/lib/Loop/UnsupportedFeatureException.php
vendored
Normal file
12
vendor/amphp/amp/lib/Loop/UnsupportedFeatureException.php
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
namespace Amp\Loop;
|
||||
|
||||
/**
|
||||
* MUST be thrown if a feature is not supported by the system.
|
||||
*
|
||||
* This might happen if ext-pcntl is missing and the loop driver doesn't support another way to dispatch signals.
|
||||
*/
|
||||
class UnsupportedFeatureException extends \Exception
|
||||
{
|
||||
}
|
||||
350
vendor/amphp/amp/lib/Loop/UvDriver.php
vendored
Normal file
350
vendor/amphp/amp/lib/Loop/UvDriver.php
vendored
Normal file
|
|
@ -0,0 +1,350 @@
|
|||
<?php
|
||||
|
||||
namespace Amp\Loop;
|
||||
|
||||
use Amp\Coroutine;
|
||||
use Amp\Promise;
|
||||
use React\Promise\PromiseInterface as ReactPromise;
|
||||
use function Amp\Promise\rethrow;
|
||||
|
||||
class UvDriver extends Driver
|
||||
{
|
||||
/** @var resource A uv_loop resource created with uv_loop_new() */
|
||||
private $handle;
|
||||
|
||||
/** @var resource[] */
|
||||
private $events = [];
|
||||
|
||||
/** @var Watcher[][] */
|
||||
private $watchers = [];
|
||||
|
||||
/** @var resource[] */
|
||||
private $streams = [];
|
||||
|
||||
/** @var callable */
|
||||
private $ioCallback;
|
||||
|
||||
/** @var callable */
|
||||
private $timerCallback;
|
||||
|
||||
/** @var callable */
|
||||
private $signalCallback;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->handle = \uv_loop_new();
|
||||
|
||||
/**
|
||||
* @param $event
|
||||
* @param $status
|
||||
* @param $events
|
||||
* @param $resource
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
$this->ioCallback = function ($event, $status, $events, $resource) {
|
||||
$watchers = $this->watchers[(int) $event];
|
||||
|
||||
switch ($status) {
|
||||
case 0: // OK
|
||||
break;
|
||||
|
||||
default: // Invoke the callback on errors, as this matches behavior with other loop back-ends.
|
||||
// Re-enable watcher as libuv disables the watcher on non-zero status.
|
||||
$flags = 0;
|
||||
foreach ($watchers as $watcher) {
|
||||
$flags |= $watcher->enabled ? $watcher->type : 0;
|
||||
}
|
||||
\uv_poll_start($event, $flags, $this->ioCallback);
|
||||
break;
|
||||
}
|
||||
|
||||
foreach ($watchers as $watcher) {
|
||||
// $events is OR'ed with 4 to trigger watcher if no events are indicated (0) or on UV_DISCONNECT (4).
|
||||
// http://docs.libuv.org/en/v1.x/poll.html
|
||||
if (!($watcher->enabled && ($watcher->type & $events || ($events | 4) === 4))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$result = ($watcher->callback)($watcher->id, $resource, $watcher->data);
|
||||
|
||||
if ($result === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($result instanceof \Generator) {
|
||||
$result = new Coroutine($result);
|
||||
}
|
||||
|
||||
if ($result instanceof Promise || $result instanceof ReactPromise) {
|
||||
rethrow($result);
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
$this->error($exception);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param $event
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
$this->timerCallback = function ($event) {
|
||||
$watcher = $this->watchers[(int) $event][0];
|
||||
|
||||
if ($watcher->type & Watcher::DELAY) {
|
||||
unset($this->events[$watcher->id], $this->watchers[(int) $event]); // Avoid call to uv_is_active().
|
||||
$this->cancel($watcher->id); // Remove reference to watcher in parent.
|
||||
} elseif ($watcher->value === 0) {
|
||||
// Disable and re-enable so it's not executed repeatedly in the same tick
|
||||
// See https://github.com/amphp/amp/issues/131
|
||||
$this->disable($watcher->id);
|
||||
$this->enable($watcher->id);
|
||||
}
|
||||
|
||||
try {
|
||||
$result = ($watcher->callback)($watcher->id, $watcher->data);
|
||||
|
||||
if ($result === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($result instanceof \Generator) {
|
||||
$result = new Coroutine($result);
|
||||
}
|
||||
|
||||
if ($result instanceof Promise || $result instanceof ReactPromise) {
|
||||
rethrow($result);
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
$this->error($exception);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param $event
|
||||
* @param $signo
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
$this->signalCallback = function ($event, $signo) {
|
||||
$watcher = $this->watchers[(int) $event][0];
|
||||
|
||||
try {
|
||||
$result = ($watcher->callback)($watcher->id, $signo, $watcher->data);
|
||||
|
||||
if ($result === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($result instanceof \Generator) {
|
||||
$result = new Coroutine($result);
|
||||
}
|
||||
|
||||
if ($result instanceof Promise || $result instanceof ReactPromise) {
|
||||
rethrow($result);
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
$this->error($exception);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function cancel(string $watcherId)
|
||||
{
|
||||
parent::cancel($watcherId);
|
||||
|
||||
if (!isset($this->events[$watcherId])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$event = $this->events[$watcherId];
|
||||
$eventId = (int) $event;
|
||||
|
||||
if (isset($this->watchers[$eventId][0])) { // All except IO watchers.
|
||||
unset($this->watchers[$eventId]);
|
||||
} elseif (isset($this->watchers[$eventId][$watcherId])) {
|
||||
$watcher = $this->watchers[$eventId][$watcherId];
|
||||
unset($this->watchers[$eventId][$watcherId]);
|
||||
|
||||
if (empty($this->watchers[$eventId])) {
|
||||
unset($this->watchers[$eventId], $this->streams[(int) $watcher->value]);
|
||||
}
|
||||
}
|
||||
|
||||
unset($this->events[$watcherId]);
|
||||
}
|
||||
|
||||
public static function isSupported(): bool
|
||||
{
|
||||
return \extension_loaded("uv");
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function now(): int
|
||||
{
|
||||
\uv_update_time($this->handle);
|
||||
|
||||
/** @psalm-suppress TooManyArguments */
|
||||
return \uv_now($this->handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getHandle()
|
||||
{
|
||||
return $this->handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function dispatch(bool $blocking)
|
||||
{
|
||||
/** @psalm-suppress TooManyArguments */
|
||||
\uv_run($this->handle, $blocking ? \UV::RUN_ONCE : \UV::RUN_NOWAIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function activate(array $watchers)
|
||||
{
|
||||
$now = $this->now();
|
||||
|
||||
foreach ($watchers as $watcher) {
|
||||
$id = $watcher->id;
|
||||
|
||||
switch ($watcher->type) {
|
||||
case Watcher::READABLE:
|
||||
case Watcher::WRITABLE:
|
||||
\assert(\is_resource($watcher->value));
|
||||
|
||||
$streamId = (int) $watcher->value;
|
||||
|
||||
if (isset($this->streams[$streamId])) {
|
||||
$event = $this->streams[$streamId];
|
||||
} elseif (isset($this->events[$id])) {
|
||||
$event = $this->streams[$streamId] = $this->events[$id];
|
||||
} else {
|
||||
/** @psalm-suppress UndefinedFunction */
|
||||
$event = $this->streams[$streamId] = \uv_poll_init_socket($this->handle, $watcher->value);
|
||||
}
|
||||
|
||||
$eventId = (int) $event;
|
||||
$this->events[$id] = $event;
|
||||
$this->watchers[$eventId][$id] = $watcher;
|
||||
|
||||
$flags = 0;
|
||||
foreach ($this->watchers[$eventId] as $w) {
|
||||
$flags |= $w->enabled ? $w->type : 0;
|
||||
}
|
||||
\uv_poll_start($event, $flags, $this->ioCallback);
|
||||
break;
|
||||
|
||||
case Watcher::DELAY:
|
||||
case Watcher::REPEAT:
|
||||
\assert(\is_int($watcher->value));
|
||||
|
||||
if (isset($this->events[$id])) {
|
||||
$event = $this->events[$id];
|
||||
} else {
|
||||
$event = $this->events[$id] = \uv_timer_init($this->handle);
|
||||
}
|
||||
|
||||
$this->watchers[(int) $event] = [$watcher];
|
||||
|
||||
\uv_timer_start(
|
||||
$event,
|
||||
\max(0, $watcher->expiration - $now),
|
||||
($watcher->type & Watcher::REPEAT) ? $watcher->value : 0,
|
||||
$this->timerCallback
|
||||
);
|
||||
break;
|
||||
|
||||
case Watcher::SIGNAL:
|
||||
\assert(\is_int($watcher->value));
|
||||
|
||||
if (isset($this->events[$id])) {
|
||||
$event = $this->events[$id];
|
||||
} else {
|
||||
/** @psalm-suppress UndefinedFunction */
|
||||
$event = $this->events[$id] = \uv_signal_init($this->handle);
|
||||
}
|
||||
|
||||
$this->watchers[(int) $event] = [$watcher];
|
||||
|
||||
/** @psalm-suppress UndefinedFunction */
|
||||
\uv_signal_start($event, $this->signalCallback, $watcher->value);
|
||||
break;
|
||||
|
||||
default:
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new \Error("Unknown watcher type");
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function deactivate(Watcher $watcher)
|
||||
{
|
||||
$id = $watcher->id;
|
||||
|
||||
if (!isset($this->events[$id])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$event = $this->events[$id];
|
||||
|
||||
if (!\uv_is_active($event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch ($watcher->type) {
|
||||
case Watcher::READABLE:
|
||||
case Watcher::WRITABLE:
|
||||
$flags = 0;
|
||||
foreach ($this->watchers[(int) $event] as $w) {
|
||||
$flags |= $w->enabled ? $w->type : 0;
|
||||
}
|
||||
|
||||
if ($flags) {
|
||||
\uv_poll_start($event, $flags, $this->ioCallback);
|
||||
} else {
|
||||
\uv_poll_stop($event);
|
||||
}
|
||||
break;
|
||||
|
||||
case Watcher::DELAY:
|
||||
case Watcher::REPEAT:
|
||||
\uv_timer_stop($event);
|
||||
break;
|
||||
|
||||
case Watcher::SIGNAL:
|
||||
\uv_signal_stop($event);
|
||||
break;
|
||||
|
||||
default:
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new \Error("Unknown watcher type");
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
}
|
||||
}
|
||||
57
vendor/amphp/amp/lib/Loop/Watcher.php
vendored
Normal file
57
vendor/amphp/amp/lib/Loop/Watcher.php
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
namespace Amp\Loop;
|
||||
|
||||
use Amp\Struct;
|
||||
|
||||
/**
|
||||
* @template TValue as (int|resource|null)
|
||||
*
|
||||
* @psalm-suppress MissingConstructor
|
||||
*/
|
||||
class Watcher
|
||||
{
|
||||
use Struct;
|
||||
|
||||
const IO = 0b00000011;
|
||||
const READABLE = 0b00000001;
|
||||
const WRITABLE = 0b00000010;
|
||||
const DEFER = 0b00000100;
|
||||
const TIMER = 0b00011000;
|
||||
const DELAY = 0b00001000;
|
||||
const REPEAT = 0b00010000;
|
||||
const SIGNAL = 0b00100000;
|
||||
|
||||
/** @var int */
|
||||
public $type;
|
||||
|
||||
/** @var bool */
|
||||
public $enabled = true;
|
||||
|
||||
/** @var bool */
|
||||
public $referenced = true;
|
||||
|
||||
/** @var string */
|
||||
public $id;
|
||||
|
||||
/** @var callable */
|
||||
public $callback;
|
||||
|
||||
/**
|
||||
* Data provided to the watcher callback.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public $data;
|
||||
|
||||
/**
|
||||
* Watcher-dependent value storage. Stream for IO watchers, signal number for signal watchers, interval for timers.
|
||||
*
|
||||
* @var resource|int|null
|
||||
* @psalm-var TValue
|
||||
*/
|
||||
public $value;
|
||||
|
||||
/** @var int|null */
|
||||
public $expiration;
|
||||
}
|
||||
29
vendor/amphp/amp/lib/MultiReasonException.php
vendored
Normal file
29
vendor/amphp/amp/lib/MultiReasonException.php
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace Amp;
|
||||
|
||||
class MultiReasonException extends \Exception
|
||||
{
|
||||
/** @var \Throwable[] */
|
||||
private $reasons;
|
||||
|
||||
/**
|
||||
* @param \Throwable[] $reasons Array of exceptions rejecting the promise.
|
||||
* @param string|null $message
|
||||
*/
|
||||
public function __construct(array $reasons, ?string $message = null)
|
||||
{
|
||||
parent::__construct($message ?: "Multiple errors encountered; use "
|
||||
. self::class . "::getReasons() to retrieve the array of exceptions thrown");
|
||||
|
||||
$this->reasons = $reasons;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Throwable[]
|
||||
*/
|
||||
public function getReasons(): array
|
||||
{
|
||||
return $this->reasons;
|
||||
}
|
||||
}
|
||||
53
vendor/amphp/amp/lib/NullCancellationToken.php
vendored
Normal file
53
vendor/amphp/amp/lib/NullCancellationToken.php
vendored
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
namespace Amp;
|
||||
|
||||
/**
|
||||
* A NullCancellationToken can be used to avoid conditionals to check whether a token has been provided.
|
||||
*
|
||||
* Instead of writing
|
||||
*
|
||||
* ```php
|
||||
* if ($token) {
|
||||
* $token->throwIfRequested();
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* potentially multiple times, it allows writing
|
||||
*
|
||||
* ```php
|
||||
* $token = $token ?? new NullCancellationToken;
|
||||
*
|
||||
* // ...
|
||||
*
|
||||
* $token->throwIfRequested();
|
||||
* ```
|
||||
*
|
||||
* instead.
|
||||
*/
|
||||
final class NullCancellationToken implements CancellationToken
|
||||
{
|
||||
/** @inheritdoc */
|
||||
public function subscribe(callable $callback): string
|
||||
{
|
||||
return "null-token";
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function unsubscribe(string $id)
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function isRequested(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function throwIfRequested()
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
}
|
||||
43
vendor/amphp/amp/lib/Producer.php
vendored
Normal file
43
vendor/amphp/amp/lib/Producer.php
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
namespace Amp;
|
||||
|
||||
/**
|
||||
* @template-covariant TValue
|
||||
* @template-implements Iterator<TValue>
|
||||
*/
|
||||
final class Producer implements Iterator
|
||||
{
|
||||
/**
|
||||
* @use Internal\Producer<TValue>
|
||||
*/
|
||||
use CallableMaker, Internal\Producer;
|
||||
|
||||
/**
|
||||
* @param callable(callable(TValue):Promise):\Generator $producer
|
||||
*
|
||||
* @throws \Error Thrown if the callable does not return a Generator.
|
||||
*/
|
||||
public function __construct(callable $producer)
|
||||
{
|
||||
$result = $producer($this->callableFromInstanceMethod("emit"));
|
||||
|
||||
if (!$result instanceof \Generator) {
|
||||
throw new \Error("The callable did not return a Generator");
|
||||
}
|
||||
|
||||
$coroutine = new Coroutine($result);
|
||||
$coroutine->onResolve(function ($exception) {
|
||||
if ($this->complete) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($exception) {
|
||||
$this->fail($exception);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->complete();
|
||||
});
|
||||
}
|
||||
}
|
||||
37
vendor/amphp/amp/lib/Promise.php
vendored
Normal file
37
vendor/amphp/amp/lib/Promise.php
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace Amp;
|
||||
|
||||
/**
|
||||
* Representation of the future value of an asynchronous operation.
|
||||
*
|
||||
* @template-covariant TValue
|
||||
* @psalm-yield TValue
|
||||
*/
|
||||
interface Promise
|
||||
{
|
||||
/**
|
||||
* Registers a callback to be invoked when the promise is resolved.
|
||||
*
|
||||
* If this method is called multiple times, additional handlers will be registered instead of replacing any already
|
||||
* existing handlers.
|
||||
*
|
||||
* If the promise is already resolved, the callback MUST be executed immediately.
|
||||
*
|
||||
* Exceptions MUST NOT be thrown from this method. Any exceptions thrown from invoked callbacks MUST be
|
||||
* forwarded to the event-loop error handler.
|
||||
*
|
||||
* Note: You shouldn't implement this interface yourself. Instead, provide a method that returns a promise for the
|
||||
* operation you're implementing. Objects other than pure placeholders implementing it are a very bad idea.
|
||||
*
|
||||
* @param callable $onResolved The first argument shall be `null` on success, while the second shall be `null` on
|
||||
* failure.
|
||||
*
|
||||
* @psalm-param callable(\Throwable|null, mixed): (Promise|\React\Promise\PromiseInterface|\Generator<mixed,
|
||||
* Promise|\React\Promise\PromiseInterface|array<array-key, Promise|\React\Promise\PromiseInterface>, mixed,
|
||||
* mixed>|null) | callable(\Throwable|null, mixed): void $onResolved
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function onResolve(callable $onResolved);
|
||||
}
|
||||
78
vendor/amphp/amp/lib/Struct.php
vendored
Normal file
78
vendor/amphp/amp/lib/Struct.php
vendored
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
|
||||
namespace Amp;
|
||||
|
||||
/**
|
||||
* A "safe" struct trait for public property aggregators.
|
||||
*
|
||||
* This trait is intended to make using public properties a little safer by throwing when
|
||||
* nonexistent property names are read or written.
|
||||
*/
|
||||
trait Struct
|
||||
{
|
||||
/**
|
||||
* The minimum percentage [0-100] at which to recommend a similar property
|
||||
* name when generating error messages.
|
||||
*/
|
||||
private $__propertySuggestThreshold = 70;
|
||||
|
||||
/**
|
||||
* @param string $property
|
||||
*
|
||||
* @psalm-return no-return
|
||||
*/
|
||||
public function __get(string $property)
|
||||
{
|
||||
throw new \Error(
|
||||
$this->generateStructPropertyError($property)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $property
|
||||
* @param mixed $value
|
||||
*
|
||||
* @psalm-return no-return
|
||||
*/
|
||||
public function __set(string $property, $value)
|
||||
{
|
||||
throw new \Error(
|
||||
$this->generateStructPropertyError($property)
|
||||
);
|
||||
}
|
||||
|
||||
private function generateStructPropertyError(string $property): string
|
||||
{
|
||||
$suggestion = $this->suggestPropertyName($property);
|
||||
$suggestStr = ($suggestion == "") ? "" : " ... did you mean \"{$suggestion}?\"";
|
||||
|
||||
return \sprintf(
|
||||
"%s property \"%s\" does not exist%s",
|
||||
\str_replace("\0", "@", \get_class($this)), // Handle anonymous class names.
|
||||
$property,
|
||||
$suggestStr
|
||||
);
|
||||
}
|
||||
|
||||
private function suggestPropertyName(string $badProperty): string
|
||||
{
|
||||
$badProperty = \strtolower($badProperty);
|
||||
$bestMatch = "";
|
||||
$bestMatchPercentage = 0;
|
||||
|
||||
/** @psalm-suppress RawObjectIteration */
|
||||
foreach ($this as $property => $value) {
|
||||
// Never suggest properties that begin with an underscore
|
||||
if ($property[0] === "_") {
|
||||
continue;
|
||||
}
|
||||
\similar_text($badProperty, \strtolower($property), $byRefPercentage);
|
||||
if ($byRefPercentage > $bestMatchPercentage) {
|
||||
$bestMatchPercentage = $byRefPercentage;
|
||||
$bestMatch = $property;
|
||||
}
|
||||
}
|
||||
|
||||
return ($bestMatchPercentage >= $this->__propertySuggestThreshold) ? $bestMatch : "";
|
||||
}
|
||||
}
|
||||
60
vendor/amphp/amp/lib/Success.php
vendored
Normal file
60
vendor/amphp/amp/lib/Success.php
vendored
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
<?php
|
||||
|
||||
namespace Amp;
|
||||
|
||||
use React\Promise\PromiseInterface as ReactPromise;
|
||||
|
||||
/**
|
||||
* Creates a successful promise using the given value (which can be any value except an object implementing
|
||||
* `Amp\Promise` or `React\Promise\PromiseInterface`).
|
||||
*
|
||||
* @template-covariant TValue
|
||||
* @template-implements Promise<TValue>
|
||||
*/
|
||||
final class Success implements Promise
|
||||
{
|
||||
/** @var mixed */
|
||||
private $value;
|
||||
|
||||
/**
|
||||
* @param mixed $value Anything other than a Promise object.
|
||||
*
|
||||
* @psalm-param TValue $value
|
||||
*
|
||||
* @throws \Error If a promise is given as the value.
|
||||
*/
|
||||
public function __construct($value = null)
|
||||
{
|
||||
if ($value instanceof Promise || $value instanceof ReactPromise) {
|
||||
throw new \Error("Cannot use a promise as success value");
|
||||
}
|
||||
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function onResolve(callable $onResolved)
|
||||
{
|
||||
try {
|
||||
$result = $onResolved(null, $this->value);
|
||||
|
||||
if ($result === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($result instanceof \Generator) {
|
||||
$result = new Coroutine($result);
|
||||
}
|
||||
|
||||
if ($result instanceof Promise || $result instanceof ReactPromise) {
|
||||
Promise\rethrow($result);
|
||||
}
|
||||
} catch (\Throwable $exception) {
|
||||
Loop::defer(static function () use ($exception) {
|
||||
throw $exception;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
75
vendor/amphp/amp/lib/TimeoutCancellationToken.php
vendored
Normal file
75
vendor/amphp/amp/lib/TimeoutCancellationToken.php
vendored
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
namespace Amp;
|
||||
|
||||
use function Amp\Internal\formatStacktrace;
|
||||
|
||||
/**
|
||||
* A TimeoutCancellationToken automatically requests cancellation after the timeout has elapsed.
|
||||
*/
|
||||
final class TimeoutCancellationToken implements CancellationToken
|
||||
{
|
||||
/** @var string */
|
||||
private $watcher;
|
||||
|
||||
/** @var CancellationToken */
|
||||
private $token;
|
||||
|
||||
/**
|
||||
* @param int $timeout Milliseconds until cancellation is requested.
|
||||
* @param string $message Message for TimeoutException. Default is "Operation timed out".
|
||||
*/
|
||||
public function __construct(int $timeout, string $message = "Operation timed out")
|
||||
{
|
||||
$source = new CancellationTokenSource;
|
||||
$this->token = $source->getToken();
|
||||
|
||||
$trace = \debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||
$this->watcher = Loop::delay($timeout, static function () use ($source, $message, $trace) {
|
||||
$trace = formatStacktrace($trace);
|
||||
$source->cancel(new TimeoutException("$message\r\nTimeoutCancellationToken was created here:\r\n$trace"));
|
||||
});
|
||||
|
||||
Loop::unreference($this->watcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels the delay watcher.
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
Loop::cancel($this->watcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function subscribe(callable $callback): string
|
||||
{
|
||||
return $this->token->subscribe($callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function unsubscribe(string $id)
|
||||
{
|
||||
$this->token->unsubscribe($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isRequested(): bool
|
||||
{
|
||||
return $this->token->isRequested();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function throwIfRequested()
|
||||
{
|
||||
$this->token->throwIfRequested();
|
||||
}
|
||||
}
|
||||
19
vendor/amphp/amp/lib/TimeoutException.php
vendored
Normal file
19
vendor/amphp/amp/lib/TimeoutException.php
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
namespace Amp;
|
||||
|
||||
/**
|
||||
* Thrown if a promise doesn't resolve within a specified timeout.
|
||||
*
|
||||
* @see \Amp\Promise\timeout()
|
||||
*/
|
||||
class TimeoutException extends \Exception
|
||||
{
|
||||
/**
|
||||
* @param string $message Exception message.
|
||||
*/
|
||||
public function __construct(string $message = "Operation timed out")
|
||||
{
|
||||
parent::__construct($message);
|
||||
}
|
||||
}
|
||||
825
vendor/amphp/amp/lib/functions.php
vendored
Normal file
825
vendor/amphp/amp/lib/functions.php
vendored
Normal file
|
|
@ -0,0 +1,825 @@
|
|||
<?php
|
||||
|
||||
namespace Amp
|
||||
{
|
||||
|
||||
use React\Promise\PromiseInterface as ReactPromise;
|
||||
|
||||
/**
|
||||
* Returns a new function that wraps $callback in a promise/coroutine-aware function that automatically runs
|
||||
* Generators as coroutines. The returned function always returns a promise when invoked. Errors have to be handled
|
||||
* by the callback caller or they will go unnoticed.
|
||||
*
|
||||
* Use this function to create a coroutine-aware callable for a promise-aware callback caller.
|
||||
*
|
||||
* @template TReturn
|
||||
* @template TPromise
|
||||
* @template TGeneratorReturn
|
||||
* @template TGeneratorPromise
|
||||
*
|
||||
* @template TGenerator as TGeneratorReturn|Promise<TGeneratorPromise>
|
||||
* @template T as TReturn|Promise<TPromise>|\Generator<mixed, mixed, mixed, TGenerator>
|
||||
*
|
||||
* @formatter:off
|
||||
*
|
||||
* @param callable(...mixed): T $callback
|
||||
*
|
||||
* @return callable
|
||||
* @psalm-return (T is Promise ? (callable(mixed...): Promise<TPromise>) : (T is \Generator ? (TGenerator is Promise ? (callable(mixed...): Promise<TGeneratorPromise>) : (callable(mixed...): Promise<TGeneratorReturn>)) : (callable(mixed...): Promise<TReturn>)))
|
||||
*
|
||||
* @formatter:on
|
||||
*
|
||||
* @see asyncCoroutine()
|
||||
*
|
||||
* @psalm-suppress InvalidReturnType
|
||||
*/
|
||||
function coroutine(callable $callback): callable
|
||||
{
|
||||
/** @psalm-suppress InvalidReturnStatement */
|
||||
return static function (...$args) use ($callback): Promise {
|
||||
return call($callback, ...$args);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new function that wraps $callback in a promise/coroutine-aware function that automatically runs
|
||||
* Generators as coroutines. The returned function always returns void when invoked. Errors are forwarded to the
|
||||
* loop's error handler using `Amp\Promise\rethrow()`.
|
||||
*
|
||||
* Use this function to create a coroutine-aware callable for a non-promise-aware callback caller.
|
||||
*
|
||||
* @param callable(...mixed): mixed $callback
|
||||
*
|
||||
* @return callable
|
||||
* @psalm-return callable(mixed...): void
|
||||
*
|
||||
* @see coroutine()
|
||||
*/
|
||||
function asyncCoroutine(callable $callback): callable
|
||||
{
|
||||
return static function (...$args) use ($callback) {
|
||||
Promise\rethrow(call($callback, ...$args));
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the given function, always returning a promise. If the function returns a Generator, it will be run as a
|
||||
* coroutine. If the function throws, a failed promise will be returned.
|
||||
*
|
||||
* @template TReturn
|
||||
* @template TPromise
|
||||
* @template TGeneratorReturn
|
||||
* @template TGeneratorPromise
|
||||
*
|
||||
* @template TGenerator as TGeneratorReturn|Promise<TGeneratorPromise>
|
||||
* @template T as TReturn|Promise<TPromise>|\Generator<mixed, mixed, mixed, TGenerator>
|
||||
*
|
||||
* @formatter:off
|
||||
*
|
||||
* @param callable(...mixed): T $callback
|
||||
* @param mixed ...$args Arguments to pass to the function.
|
||||
*
|
||||
* @return Promise
|
||||
* @psalm-return (T is Promise ? Promise<TPromise> : (T is \Generator ? (TGenerator is Promise ? Promise<TGeneratorPromise> : Promise<TGeneratorReturn>) : Promise<TReturn>))
|
||||
*
|
||||
* @formatter:on
|
||||
*/
|
||||
function call(callable $callback, ...$args): Promise
|
||||
{
|
||||
try {
|
||||
$result = $callback(...$args);
|
||||
} catch (\Throwable $exception) {
|
||||
return new Failure($exception);
|
||||
}
|
||||
|
||||
if ($result instanceof \Generator) {
|
||||
return new Coroutine($result);
|
||||
}
|
||||
|
||||
if ($result instanceof Promise) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
if ($result instanceof ReactPromise) {
|
||||
return Promise\adapt($result);
|
||||
}
|
||||
|
||||
return new Success($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the given function. If the function returns a Generator, it will be run as a coroutine. If the function
|
||||
* throws or returns a failing promise, the failure is forwarded to the loop error handler.
|
||||
*
|
||||
* @param callable(...mixed): mixed $callback
|
||||
* @param mixed ...$args Arguments to pass to the function.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function asyncCall(callable $callback, ...$args)
|
||||
{
|
||||
Promise\rethrow(call($callback, ...$args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sleeps for the specified number of milliseconds.
|
||||
*
|
||||
* @param int $milliseconds
|
||||
*
|
||||
* @return Delayed
|
||||
*/
|
||||
function delay(int $milliseconds): Delayed
|
||||
{
|
||||
return new Delayed($milliseconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current time relative to an arbitrary point in time.
|
||||
*
|
||||
* @return int Time in milliseconds.
|
||||
*/
|
||||
function getCurrentTime(): int
|
||||
{
|
||||
return Internal\getCurrentTime();
|
||||
}
|
||||
}
|
||||
|
||||
namespace Amp\Promise
|
||||
{
|
||||
|
||||
use Amp\Deferred;
|
||||
use Amp\Loop;
|
||||
use Amp\MultiReasonException;
|
||||
use Amp\Promise;
|
||||
use Amp\Success;
|
||||
use Amp\TimeoutException;
|
||||
use React\Promise\PromiseInterface as ReactPromise;
|
||||
use function Amp\call;
|
||||
use function Amp\Internal\createTypeError;
|
||||
|
||||
/**
|
||||
* Registers a callback that will forward the failure reason to the event loop's error handler if the promise fails.
|
||||
*
|
||||
* Use this function if you neither return the promise nor handle a possible error yourself to prevent errors from
|
||||
* going entirely unnoticed.
|
||||
*
|
||||
* @param Promise|ReactPromise $promise Promise to register the handler on.
|
||||
*
|
||||
* @return void
|
||||
* @throws \TypeError If $promise is not an instance of \Amp\Promise or \React\Promise\PromiseInterface.
|
||||
*
|
||||
*/
|
||||
function rethrow($promise)
|
||||
{
|
||||
if (!$promise instanceof Promise) {
|
||||
if ($promise instanceof ReactPromise) {
|
||||
$promise = adapt($promise);
|
||||
} else {
|
||||
throw createTypeError([Promise::class, ReactPromise::class], $promise);
|
||||
}
|
||||
}
|
||||
|
||||
$promise->onResolve(static function ($exception) {
|
||||
if ($exception) {
|
||||
throw $exception;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the event loop until the promise is resolved. Should not be called within a running event loop.
|
||||
*
|
||||
* Use this function only in synchronous contexts to wait for an asynchronous operation. Use coroutines and yield to
|
||||
* await promise resolution in a fully asynchronous application instead.
|
||||
*
|
||||
* @template TPromise
|
||||
* @template T as Promise<TPromise>|ReactPromise
|
||||
*
|
||||
* @param Promise|ReactPromise $promise Promise to wait for.
|
||||
*
|
||||
* @return mixed Promise success value.
|
||||
*
|
||||
* @psalm-param T $promise
|
||||
* @psalm-return (T is Promise ? TPromise : mixed)
|
||||
*
|
||||
* @throws \TypeError If $promise is not an instance of \Amp\Promise or \React\Promise\PromiseInterface.
|
||||
* @throws \Error If the event loop stopped without the $promise being resolved.
|
||||
* @throws \Throwable Promise failure reason.
|
||||
*/
|
||||
function wait($promise)
|
||||
{
|
||||
if (!$promise instanceof Promise) {
|
||||
if ($promise instanceof ReactPromise) {
|
||||
$promise = adapt($promise);
|
||||
} else {
|
||||
throw createTypeError([Promise::class, ReactPromise::class], $promise);
|
||||
}
|
||||
}
|
||||
|
||||
$resolved = false;
|
||||
|
||||
try {
|
||||
Loop::run(function () use (&$resolved, &$value, &$exception, $promise) {
|
||||
$promise->onResolve(function ($e, $v) use (&$resolved, &$value, &$exception) {
|
||||
Loop::stop();
|
||||
$resolved = true;
|
||||
$exception = $e;
|
||||
$value = $v;
|
||||
});
|
||||
});
|
||||
} catch (\Throwable $throwable) {
|
||||
throw new \Error("Loop exceptionally stopped without resolving the promise", 0, $throwable);
|
||||
}
|
||||
|
||||
if (!$resolved) {
|
||||
throw new \Error("Loop stopped without resolving the promise");
|
||||
}
|
||||
|
||||
if ($exception) {
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an artificial timeout for any `Promise`.
|
||||
*
|
||||
* If the timeout expires before the promise is resolved, the returned promise fails with an instance of
|
||||
* `Amp\TimeoutException`.
|
||||
*
|
||||
* @template TReturn
|
||||
*
|
||||
* @param Promise<TReturn>|ReactPromise $promise Promise to which the timeout is applied.
|
||||
* @param int $timeout Timeout in milliseconds.
|
||||
*
|
||||
* @return Promise<TReturn>
|
||||
*
|
||||
* @throws \TypeError If $promise is not an instance of \Amp\Promise or \React\Promise\PromiseInterface.
|
||||
*/
|
||||
function timeout($promise, int $timeout): Promise
|
||||
{
|
||||
if (!$promise instanceof Promise) {
|
||||
if ($promise instanceof ReactPromise) {
|
||||
$promise = adapt($promise);
|
||||
} else {
|
||||
throw createTypeError([Promise::class, ReactPromise::class], $promise);
|
||||
}
|
||||
}
|
||||
|
||||
$deferred = new Deferred;
|
||||
|
||||
$watcher = Loop::delay($timeout, static function () use (&$deferred) {
|
||||
$temp = $deferred; // prevent double resolve
|
||||
$deferred = null;
|
||||
$temp->fail(new TimeoutException);
|
||||
});
|
||||
Loop::unreference($watcher);
|
||||
|
||||
$promise->onResolve(function () use (&$deferred, $promise, $watcher) {
|
||||
if ($deferred !== null) {
|
||||
Loop::cancel($watcher);
|
||||
$deferred->resolve($promise);
|
||||
}
|
||||
});
|
||||
|
||||
return $deferred->promise();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an artificial timeout for any `Promise`.
|
||||
*
|
||||
* If the promise is resolved before the timeout expires, the result is returned
|
||||
*
|
||||
* If the timeout expires before the promise is resolved, a default value is returned
|
||||
*
|
||||
* @template TReturn
|
||||
*
|
||||
* @param Promise<TReturn>|ReactPromise $promise Promise to which the timeout is applied.
|
||||
* @param int $timeout Timeout in milliseconds.
|
||||
* @param TReturn $default
|
||||
*
|
||||
* @return Promise<TReturn>
|
||||
*
|
||||
* @throws \TypeError If $promise is not an instance of \Amp\Promise or \React\Promise\PromiseInterface.
|
||||
*/
|
||||
function timeoutWithDefault($promise, int $timeout, $default = null): Promise
|
||||
{
|
||||
$promise = timeout($promise, $timeout);
|
||||
|
||||
return call(static function () use ($promise, $default) {
|
||||
try {
|
||||
return yield $promise;
|
||||
} catch (TimeoutException $exception) {
|
||||
return $default;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapts any object with a done(callable $onFulfilled, callable $onRejected) or then(callable $onFulfilled,
|
||||
* callable $onRejected) method to a promise usable by components depending on placeholders implementing
|
||||
* \AsyncInterop\Promise.
|
||||
*
|
||||
* @param object $promise Object with a done() or then() method.
|
||||
*
|
||||
* @return Promise Promise resolved by the $thenable object.
|
||||
*
|
||||
* @throws \Error If the provided object does not have a then() method.
|
||||
*/
|
||||
function adapt($promise): Promise
|
||||
{
|
||||
if (!\is_object($promise)) {
|
||||
throw new \Error("Object must be provided");
|
||||
}
|
||||
|
||||
$deferred = new Deferred;
|
||||
|
||||
if (\method_exists($promise, 'done')) {
|
||||
$promise->done([$deferred, 'resolve'], [$deferred, 'fail']);
|
||||
} elseif (\method_exists($promise, 'then')) {
|
||||
$promise->then([$deferred, 'resolve'], [$deferred, 'fail']);
|
||||
} else {
|
||||
throw new \Error("Object must have a 'then' or 'done' method");
|
||||
}
|
||||
|
||||
return $deferred->promise();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a promise that is resolved when all promises are resolved. The returned promise will not fail.
|
||||
* Returned promise succeeds with a two-item array delineating successful and failed promise results,
|
||||
* with keys identical and corresponding to the original given array.
|
||||
*
|
||||
* This function is the same as some() with the notable exception that it will never fail even
|
||||
* if all promises in the array resolve unsuccessfully.
|
||||
*
|
||||
* @template TValue
|
||||
*
|
||||
* @param Promise<TValue>[]|ReactPromise[] $promises
|
||||
*
|
||||
* @return Promise<array{0: \Throwable[], 1: TValue[]}>
|
||||
*
|
||||
* @throws \Error If a non-Promise is in the array.
|
||||
*/
|
||||
function any(array $promises): Promise
|
||||
{
|
||||
return some($promises, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a promise that succeeds when all promises succeed, and fails if any promise fails. Returned
|
||||
* promise succeeds with an array of values used to succeed each contained promise, with keys corresponding to
|
||||
* the array of promises.
|
||||
*
|
||||
* @param Promise[]|ReactPromise[] $promises Array of only promises.
|
||||
*
|
||||
* @return Promise
|
||||
*
|
||||
* @throws \Error If a non-Promise is in the array.
|
||||
*
|
||||
* @template TValue
|
||||
*
|
||||
* @psalm-param array<array-key, Promise<TValue>|ReactPromise> $promises
|
||||
* @psalm-assert array<array-key, Promise<TValue>|ReactPromise> $promises $promises
|
||||
* @psalm-return Promise<array<array-key, TValue>>
|
||||
*/
|
||||
function all(array $promises): Promise
|
||||
{
|
||||
if (empty($promises)) {
|
||||
return new Success([]);
|
||||
}
|
||||
|
||||
$deferred = new Deferred;
|
||||
$result = $deferred->promise();
|
||||
|
||||
$pending = \count($promises);
|
||||
$values = [];
|
||||
|
||||
foreach ($promises as $key => $promise) {
|
||||
if ($promise instanceof ReactPromise) {
|
||||
$promise = adapt($promise);
|
||||
} elseif (!$promise instanceof Promise) {
|
||||
throw createTypeError([Promise::class, ReactPromise::class], $promise);
|
||||
}
|
||||
|
||||
$values[$key] = null; // add entry to array to preserve order
|
||||
$promise->onResolve(function ($exception, $value) use (&$deferred, &$values, &$pending, $key) {
|
||||
if ($pending === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($exception) {
|
||||
$pending = 0;
|
||||
$deferred->fail($exception);
|
||||
$deferred = null;
|
||||
return;
|
||||
}
|
||||
|
||||
$values[$key] = $value;
|
||||
if (0 === --$pending) {
|
||||
$deferred->resolve($values);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a promise that succeeds when the first promise succeeds, and fails only if all promises fail.
|
||||
*
|
||||
* @template TValue
|
||||
*
|
||||
* @param Promise<TValue>[]|ReactPromise[] $promises Array of only promises.
|
||||
*
|
||||
* @return Promise<TValue>
|
||||
*
|
||||
* @throws \Error If the array is empty or a non-Promise is in the array.
|
||||
*/
|
||||
function first(array $promises): Promise
|
||||
{
|
||||
if (empty($promises)) {
|
||||
throw new \Error("No promises provided");
|
||||
}
|
||||
|
||||
$deferred = new Deferred;
|
||||
$result = $deferred->promise();
|
||||
|
||||
$pending = \count($promises);
|
||||
$exceptions = [];
|
||||
|
||||
foreach ($promises as $key => $promise) {
|
||||
if ($promise instanceof ReactPromise) {
|
||||
$promise = adapt($promise);
|
||||
} elseif (!$promise instanceof Promise) {
|
||||
throw createTypeError([Promise::class, ReactPromise::class], $promise);
|
||||
}
|
||||
|
||||
$exceptions[$key] = null; // add entry to array to preserve order
|
||||
$promise->onResolve(function ($error, $value) use (&$deferred, &$exceptions, &$pending, $key) {
|
||||
if ($pending === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$error) {
|
||||
$pending = 0;
|
||||
$deferred->resolve($value);
|
||||
$deferred = null;
|
||||
return;
|
||||
}
|
||||
|
||||
$exceptions[$key] = $error;
|
||||
if (0 === --$pending) {
|
||||
$deferred->fail(new MultiReasonException($exceptions));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves with a two-item array delineating successful and failed Promise results.
|
||||
*
|
||||
* The returned promise will only fail if the given number of required promises fail.
|
||||
*
|
||||
* @template TValue
|
||||
*
|
||||
* @param Promise<TValue>[]|ReactPromise[] $promises Array of only promises.
|
||||
* @param int $required Number of promises that must succeed for the
|
||||
* returned promise to succeed.
|
||||
*
|
||||
* @return Promise<array{0: \Throwable[], 1: TValue[]}>
|
||||
*
|
||||
* @throws \Error If a non-Promise is in the array.
|
||||
*/
|
||||
function some(array $promises, int $required = 1): Promise
|
||||
{
|
||||
if ($required < 0) {
|
||||
throw new \Error("Number of promises required must be non-negative");
|
||||
}
|
||||
|
||||
$pending = \count($promises);
|
||||
|
||||
if ($required > $pending) {
|
||||
throw new \Error("Too few promises provided");
|
||||
}
|
||||
|
||||
if (empty($promises)) {
|
||||
return new Success([[], []]);
|
||||
}
|
||||
|
||||
$deferred = new Deferred;
|
||||
$result = $deferred->promise();
|
||||
$values = [];
|
||||
$exceptions = [];
|
||||
|
||||
foreach ($promises as $key => $promise) {
|
||||
if ($promise instanceof ReactPromise) {
|
||||
$promise = adapt($promise);
|
||||
} elseif (!$promise instanceof Promise) {
|
||||
throw createTypeError([Promise::class, ReactPromise::class], $promise);
|
||||
}
|
||||
|
||||
$values[$key] = $exceptions[$key] = null; // add entry to arrays to preserve order
|
||||
$promise->onResolve(static function ($exception, $value) use (
|
||||
&$values,
|
||||
&$exceptions,
|
||||
&$pending,
|
||||
$key,
|
||||
$required,
|
||||
$deferred
|
||||
) {
|
||||
if ($exception) {
|
||||
$exceptions[$key] = $exception;
|
||||
unset($values[$key]);
|
||||
} else {
|
||||
$values[$key] = $value;
|
||||
unset($exceptions[$key]);
|
||||
}
|
||||
|
||||
if (0 === --$pending) {
|
||||
if (\count($values) < $required) {
|
||||
$deferred->fail(new MultiReasonException($exceptions));
|
||||
} else {
|
||||
$deferred->resolve([$exceptions, $values]);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a promise into another promise, altering the exception or result.
|
||||
*
|
||||
* @param Promise|ReactPromise $promise
|
||||
* @param callable $callback
|
||||
*
|
||||
* @return Promise
|
||||
*/
|
||||
function wrap($promise, callable $callback): Promise
|
||||
{
|
||||
if ($promise instanceof ReactPromise) {
|
||||
$promise = adapt($promise);
|
||||
} elseif (!$promise instanceof Promise) {
|
||||
throw createTypeError([Promise::class, ReactPromise::class], $promise);
|
||||
}
|
||||
|
||||
$deferred = new Deferred();
|
||||
|
||||
$promise->onResolve(static function (?\Throwable $exception, $result) use ($deferred, $callback) {
|
||||
try {
|
||||
$result = $callback($exception, $result);
|
||||
} catch (\Throwable $exception) {
|
||||
$deferred->fail($exception);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$deferred->resolve($result);
|
||||
});
|
||||
|
||||
return $deferred->promise();
|
||||
}
|
||||
}
|
||||
|
||||
namespace Amp\Iterator
|
||||
{
|
||||
|
||||
use Amp\Delayed;
|
||||
use Amp\Emitter;
|
||||
use Amp\Iterator;
|
||||
use Amp\Producer;
|
||||
use Amp\Promise;
|
||||
use function Amp\call;
|
||||
use function Amp\coroutine;
|
||||
use function Amp\Internal\createTypeError;
|
||||
|
||||
/**
|
||||
* Creates an iterator from the given iterable, emitting the each value. The iterable may contain promises. If any
|
||||
* promise fails, the iterator will fail with the same reason.
|
||||
*
|
||||
* @param array|\Traversable $iterable Elements to emit.
|
||||
* @param int $delay Delay between element emissions in milliseconds.
|
||||
*
|
||||
* @return Iterator
|
||||
*
|
||||
* @throws \TypeError If the argument is not an array or instance of \Traversable.
|
||||
*/
|
||||
function fromIterable(/* iterable */
|
||||
$iterable,
|
||||
int $delay = 0
|
||||
): Iterator {
|
||||
if (!$iterable instanceof \Traversable && !\is_array($iterable)) {
|
||||
throw createTypeError(["array", "Traversable"], $iterable);
|
||||
}
|
||||
|
||||
if ($delay) {
|
||||
return new Producer(static function (callable $emit) use ($iterable, $delay) {
|
||||
foreach ($iterable as $value) {
|
||||
yield new Delayed($delay);
|
||||
yield $emit($value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return new Producer(static function (callable $emit) use ($iterable) {
|
||||
foreach ($iterable as $value) {
|
||||
yield $emit($value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @template TValue
|
||||
* @template TReturn
|
||||
*
|
||||
* @param Iterator<TValue> $iterator
|
||||
* @param callable (TValue $value): TReturn $onEmit
|
||||
*
|
||||
* @return Iterator<TReturn>
|
||||
*/
|
||||
function map(Iterator $iterator, callable $onEmit): Iterator
|
||||
{
|
||||
return new Producer(static function (callable $emit) use ($iterator, $onEmit) {
|
||||
while (yield $iterator->advance()) {
|
||||
yield $emit($onEmit($iterator->getCurrent()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @template TValue
|
||||
*
|
||||
* @param Iterator<TValue> $iterator
|
||||
* @param callable(TValue $value):bool $filter
|
||||
*
|
||||
* @return Iterator<TValue>
|
||||
*/
|
||||
function filter(Iterator $iterator, callable $filter): Iterator
|
||||
{
|
||||
return new Producer(static function (callable $emit) use ($iterator, $filter) {
|
||||
while (yield $iterator->advance()) {
|
||||
if ($filter($iterator->getCurrent())) {
|
||||
yield $emit($iterator->getCurrent());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an iterator that emits values emitted from any iterator in the array of iterators.
|
||||
*
|
||||
* @param Iterator[] $iterators
|
||||
*
|
||||
* @return Iterator
|
||||
*/
|
||||
function merge(array $iterators): Iterator
|
||||
{
|
||||
$emitter = new Emitter;
|
||||
$result = $emitter->iterate();
|
||||
|
||||
$coroutine = coroutine(static function (Iterator $iterator) use (&$emitter) {
|
||||
while ((yield $iterator->advance()) && $emitter !== null) {
|
||||
yield $emitter->emit($iterator->getCurrent());
|
||||
}
|
||||
});
|
||||
|
||||
$coroutines = [];
|
||||
foreach ($iterators as $iterator) {
|
||||
if (!$iterator instanceof Iterator) {
|
||||
throw createTypeError([Iterator::class], $iterator);
|
||||
}
|
||||
|
||||
$coroutines[] = $coroutine($iterator);
|
||||
}
|
||||
|
||||
Promise\all($coroutines)->onResolve(static function ($exception) use (&$emitter) {
|
||||
if ($exception) {
|
||||
$emitter->fail($exception);
|
||||
$emitter = null;
|
||||
} else {
|
||||
$emitter->complete();
|
||||
}
|
||||
});
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenates the given iterators into a single iterator, emitting values from a single iterator at a time. The
|
||||
* prior iterator must complete before values are emitted from any subsequent iterators. Iterators are concatenated
|
||||
* in the order given (iteration order of the array).
|
||||
*
|
||||
* @param Iterator[] $iterators
|
||||
*
|
||||
* @return Iterator
|
||||
*/
|
||||
function concat(array $iterators): Iterator
|
||||
{
|
||||
foreach ($iterators as $iterator) {
|
||||
if (!$iterator instanceof Iterator) {
|
||||
throw createTypeError([Iterator::class], $iterator);
|
||||
}
|
||||
}
|
||||
|
||||
$emitter = new Emitter;
|
||||
$previous = [];
|
||||
$promise = Promise\all($previous);
|
||||
|
||||
$coroutine = coroutine(static function (Iterator $iterator, callable $emit) {
|
||||
while (yield $iterator->advance()) {
|
||||
yield $emit($iterator->getCurrent());
|
||||
}
|
||||
});
|
||||
|
||||
foreach ($iterators as $iterator) {
|
||||
$emit = coroutine(static function ($value) use ($emitter, $promise) {
|
||||
static $pending = true, $failed = false;
|
||||
|
||||
if ($failed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($pending) {
|
||||
try {
|
||||
yield $promise;
|
||||
$pending = false;
|
||||
} catch (\Throwable $exception) {
|
||||
$failed = true;
|
||||
return; // Prior iterator failed.
|
||||
}
|
||||
}
|
||||
|
||||
yield $emitter->emit($value);
|
||||
});
|
||||
$previous[] = $coroutine($iterator, $emit);
|
||||
$promise = Promise\all($previous);
|
||||
}
|
||||
|
||||
$promise->onResolve(static function ($exception) use ($emitter) {
|
||||
if ($exception) {
|
||||
$emitter->fail($exception);
|
||||
return;
|
||||
}
|
||||
|
||||
$emitter->complete();
|
||||
});
|
||||
|
||||
return $emitter->iterate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Discards all remaining items and returns the number of discarded items.
|
||||
*
|
||||
* @template TValue
|
||||
*
|
||||
* @param Iterator $iterator
|
||||
*
|
||||
* @return Promise
|
||||
*
|
||||
* @psalm-param Iterator<TValue> $iterator
|
||||
* @psalm-return Promise<int>
|
||||
*/
|
||||
function discard(Iterator $iterator): Promise
|
||||
{
|
||||
return call(static function () use ($iterator): \Generator {
|
||||
$count = 0;
|
||||
|
||||
while (yield $iterator->advance()) {
|
||||
$count++;
|
||||
}
|
||||
|
||||
return $count;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects all items from an iterator into an array.
|
||||
*
|
||||
* @template TValue
|
||||
*
|
||||
* @param Iterator $iterator
|
||||
*
|
||||
* @psalm-param Iterator<TValue> $iterator
|
||||
*
|
||||
* @return Promise
|
||||
* @psalm-return Promise<array<array-key, TValue>>
|
||||
*/
|
||||
function toArray(Iterator $iterator): Promise
|
||||
{
|
||||
return call(static function () use ($iterator) {
|
||||
/** @psalm-var list $array */
|
||||
$array = [];
|
||||
|
||||
while (yield $iterator->advance()) {
|
||||
$array[] = $iterator->getCurrent();
|
||||
}
|
||||
|
||||
return $array;
|
||||
});
|
||||
}
|
||||
}
|
||||
22
vendor/amphp/byte-stream/LICENSE
vendored
Normal file
22
vendor/amphp/byte-stream/LICENSE
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2021 amphp
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
52
vendor/amphp/byte-stream/composer.json
vendored
Normal file
52
vendor/amphp/byte-stream/composer.json
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
{
|
||||
"name": "amphp/byte-stream",
|
||||
"homepage": "https://amphp.org/byte-stream",
|
||||
"description": "A stream abstraction to make working with non-blocking I/O simple.",
|
||||
"support": {
|
||||
"issues": "https://github.com/amphp/byte-stream/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"stream",
|
||||
"async",
|
||||
"non-blocking",
|
||||
"amp",
|
||||
"amphp",
|
||||
"io"
|
||||
],
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Aaron Piotrowski",
|
||||
"email": "aaron@trowski.com"
|
||||
},
|
||||
{
|
||||
"name": "Niklas Keller",
|
||||
"email": "me@kelunik.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.1",
|
||||
"amphp/amp": "^2"
|
||||
},
|
||||
"require-dev": {
|
||||
"amphp/phpunit-util": "^1.4",
|
||||
"phpunit/phpunit": "^6 || ^7 || ^8",
|
||||
"friendsofphp/php-cs-fixer": "^2.3",
|
||||
"amphp/php-cs-fixer-config": "dev-master",
|
||||
"psalm/phar": "^3.11.4",
|
||||
"jetbrains/phpstorm-stubs": "^2019.3"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Amp\\ByteStream\\": "lib"
|
||||
},
|
||||
"files": [
|
||||
"lib/functions.php"
|
||||
]
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Amp\\ByteStream\\Test\\": "test"
|
||||
}
|
||||
}
|
||||
}
|
||||
65
vendor/amphp/byte-stream/lib/Base64/Base64DecodingInputStream.php
vendored
Normal file
65
vendor/amphp/byte-stream/lib/Base64/Base64DecodingInputStream.php
vendored
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
namespace Amp\ByteStream\Base64;
|
||||
|
||||
use Amp\ByteStream\InputStream;
|
||||
use Amp\ByteStream\StreamException;
|
||||
use Amp\Promise;
|
||||
use function Amp\call;
|
||||
|
||||
final class Base64DecodingInputStream implements InputStream
|
||||
{
|
||||
/** @var InputStream|null */
|
||||
private $source;
|
||||
|
||||
/** @var string|null */
|
||||
private $buffer = '';
|
||||
|
||||
public function __construct(InputStream $source)
|
||||
{
|
||||
$this->source = $source;
|
||||
}
|
||||
|
||||
public function read(): Promise
|
||||
{
|
||||
return call(function () {
|
||||
if ($this->source === null) {
|
||||
throw new StreamException('Failed to read stream chunk due to invalid base64 data');
|
||||
}
|
||||
|
||||
$chunk = yield $this->source->read();
|
||||
if ($chunk === null) {
|
||||
if ($this->buffer === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$chunk = \base64_decode($this->buffer, true);
|
||||
if ($chunk === false) {
|
||||
$this->source = null;
|
||||
$this->buffer = null;
|
||||
|
||||
throw new StreamException('Failed to read stream chunk due to invalid base64 data');
|
||||
}
|
||||
|
||||
$this->buffer = null;
|
||||
|
||||
return $chunk;
|
||||
}
|
||||
|
||||
$this->buffer .= $chunk;
|
||||
|
||||
$length = \strlen($this->buffer);
|
||||
$chunk = \base64_decode(\substr($this->buffer, 0, $length - $length % 4), true);
|
||||
if ($chunk === false) {
|
||||
$this->source = null;
|
||||
$this->buffer = null;
|
||||
|
||||
throw new StreamException('Failed to read stream chunk due to invalid base64 data');
|
||||
}
|
||||
|
||||
$this->buffer = \substr($this->buffer, $length - $length % 4);
|
||||
|
||||
return $chunk;
|
||||
});
|
||||
}
|
||||
}
|
||||
55
vendor/amphp/byte-stream/lib/Base64/Base64DecodingOutputStream.php
vendored
Normal file
55
vendor/amphp/byte-stream/lib/Base64/Base64DecodingOutputStream.php
vendored
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
namespace Amp\ByteStream\Base64;
|
||||
|
||||
use Amp\ByteStream\OutputStream;
|
||||
use Amp\ByteStream\StreamException;
|
||||
use Amp\Failure;
|
||||
use Amp\Promise;
|
||||
|
||||
final class Base64DecodingOutputStream implements OutputStream
|
||||
{
|
||||
/** @var OutputStream */
|
||||
private $destination;
|
||||
|
||||
/** @var string */
|
||||
private $buffer = '';
|
||||
|
||||
/** @var int */
|
||||
private $offset = 0;
|
||||
|
||||
public function __construct(OutputStream $destination)
|
||||
{
|
||||
$this->destination = $destination;
|
||||
}
|
||||
|
||||
public function write(string $data): Promise
|
||||
{
|
||||
$this->buffer .= $data;
|
||||
|
||||
$length = \strlen($this->buffer);
|
||||
$chunk = \base64_decode(\substr($this->buffer, 0, $length - $length % 4), true);
|
||||
if ($chunk === false) {
|
||||
return new Failure(new StreamException('Invalid base64 near offset ' . $this->offset));
|
||||
}
|
||||
|
||||
$this->offset += $length - $length % 4;
|
||||
$this->buffer = \substr($this->buffer, $length - $length % 4);
|
||||
|
||||
return $this->destination->write($chunk);
|
||||
}
|
||||
|
||||
public function end(string $finalData = ""): Promise
|
||||
{
|
||||
$this->offset += \strlen($this->buffer);
|
||||
|
||||
$chunk = \base64_decode($this->buffer . $finalData, true);
|
||||
if ($chunk === false) {
|
||||
return new Failure(new StreamException('Invalid base64 near offset ' . $this->offset));
|
||||
}
|
||||
|
||||
$this->buffer = '';
|
||||
|
||||
return $this->destination->end($chunk);
|
||||
}
|
||||
}
|
||||
46
vendor/amphp/byte-stream/lib/Base64/Base64EncodingInputStream.php
vendored
Normal file
46
vendor/amphp/byte-stream/lib/Base64/Base64EncodingInputStream.php
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
namespace Amp\ByteStream\Base64;
|
||||
|
||||
use Amp\ByteStream\InputStream;
|
||||
use Amp\Promise;
|
||||
use function Amp\call;
|
||||
|
||||
final class Base64EncodingInputStream implements InputStream
|
||||
{
|
||||
/** @var InputStream */
|
||||
private $source;
|
||||
|
||||
/** @var string|null */
|
||||
private $buffer = '';
|
||||
|
||||
public function __construct(InputStream $source)
|
||||
{
|
||||
$this->source = $source;
|
||||
}
|
||||
|
||||
public function read(): Promise
|
||||
{
|
||||
return call(function () {
|
||||
$chunk = yield $this->source->read();
|
||||
if ($chunk === null) {
|
||||
if ($this->buffer === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$chunk = \base64_encode($this->buffer);
|
||||
$this->buffer = null;
|
||||
|
||||
return $chunk;
|
||||
}
|
||||
|
||||
$this->buffer .= $chunk;
|
||||
|
||||
$length = \strlen($this->buffer);
|
||||
$chunk = \base64_encode(\substr($this->buffer, 0, $length - $length % 3));
|
||||
$this->buffer = \substr($this->buffer, $length - $length % 3);
|
||||
|
||||
return $chunk;
|
||||
});
|
||||
}
|
||||
}
|
||||
39
vendor/amphp/byte-stream/lib/Base64/Base64EncodingOutputStream.php
vendored
Normal file
39
vendor/amphp/byte-stream/lib/Base64/Base64EncodingOutputStream.php
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
namespace Amp\ByteStream\Base64;
|
||||
|
||||
use Amp\ByteStream\OutputStream;
|
||||
use Amp\Promise;
|
||||
|
||||
final class Base64EncodingOutputStream implements OutputStream
|
||||
{
|
||||
/** @var OutputStream */
|
||||
private $destination;
|
||||
|
||||
/** @var string */
|
||||
private $buffer = '';
|
||||
|
||||
public function __construct(OutputStream $destination)
|
||||
{
|
||||
$this->destination = $destination;
|
||||
}
|
||||
|
||||
public function write(string $data): Promise
|
||||
{
|
||||
$this->buffer .= $data;
|
||||
|
||||
$length = \strlen($this->buffer);
|
||||
$chunk = \base64_encode(\substr($this->buffer, 0, $length - $length % 3));
|
||||
$this->buffer = \substr($this->buffer, $length - $length % 3);
|
||||
|
||||
return $this->destination->write($chunk);
|
||||
}
|
||||
|
||||
public function end(string $finalData = ""): Promise
|
||||
{
|
||||
$chunk = \base64_encode($this->buffer . $finalData);
|
||||
$this->buffer = '';
|
||||
|
||||
return $this->destination->end($chunk);
|
||||
}
|
||||
}
|
||||
7
vendor/amphp/byte-stream/lib/ClosedException.php
vendored
Normal file
7
vendor/amphp/byte-stream/lib/ClosedException.php
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
namespace Amp\ByteStream;
|
||||
|
||||
final class ClosedException extends StreamException
|
||||
{
|
||||
}
|
||||
39
vendor/amphp/byte-stream/lib/InMemoryStream.php
vendored
Normal file
39
vendor/amphp/byte-stream/lib/InMemoryStream.php
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
namespace Amp\ByteStream;
|
||||
|
||||
use Amp\Promise;
|
||||
use Amp\Success;
|
||||
|
||||
/**
|
||||
* Input stream with a single already known data chunk.
|
||||
*/
|
||||
final class InMemoryStream implements InputStream
|
||||
{
|
||||
private $contents;
|
||||
|
||||
/**
|
||||
* @param string|null $contents Data chunk or `null` for no data chunk.
|
||||
*/
|
||||
public function __construct(?string $contents = null)
|
||||
{
|
||||
$this->contents = $contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads data from the stream.
|
||||
*
|
||||
* @return Promise<string|null> Resolves with the full contents or `null` if the stream has closed / already been consumed.
|
||||
*/
|
||||
public function read(): Promise
|
||||
{
|
||||
if ($this->contents === null) {
|
||||
return new Success;
|
||||
}
|
||||
|
||||
$promise = new Success($this->contents);
|
||||
$this->contents = null;
|
||||
|
||||
return $promise;
|
||||
}
|
||||
}
|
||||
38
vendor/amphp/byte-stream/lib/InputStream.php
vendored
Normal file
38
vendor/amphp/byte-stream/lib/InputStream.php
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
namespace Amp\ByteStream;
|
||||
|
||||
use Amp\Promise;
|
||||
|
||||
/**
|
||||
* An `InputStream` allows reading byte streams in chunks.
|
||||
*
|
||||
* **Example**
|
||||
*
|
||||
* ```php
|
||||
* function readAll(InputStream $in): Promise {
|
||||
* return Amp\call(function () use ($in) {
|
||||
* $buffer = "";
|
||||
*
|
||||
* while (($chunk = yield $in->read()) !== null) {
|
||||
* $buffer .= $chunk;
|
||||
* }
|
||||
*
|
||||
* return $buffer;
|
||||
* });
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
interface InputStream
|
||||
{
|
||||
/**
|
||||
* Reads data from the stream.
|
||||
*
|
||||
* @return Promise Resolves with a string when new data is available or `null` if the stream has closed.
|
||||
*
|
||||
* @psalm-return Promise<string|null>
|
||||
*
|
||||
* @throws PendingReadError Thrown if another read operation is still pending.
|
||||
*/
|
||||
public function read(): Promise;
|
||||
}
|
||||
52
vendor/amphp/byte-stream/lib/InputStreamChain.php
vendored
Normal file
52
vendor/amphp/byte-stream/lib/InputStreamChain.php
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
namespace Amp\ByteStream;
|
||||
|
||||
use Amp\Promise;
|
||||
use Amp\Success;
|
||||
use function Amp\call;
|
||||
|
||||
final class InputStreamChain implements InputStream
|
||||
{
|
||||
/** @var InputStream[] */
|
||||
private $streams;
|
||||
/** @var bool */
|
||||
private $reading = false;
|
||||
|
||||
public function __construct(InputStream ...$streams)
|
||||
{
|
||||
$this->streams = $streams;
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function read(): Promise
|
||||
{
|
||||
if ($this->reading) {
|
||||
throw new PendingReadError;
|
||||
}
|
||||
|
||||
if (!$this->streams) {
|
||||
return new Success(null);
|
||||
}
|
||||
|
||||
return call(function () {
|
||||
$this->reading = true;
|
||||
|
||||
try {
|
||||
while ($this->streams) {
|
||||
$chunk = yield $this->streams[0]->read();
|
||||
if ($chunk === null) {
|
||||
\array_shift($this->streams);
|
||||
continue;
|
||||
}
|
||||
|
||||
return $chunk;
|
||||
}
|
||||
|
||||
return null;
|
||||
} finally {
|
||||
$this->reading = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
70
vendor/amphp/byte-stream/lib/IteratorStream.php
vendored
Normal file
70
vendor/amphp/byte-stream/lib/IteratorStream.php
vendored
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
|
||||
namespace Amp\ByteStream;
|
||||
|
||||
use Amp\Deferred;
|
||||
use Amp\Failure;
|
||||
use Amp\Iterator;
|
||||
use Amp\Promise;
|
||||
|
||||
final class IteratorStream implements InputStream
|
||||
{
|
||||
/** @var Iterator<string> */
|
||||
private $iterator;
|
||||
/** @var \Throwable|null */
|
||||
private $exception;
|
||||
/** @var bool */
|
||||
private $pending = false;
|
||||
|
||||
/**
|
||||
* @psalm-param Iterator<string> $iterator
|
||||
*/
|
||||
public function __construct(Iterator $iterator)
|
||||
{
|
||||
$this->iterator = $iterator;
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
public function read(): Promise
|
||||
{
|
||||
if ($this->exception) {
|
||||
return new Failure($this->exception);
|
||||
}
|
||||
|
||||
if ($this->pending) {
|
||||
throw new PendingReadError;
|
||||
}
|
||||
|
||||
$this->pending = true;
|
||||
/** @var Deferred<string|null> $deferred */
|
||||
$deferred = new Deferred;
|
||||
|
||||
$this->iterator->advance()->onResolve(function ($error, $hasNextElement) use ($deferred) {
|
||||
$this->pending = false;
|
||||
|
||||
if ($error) {
|
||||
$this->exception = $error;
|
||||
$deferred->fail($error);
|
||||
} elseif ($hasNextElement) {
|
||||
$chunk = $this->iterator->getCurrent();
|
||||
|
||||
if (!\is_string($chunk)) {
|
||||
$this->exception = new StreamException(\sprintf(
|
||||
"Unexpected iterator value of type '%s', expected string",
|
||||
\is_object($chunk) ? \get_class($chunk) : \gettype($chunk)
|
||||
));
|
||||
|
||||
$deferred->fail($this->exception);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$deferred->resolve($chunk);
|
||||
} else {
|
||||
$deferred->resolve();
|
||||
}
|
||||
});
|
||||
|
||||
return $deferred->promise();
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue