This commit is contained in:
2026-03-01 19:29:21 +01:00
parent 6aea41d765
commit 6e2dad9a82
208 changed files with 36579 additions and 2101 deletions
+97
View File
@@ -0,0 +1,97 @@
<?php
require_once __DIR__ . '/config.php';
if (session_status() === PHP_SESSION_NONE) { session_start(); }
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
exit('Méthode non autorisée');
}
// CSRF
if (empty($_POST['csrf_token']) || $_POST['csrf_token'] !== ($_SESSION['csrf_token'] ?? '')) {
http_response_code(400);
exit('Token CSRF invalide.');
}
// Vérif login
if (empty($_SESSION['user_id'])) {
http_response_code(403);
exit('Tu dois être connecté pour acheter.');
}
$user_id = (int)$_SESSION['user_id'];
$item_id = isset($_POST['item_id']) ? (int)$_POST['item_id'] : 0;
$pdo = pdo_connect();
try {
$pdo->beginTransaction();
// Vérifie si le user possède déjà un item
$stmt = $pdo->prepare("SELECT ui.id, i.name
FROM user_items ui
JOIN items i ON ui.item_id = i.id
WHERE ui.user_id = :uid
LIMIT 1 FOR UPDATE");
$stmt->execute([':uid' => $user_id]);
$existing = $stmt->fetch();
if ($existing) {
$pdo->rollBack();
exit("Tu possèdes déjà un item actif : " . htmlspecialchars($existing['name']));
}
// Récupère item
$stmt = $pdo->prepare("SELECT id, name, price FROM items WHERE id = :id FOR UPDATE");
$stmt->execute([':id' => $item_id]);
$item = $stmt->fetch();
if (!$item) {
$pdo->rollBack();
exit('Item introuvable.');
}
$total = (int)$item['price'];
// Vérifie aura
$stmt = $pdo->prepare("SELECT aura FROM users WHERE id = :uid FOR UPDATE");
$stmt->execute([':uid' => $user_id]);
$u = $stmt->fetch();
if (!$u) {
$pdo->rollBack();
exit('Utilisateur introuvable.');
}
$aura = (int)$u['aura'];
if ($aura < $total) {
$pdo->rollBack();
exit('Tu n\'as pas assez d\'aura pour cet achat.');
}
// Débite l'aura
$stmt = $pdo->prepare("UPDATE users SET aura = aura - :amt WHERE id = :uid");
$stmt->execute([':amt' => $total, ':uid' => $user_id]);
// Ajoute item à user_items
$stmt = $pdo->prepare("INSERT INTO user_items (user_id, item_id) VALUES (:uid, :iid)");
$stmt->execute([':uid' => $user_id, ':iid' => $item_id]);
// Log (version simplifiée, sans actor_discord_id ni type)
$stmt = $pdo->prepare("INSERT INTO logs (user_id, amount, reason)
VALUES (:uid, :amount, :reason)");
$stmt->execute([
':uid' => $user_id,
':amount' => -$total,
':reason' => 'Achat: ' . $item['name']
]);
$pdo->commit();
header('Location: shop.php?buy=ok');
exit;
} catch (Exception $e) {
if ($pdo->inTransaction()) $pdo->rollBack();
echo "Erreur détaillée : " . $e->getMessage();
var_dump($item_id, $user_id, $total, $aura);
exit;
}
+120
View File
@@ -0,0 +1,120 @@
<?php
require_once __DIR__ . '/config.php';
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
if (!isset($_GET['code']) || !isset($_GET['state'])) {
http_response_code(400);
exit("Paramètres manquants.");
}
// CSRF : vérifier state
if (!isset($_SESSION['oauth2_state']) || $_GET['state'] !== $_SESSION['oauth2_state']) {
unset($_SESSION['oauth2_state']);
http_response_code(400);
exit("Échec de la vérification de sécurité (state).");
}
unset($_SESSION['oauth2_state']);
$code = $_GET['code'];
// Étape 1 : échange du code contre un access_token
$token_url = "https://discord.com/api/oauth2/token";
$post_fields = [
'client_id' => DISCORD_CLIENT_ID,
'client_secret' => DISCORD_CLIENT_SECRET,
'grant_type' => 'authorization_code',
'code' => $code,
'redirect_uri' => DISCORD_REDIRECT_URI,
'scope' => 'identify email'
];
$ch = curl_init($token_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_fields));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/x-www-form-urlencoded'
]);
// ⚠️ remet le SSL, mieux pour la prod
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
$response = curl_exec($ch);
if ($response === false) {
exit("Erreur cURL token: " . curl_error($ch));
}
curl_close($ch);
$token_data = json_decode($response, true);
if (!isset($token_data['access_token'])) {
exit("Échec de l'échange de token: " . htmlspecialchars($response));
}
$access_token = $token_data['access_token'];
// Étape 2 : récupérer infos utilisateur
$ch = curl_init("https://discord.com/api/users/@me");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer $access_token"
]);
$user_json = curl_exec($ch);
if ($user_json === false) {
exit("Erreur cURL user: " . curl_error($ch));
}
curl_close($ch);
$user_data = json_decode($user_json, true);
if (!isset($user_data['id'])) {
exit("Impossible de récupérer l'utilisateur Discord. Réponse: " . htmlspecialchars($user_json));
}
// Préparation des données
$discord_id = $user_data['id'];
$username = $user_data['username'] . (isset($user_data['discriminator']) && $user_data['discriminator'] !== "0" ? '#' . $user_data['discriminator'] : "");
$email = $user_data['email'] ?? null;
$avatar = !empty($user_data['avatar'])
? "https://cdn.discordapp.com/avatars/{$discord_id}/{$user_data['avatar']}.png"
: null;
// Étape 3 : DB
try {
$pdo = pdo_connect();
} catch (Exception $e) {
exit("Erreur DB : " . $e->getMessage());
}
$stmt = $pdo->prepare("SELECT id FROM users WHERE discord_id = :did LIMIT 1");
$stmt->execute([':did' => $discord_id]);
$u = $stmt->fetch();
if ($u) {
$stmt = $pdo->prepare("UPDATE users SET username = :username, email = :email, profile_picture = :avatar WHERE discord_id = :did");
$stmt->execute([
':username' => $username,
':email' => $email,
':avatar' => $avatar,
':did' => $discord_id
]);
$user_id = $u['id'];
} else {
$stmt = $pdo->prepare("INSERT INTO users (discord_id, username, email, profile_picture, aura, tier)
VALUES (:did, :username, :email, :avatar, 0, 'Aura')");
$stmt->execute([
':did' => $discord_id,
':username' => $username,
':email' => $email,
':avatar' => $avatar
]);
$user_id = $pdo->lastInsertId();
}
// Étape 4 : session
$_SESSION['user_id'] = $user_id;
$_SESSION['discord_id'] = $discord_id;
$_SESSION['username'] = $username;
$_SESSION['profile_picture'] = $avatar;
// Étape 5 : redirection
header("Location: index.php");
exit;
+25
View File
@@ -0,0 +1,25 @@
<?php
// config.php
session_start();
define('DB_HOST', '127.0.0.1');
define('DB_PORT', '3306'); // ou 8035 si tu as changé
define('DB_NAME', 'banque_aura');
define('DB_USER', 'root');
define('DB_PASS', 'root');
define('DISCORD_CLIENT_ID', '1318190631914307645');
define('DISCORD_CLIENT_SECRET', 'zRXVwXeAYSSL1YbSwPkNVgrgBJN6-i1_');
define('DISCORD_REDIRECT_URI', 'http://128.78.3.237:8082/aura_bank/callback.php'); // adapter
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4"
];
function pdo_connect(){
global $options;
$dsn = "mysql:host=".DB_HOST.";port=".DB_PORT.";dbname=".DB_NAME.";charset=utf8mb4";
return new PDO($dsn, DB_USER, DB_PASS, $options);
}
+26
View File
@@ -0,0 +1,26 @@
<?php
// functions.php
require_once __DIR__ . '/config.php';
function get_top_users($limit = 10) {
$pdo = pdo_connect();
$stmt = $pdo->prepare("SELECT username, aura, discord_id, tier, profile_picture FROM users ORDER BY aura DESC LIMIT :lim");
$stmt->bindValue(':lim', (int)$limit, PDO::PARAM_INT);
$stmt->execute();
return $stmt->fetchAll();
}
function get_user_by_discord($discord_id) {
$pdo = pdo_connect();
$stmt = $pdo->prepare("SELECT * FROM users WHERE discord_id = :did LIMIT 1");
$stmt->execute([':did' => $discord_id]);
return $stmt->fetch();
}
function get_user_rank($aura) {
$pdo = pdo_connect();
$stmt = $pdo->prepare("SELECT COUNT(*) + 1 AS 'rank' FROM users WHERE aura > :aura");
$stmt->execute([':aura' => $aura]);
$r = $stmt->fetch();
return $r ? (int)$r['rank'] : null;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 327 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

+78
View File
@@ -0,0 +1,78 @@
<?php
require_once __DIR__ . '/functions.php';
$top = get_top_users(10);
require_once __DIR__ . '/config.php';
$logged = isset($_SESSION['discord_id']);
?>
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Banque de l'Aura — Classement</title>
<style>
body{font-family:Arial,Helvetica,sans-serif;background:#f4f4f9;color:#222;padding:20px}
.card{max-width:800px;margin:0 auto;background:#fff;padding:18px;border-radius:8px;box-shadow:0 6px 18px rgba(0,0,0,.06)}
h1{margin:0 0 12px}
table{width:100%;border-collapse:collapse}
th,td{padding:10px;border-bottom:1px solid #eee;text-align:left;vertical-align:middle}
th{background:#fbfbfc}
.pos-1::before{content:"🥇 ";}
.pos-2::before{content:"🥈 ";}
.pos-3::before{content:"🥉 ";}
.avatar{width:32px;height:32px;border-radius:50%;object-fit:cover;vertical-align:middle;margin-right:8px}
.user-link{display:flex;align-items:center;text-decoration:none;color:#222}
.user-link:hover{text-decoration:underline}
.user-id{font-size:12px;color:#666;margin-left:40px;margin-top:-4px}
.welcome{display:flex;align-items:center;gap:12px;margin-bottom:18px;font-size:16px}
.welcome img{width:40px;height:40px;border-radius:50%;object-fit:cover}
</style>
</head>
<body>
<div class="card">
<?php if ($logged): ?>
<div class="welcome" style="display:flex;align-items:center;gap:12px;margin-bottom:16px;">
<?php if(!empty($_SESSION['profile_picture'])): ?>
<a href="profile.php?discord_id=<?= urlencode($_SESSION['discord_id']) ?>">
<img src="<?= htmlspecialchars($_SESSION['profile_picture']) ?>" alt="Avatar" style="width:40px;height:40px;border-radius:50%;object-fit:cover;">
</a>
<?php endif; ?>
<span style="font-size:16px;">
Bienvenue,
<a href="profile.php?discord_id=<?= urlencode($_SESSION['discord_id']) ?>" style="text-decoration:none;color:#222;">
<strong><?= htmlspecialchars($_SESSION['username']) ?></strong>
</a>
</span>
</div>
<?php else: ?>
<a href="login.php">Se connecter avec Discord</a>
<?php endif; ?>
<h1>🏆 Classement des meilleures auras</h1>
<?php if(empty($top)): ?>
<p>Le classement est vide.</p>
<?php else: ?>
<table>
<thead><tr><th>#</th><th>Utilisateur</th><th>Aura</th><th>Grade</th></tr></thead>
<tbody>
<?php foreach($top as $i => $row): ?>
<?php $pos = $i + 1; $cls = $pos<=3 ? "pos-{$pos}" : ""; ?>
<tr>
<td class="<?= htmlspecialchars($cls) ?>"><?= $pos ?></td>
<td>
<?php if(!empty($row['profile_picture'])): ?>
<img src="<?= htmlspecialchars($row['profile_picture']) ?>" alt="" class="avatar">
<?php endif; ?>
<strong><?= htmlspecialchars($row['username']) ?></strong>
<div class="user-id">ID: <?= htmlspecialchars($row['discord_id']) ?></div>
</td>
<td><?= (int)$row['aura'] ?></td>
<td><?= htmlspecialchars($row['tier']) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</div>
</body>
</html>
+30
View File
@@ -0,0 +1,30 @@
<?php
require_once __DIR__ . '/config.php';
// scopes : identify pour ID + username, email si tu veux email
$scope = 'identify email';
// génère un state CSRF
$state = bin2hex(random_bytes(16));
$_SESSION['oauth2_state'] = $state;
$params = http_build_query([
'client_id' => DISCORD_CLIENT_ID,
'redirect_uri' => DISCORD_REDIRECT_URI,
'response_type' => 'code',
'scope' => $scope,
'state' => $state,
'prompt' => 'consent'
]);
$discord_authorize_url = "https://discord.com/oauth2/authorize?$params";
?>
<!doctype html>
<html>
<head><meta charset="utf-8"><title>Login Discord</title></head>
<body>
<a href="<?= htmlspecialchars($discord_authorize_url) ?>">
<img src="https://raw.githubusercontent.com/DiscordAssets/discord-open-graph/main/discord_logo.png" alt="Discord" style="height:28px;vertical-align:middle"> Se connecter avec Discord
</a>
</body>
</html>
+5
View File
@@ -0,0 +1,5 @@
<?php
require_once __DIR__ . '/config.php';
session_destroy();
header('Location: index.php');
exit;
+102
View File
@@ -0,0 +1,102 @@
<?php
require_once __DIR__ . '/functions.php';
$discord_id = isset($_GET['discord_id']) ? trim($_GET['discord_id']) : null;
if (!$discord_id) {
http_response_code(400);
echo "Paramètre discord_id manquant.";
exit;
}
$user = get_user_by_discord($discord_id);
if (!$user) {
http_response_code(404);
echo "Utilisateur introuvable.";
exit;
}
$rank = get_user_rank($user['aura']);
?>
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<title>Profil de <?= htmlspecialchars($user['username']) ?></title>
<style>
body{font-family:Arial,Helvetica,sans-serif;background:#f4f4f9;color:#222;padding:20px}
.card{max-width:700px;margin:0 auto;background:#fff;padding:18px;border-radius:8px;box-shadow:0 6px 18px rgba(0,0,0,.06)}
.avatar{width:96px;height:96px;border-radius:50%;object-fit:cover}
.header{display:flex;align-items:center;gap:16px;justify-content:space-between}
.user-info{flex:1}
.btn-group{display:flex;gap:8px;margin-top:4px}
.btn{padding:6px 12px;border:none;border-radius:4px;background:#4CAF50;color:white;text-decoration:none;cursor:pointer;}
.btn.logout{background:#f44336;}
table{width:100%;border-collapse:collapse;margin-top:8px;}
th, td{padding:8px;border-bottom:1px solid #ccc;text-align:left;}
</style>
</head>
<body>
<div class="card">
<div class="header">
<div style="display:flex;align-items:center;gap:16px">
<?php if(!empty($user['profile_picture'])): ?>
<img src="<?= htmlspecialchars($user['profile_picture']) ?>" alt="" class="avatar">
<?php endif; ?>
<div class="user-info">
<h2><?= htmlspecialchars($user['username']) ?></h2>
<div>ID Discord: <?= htmlspecialchars($user['discord_id']) ?></div>
<div style="margin-top:8px;"><strong>Aura:</strong> <?= (int)$user['aura'] ?> — <strong>Grade:</strong> <?= htmlspecialchars($user['tier']) ?></div>
<div style="margin-top:6px;"><strong>Rang:</strong> #<?= (int)$rank ?></div>
</div>
</div>
<div class="btn-group">
<a href="index.php" class="btn">Accueil</a>
<a href="shop.php" class="btn">Boutique</a>
<a href="logout.php" class="btn logout">Se déconnecter</a>
</div>
</div>
<hr style="margin:14px 0">
<h3>Historique récent</h3>
<?php
$pdo = pdo_connect();
$stmt = $pdo->prepare("
SELECT amount, reason, created_at
FROM logs
WHERE user_id = :uid OR user_id = :discord_id
ORDER BY created_at DESC
");
$stmt->execute([
':uid' => $user['id'],
':discord_id' => $user['discord_id']
]);
$logs = $stmt->fetchAll();
if (!$logs): ?>
<p>Aucun historique.</p>
<?php else: ?>
<table style="width:100%;border-collapse:collapse;margin-top:8px;">
<thead>
<tr style="background:#f0f0f0;text-align:left;">
<th style="padding:8px;border-bottom:1px solid #ccc;">Date</th>
<th style="padding:8px;border-bottom:1px solid #ccc;">Montant</th>
<th style="padding:8px;border-bottom:1px solid #ccc;">Raison</th>
</tr>
</thead>
<tbody>
<?php foreach($logs as $l):
$amount = (int)$l['amount'];
$bg_color = $amount >= 0 ? '#d4f7d4' : '#f7d4d4'; // vert pale si gain, rouge pale si perte
?>
<tr style="background:<?= $bg_color ?>;border-bottom:1px solid #eee;">
<td style="padding:10px;"><?= htmlspecialchars($l['created_at']) ?></td>
<td style="padding:10px;"><?= $amount ?></td>
<td style="padding:10px;"><?= htmlspecialchars($l['reason']) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</div>
</body>
</html>
+143
View File
@@ -0,0 +1,143 @@
<?php
require_once __DIR__ . '/config.php'; // contient pdo_connect() et session start
require_once __DIR__ . '/functions.php'; // si nécessaire
// Vérifie session
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
$pdo = pdo_connect();
// Récupère les items
$stmt = $pdo->query("SELECT id, name, description, price FROM items ORDER BY price ASC");
$items = $stmt->fetchAll();
// Génère token CSRF simple
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(16));
}
// Récupère saldo de l'utilisateur si connecté
$logged = isset($_SESSION['user_id']);
$userAura = null;
if ($logged) {
$stmt = $pdo->prepare("SELECT aura FROM users WHERE id = :uid LIMIT 1");
$stmt->execute([':uid' => $_SESSION['user_id']]);
$row = $stmt->fetch();
$userAura = $row ? (int)$row['aura'] : 0;
}
?>
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Boutique — Banque de l'Aura</title>
<style>
body{font-family:Arial,Helvetica,sans-serif;background:#f4f4f9;color:#222;padding:20px}
.card{max-width:1000px;margin:0 auto;background:#fff;padding:18px;border-radius:8px;box-shadow:0 6px 18px rgba(0,0,0,.06)}
h1{margin:0 0 12px}
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px}
.item{border:1px solid #eee;padding:12px;border-radius:8px;background:#fafafa;display:flex;flex-direction:column;gap:8px}
.badge{width:32px;height:32px;object-fit:cover}
.item-icon{width:32px;height:32px;object-fit:cover;vertical-align:middle;margin-right:8px}
.price{font-weight:700}
.stock{font-size:13px;color:#666}
.buy-form{margin-top:auto}
.btn{display:inline-block;padding:8px 12px;border-radius:6px;background:#2d8aef;color:#fff;text-decoration:none;border:none;cursor:pointer}
.btn.disabled{opacity:.5;cursor:not-allowed;background:#9bbbed}
.row-top {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 14px;
padding: 10px 16px;
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 6px rgba(0,0,0,0.08);
}
.row-top .user-info {
display: flex;
align-items: center;
gap: 10px;
}
.row-top img {
width: 32px;
height: 32px;
border-radius: 50%;
object-fit: cover;
}
.balance{font-weight:700}
</style>
</head>
<body>
<div class="card">
<div class="row-top">
<h1>🛒 Boutique</h1>
<?php if ($logged): ?>
<div class="user-info">
<div class="balance">
💎 Solde : <strong><?= htmlspecialchars($userAura ?? 0) ?> aura</strong>
</div>
<div class="active_item">
<?php
$stmt = $pdo->prepare("SELECT i.name
FROM user_items ui
JOIN items i ON ui.item_id = i.id
WHERE ui.user_id = :uid
LIMIT 1");
$stmt->execute([':uid' => $_SESSION['user_id']]);
$activeItem = $stmt->fetch();
?>
<?php if ($activeItem): ?>
🎖️ Item actif : <strong><?= htmlspecialchars($activeItem['name']) ?></strong>
<?php else: ?>
🎖️ Aucun item actif
<?php endif; ?>
</div>
<div class="profile-link">
<a href="profile.php?discord_id=<?= urlencode($_SESSION['discord_id']) ?>">Voir mon profil</a>
</div>
</div>
<?php else: ?>
<div class="login-link">
<a href="login.php">Se connecter avec Discord pour acheter</a>
</div>
<?php endif; ?>
</div>
<div class="grid">
<?php foreach($items as $it): ?>
<div class="item">
<div>
<span class="badge"><img class="item-icon" src="img/items/<?= htmlspecialchars($it['id']) ?>.png"></span>
<strong><?= htmlspecialchars($it['name']) ?></strong>
</div>
<?php if(!empty($it['description'])): ?>
<div style="font-size:14px;color:#333"><?= htmlspecialchars($it['description']) ?></div>
<?php endif; ?>
<div class="price"><?= (int)$it['price'] ?> aura</div>
<form class="buy-form" method="post" action="buy.php">
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
<input type="hidden" name="item_id" value="<?= (int)$it['id'] ?>">
<?php
$canBuy = $logged && ($userAura !== null && $userAura >= (int)$it['price']);
?>
<button class="btn <?= $canBuy ? '' : 'disabled' ?>" <?= $canBuy ? '' : 'disabled' ?>>
Acheter
</button>
</form>
</div>
<?php endforeach; ?>
</div>
</div>
</body>
</html>
-3
View File
@@ -28,7 +28,6 @@ body {
}
.video-container {
width: 80%;
margin: 20px auto;
border: 2px solid #2ecccc;
border-radius: 25px;
@@ -40,8 +39,6 @@ body {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
header {
+3 -3
View File
@@ -4,7 +4,7 @@
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans&display=swap" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">
<link rel="icon" href="img/logo.png">
<title>WhyKorp</title>
<title>love</title>
</head>
<body>
<div class="container">
@@ -37,11 +37,11 @@
<hr>
<h1>Voici la dernière vidéo de <a href="https://www.youtube.com/@whykioh">Whykioh</a> :</h1>
<div class="video-container">
<iframe width="560" height="315" src="https://www.youtube.com/embed/cqFXFAbXXOo?si=V2fgt9eyroo8sK6C" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
<iframe width="557,55" height="315" src="https://www.youtube.com/embed/-ZPjXjvdZFc?si=ldsNogAHy636GnzU" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
</div>
</div>
<div class="footer">
Copyright | Whykorp® 2021-2024
Copyright | Whykorp® 2021-2024 | ajoute le nom du site après l'url et un /
</div>
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

+26
View File
@@ -0,0 +1,26 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Pour Clara 💌</title>
<link rel="stylesheet" href="style.css">
<link rel="icon" href="img/logo.png">
</head>
<body>
<div class="container">
<h1>Ma Semaine sans Toi ❤️</h1>
<p class="intro"> Coucou mon amoureuse damour que jaime tant❤️. Comme tu le vois je te fais un petit journal de mes journées, je vais beaucoup mennuyer sans toi donc je me suis dis que jallais moccuper un peu tout les jours à t’écrire deux trois mots que tu liras à ton retour. Le site te plaît ? Il est joli et tout rose héhé je lai fais moi même pour toi. Dans ce journal je te raconterai mes journées comme ça tu verras que sans toi cest pas pareil😣.</p>
<hr>
<div class="button-grid">
<button onclick="location.href='journals/1_dimanche.html'">Dimanche 27 Avril</button>
<button onclick="location.href='journals/2_lundi.html'">Lundi 28 Avril</button>
<button onclick="location.href='journals/3_mardi.html'">Mardi 29 Avril</button>
<button onclick="location.href='journals/4_mercredi.html'">Mercredi 30 Avril</button>
<button onclick="location.href='journals/5_jeudi.html'">Jeudi 1er Mai</button>
<button onclick="location.href='journals/6_vendredi.html'">Vendredi 2 Mai</button>
<button onclick="location.href='journals/7_samedi.html'">Samedi 3 Mai</button>
<button onclick="location.href='journals/8_dimanche.html'">Dimanche 4 Mai</button>
</div>
</div>
</body>
</html>
+31
View File
@@ -0,0 +1,31 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Jour 1 💌</title>
<link rel="stylesheet" href="../style.css">
</head>
<body>
<div class="container">
<h1>Jour 1 - Dimanche 27 Avril</h1>
<p>Là cest dimanche, tu me manques déjà beaucoup… Est-ce que cest parce que cest le début ? Ou bien mon manque est bel est bien justifié. Là il est 11h30 j’écoute Shaka Ponk en t’écrivant ses mots Lets baaaanng bang baaaang (pardon jsuis a fond) Je taime trop vraiment. Je tai envoyé deux images que mon père ma envoyé, une de moi avec Mathieu et Fabien et mon père où est en mode <a href="https://www.youtube.com/watch?v=_VfwZSygTeI&t=9s">WAAAAHH</a> (ptddr cest Waluigi) et la deuxième un meme que mon père ma envoyé qui est plutot drôle mais tu les as pas vus donc jimagine que tu dors sur la route (même si je pense que cest pas a 3h de route) ou que tu as déjà commencer. </p>
<p><em>Je viens juste de réaliser mais ce que je suis en train de te faire cest ton rêve, cest juste moi qui raconte ma vie et tu adores ça🤭.</em></p>
<p>Je te fais mon programme de la journée : Tout dabord je vais aller manger cest un bon début, pourquoi pas me laver ça serait une bonne option mdrr ensuite je pense que je vais ranger tout mon bordel dans ma chambre, ma mère me ramènera ensuite chez mon père, je rangerais tout et je retrouverai ROBEEERTT !!🤭Après jirai manger chez ma mamie je lui mettrai sa Wii ça va être drôle je pense, par contre jy reste jusqu’à mardi et ça membête un peu… Je voulais déprimer tout seul mdrr</p>
<p>Je pense que je vais laisser le document ouvert sur mon PC et des fois je viendrai t’écrire un peu. En plus j'ai mis une note sur Insta en mode "J'espère qu'elle lira tout" ahah c'est trop drôle tout le monde veut savoir pourquoi</p>
<p>Re coucouuu là il est 16h j'ai pas encore fais mon gouter mais ça ne saurait tarder ! Je suis allé voir ma mère on a jouer à un jeu rigolo avec les coques de pistaches en mode "si je la mets tu fais ça" c'était marrant mais personne n'a réussi de lancer... Après on a manger vite fait en regardant Le fabuleux destin d'Amélie Poulain je l'avais déjà vu et ça m'a fait plaisir de le revoir. Pendant le film m'a mère a voulu me faire une coupe de fou, t'as du voir les buddies même en ayant retiré les élastiques mes cheveux volaient mdrr j'en pouvais plus. Après ça ma mère m'a dit de ranger ma chambre car je vais bientôt partir, mais évidemment je me suis laisser m'égarer en fait j'ai regarder tous les images de plannings de live que Matreox avait fait et j'ai tout jugé mdrr t'aurais trop kiffé m'entendre juger je pense. Là je pense que je vais essayer de faire mon planning de lives pour cette semaine du moins un brouillon, je vais live tout les jours a partir de mardi, j'espère que tu viendras au moins pour faire un petit coucou. Je t'aime mon amour, j'espère que ça se passe bien de ton côté et que tu t'amuses. Bisouuus !❤️</p>
<p>Je pense beaucoup à toi c'est pas la première fois où je me surprends à regarder le vide tout en pensant à toi quand je m'en rends compte j'ai les yeux lourds, la boule au ventre et le coeur qui bat vite, presque en train de pleurer. Ça fait qu'un jour, c'est déjà trop long. Je passe souvent dans ma galerie pour regarder des photos de nous, on est trop mignons tous les deux. J'ai encore rien mis dans mon sac mais tant de "je t'aime" à t'écrire... Je pourrais faire ça toute la journée. Ça y est je pleure, j'ai trop regardé nos photos. Je te laisse je dois ranger ma chambre❤️</p>
<p>Coucouuu jai rangé ma chambre et mes affaires et jai fais le trajet vers chez mon père je suis vite aller dans ma chambre pour voir Robert, il était la il mattendait, je lui ai fait un gros gros calin et je suis allé me doucher. Tas déjà pleuré sous la douche toi ? Cest trop bizarre, ça mest arrivé je pensais trop à toi je crois. Jai refais mes sacs pour chez ma mamie, la je suis sur le trajet, je te dirai quand jy serai. Je taime mon amour❤️</p>
<p>Coucouuu, oh j'suis content tu m'as envoyé des messages🤭et j'ai mangé c'était bon ça va. Là je suis en voc avec Julien, il est trop happy de me montrer ce qu'il a eu sur Minecraft. J'espère qu'il va me remonter le moral. Il a fait vla les trucs vraiment, je vais rajouter des mods sinon on va s'ennuyer il a tout dans le jeu mdrr. Bon je te laisse mon amour, en plus y a peut etre Eudes et Enzo qui vont rejoindre. Bisouuus !❤️</p>
<p>Coucouu, tu dors alors je vais écrire pas trop fort. Là y a une ambiance trop chill j'adore, même s'il manque toi... Tout à l'heure j'étais en appel avec Julien, Enzo et Eudes Je te l'ai dis en plus et Eudes m'à dit que Simon à dit cette phrase "En vrai si Adrian vient pas avec nous au Pal tu pourras dire à Noah de venir" AAAAHHH Je te jure j'suis trop heureux, ça veut dire que ça va mieux avec Simon et que je vais pouvoir partir en vacances avec toi et avec mes potes, trop bien ! J'ai du bouger parce que j'étais dans la chambre de ma mamie et quand je suis revenu sur mon ordi y avait plus personne... Pas grave, alors j'ai commencé l'article d'Adrian, je te jure que j'adore faire ça genre vraiment si un jour t'as la flemme j'suis là hein (stp) Du coup là j'ai fini son article. Je suis posé sur la table à manger sur un siège de bureau avec du Shaka Ponk à fond I dont give a They dont give a We dont give a fuuuuck !! - mon frère regarde un film sur la télé et je vais continuer d'écrire mon article je pense. Ou alors je vais regarder youtube parce que je suis un peu fatigué je ferai ça demain. Putain je crois que j'ai un putain de moustique qui me tourne autour, pitié sauve moi mon amour... J'ai trop hâte de dormir parce que demain y a petit dej et le petit dej chez ma mamie c'est trop trop trop booon, donc en fait je vais dodo devant youtube, j'ai ramener Robert et Monsieur Plouf et le pull pour dormir dedans mais pas le plaid parce que le chien de ma mamie à le même plaid et elle les manges donc je veux pas qu'elle mange mon plaid.</p>
<hr>
<p>Bon je pense que je te reparlerai pas de la journée (en plus il est minuit passé là (00h20) du coup je vais te faire un débrief ! Aujourd'hui c'était dur.. J'ai pu te parler ce matin... un peu... Je pense vraiment que ce moment était le meilleur de la semaine. J'espère que ta lecture te plait jusqu'ici, je sais pas encore si je vais te le faire lire quand je serai là ou pas.. J'ai même hésiter à te faire lire un jour par jour, genre dimanche prochain tu lis que cette journée là. Je sais pas trop... Je me suis beaucoup ennuyer aujourd'hui et en plus mon père et ma mamie m'ont dit que j'avais l'air perdu toute la soirée. Je leur ai pas dis que tu me manquais, je pense que si ma mamie me demande demain je lui dirai et mon père je lui dirai sans doute mardi ou mercredi, aujourd'hui c'était pas le jour, je pouvais pas en parler sans pleurer Je l'ai dis a Julien j'ai chialer... en plus a un moment je sortais enfin de ma chambre parce que je faisais que de pleurer mon père a parlé de toi je sais plus pourquoi et j'ai couru dans ma chambre pour re pleurer. Mdrr je fais pitié je t'ai fais un word ou je te dis toutes les deux ligne que je chiale... Bonne nuit mon amour❤️</p>
<h2 id="love">Je t'aime ❤️</h2>
<p class="author">Ton amoureux d'amour, Noah ❤️</p>
<div class="nav-bar">
<button class="glow-button" onclick="window.location.href='../index.html'">🏠 Accueil</button>
<button class="glow-button" onclick="window.location.href='2_lundi.html'">➡ Suivant</button>
</div>
</div>
</body>
</html>
File diff suppressed because one or more lines are too long
+22
View File
@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Jour 3 💌</title>
<link rel="stylesheet" href="../style.css">
</head>
<body>
<div class="container">
<h1>Jour 3 - Mardi 29 Avril</h1>
<p>Coucouu, alors aujourd'hui était une journée bien plus chargée que prévu du coup j'ai pas trop pu prendre la parole ici... Là il est 23h30 et il s'est passé beaucoup de trucs. Du coup je vais tout te raconter mais rapidement parce que j'ai un peu (beaucoup) envie de faire de l'ASMR.. Désolé. Donc j'ai fais mon petit dej trop bienn dehors comme hier ensuite on a tout rangé et je me suis remis sur ma Wii qui voulait pas ajouter les nouveaux jeux à la liste je cherche mais je trouve pas. En même temps ma mamie me parle d'un de ses vieil ordi (très vieux hein de 2007) qui marchait très bien mais qui est juste bloqué. Bon pas grave je lance un transfert sur la Wii et en attendant je m'occupe de cet ordi. En l'allumant l'écran n'affiche rien, j'en conclu que l'écran est HS alors je le branche à la télé et BOUM y a un truc. Alors c'est rempli de "!!" et entre ces "!!" il y a du texte mais écrit bizarrement, on aurait dit qu'il manquait des lettre ou que certaines lettre n'étaient pas les bonnes. Je me décide de réinstaller un Windows dessus tant qu'a faire j'en mets un vieux pour pas que l'ordi lag trop je choisi un Windows 7, qui n'est certes plus assuré par les mises à jour mais qui fera bien le taff. Et là ma mamie me dit que Yannick (mon tonton) avait déjà essayé de réparer l'ordi mais n'avait pas réussi donc il a démonté le disque dur pour récupérer les photos et askip il a gardé le disque... Je démonte l'ordi et effectivement il manque le disque dur.. Merde ! Je décide de tout démonter afin de vérifier que l'ordi est entier et que mon tonton ne se soit pas servit dedans (il aurait pu le faire). Et là je vois un emplacement vide.. De la RAM en plus ? Non l'emplacement est trop petit.. Je demande à ChatGPT et d'après lui c'est un emplacement IDE. Pour l'info les disques durs de nos jours sont soit des SSD (les très rapides) soit des HDD. Aujourd'hui on connecte les HDD avec des prises SATA (comme on connecterait un téléphone en Type-C) mais avant il éxistait une antiquité, la prise IDE avec des nappes. C'était la même vitesse qu'une disquette. Bref je m'égare. En tout cas il manque rien a part le disque dûr. Ma mamie m'a donc confié l'ordi pour que je m'en occupe dans la semaine (je ferai ça Samedi ou Vendredi) Entre temps le disque dur de la Wii avait tout fini je lance et là rien... Je fouille les paramètre de l'appli Wii où y a tous mes jeux, je décoche une option et ça y est ! Ça marche !! Et là on joue a Wii Sport Resort pendant que je faisais des steaks (oui pour encore manger des burgers mdrr) et c'était marrant, genre on faisait le bowling chacun son tour, c'était assez fun. On mange dehors il fait beau il fait bon c'est cool. Je vais donc à la douche (j'ai fais ton buddies🤭) Et juste après paf on rentre pour chez mon père. Sur le chemin j'ai un peu dormi, mais vite fait j'avais juste les yeux fermés et le vent sur la tête, trop confort. On arrive je mon mes affaires enfin heureux de ENFIN retrouver ma chambre putain (et aussi de retrouver ta boîte à goûter) ma mamie boit le café vite fait puis ils s'en vont. Avec mon père on règle un problème avec le serveur puis on fait un petit apéro en finissant un spéctacle qu'on avait commencé et ensuite on va voir Pierre Emmanuel Barré. Oh j'étais trop content tu m'as appelé. Son spectacle était drôle mais je t'en dirai plus en voc j'ai un peu la flemme mon amour. On est rentré on a fait burger king mdrr j'ai branché mon ordi et je t'écris ceci avant de te parler pas messages. Là tu m'en envoies j'suis trop heureux</p>
<h2 id="love">Je t'aime ❤️</h2>
<p class="author">Ton homme, Noah ❤️</p>
<div class="nav-bar">
<button class="glow-button" onclick="window.location.href='2_lundi.html'">⬅ Précédent</button>
<button class="glow-button" onclick="window.location.href='../index.html'">🏠 Accueil</button>
<button class="glow-button" onclick="window.location.href='4_mercredi.html'">➡ Suivant</button>
</div>
</div>
</body>
</html>
+29
View File
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Jour 4 💌</title>
<link rel="stylesheet" href="../style.css">
</head>
<body>
<div class="container">
<h1>Jour 4 - Mercredi 30 Avril</h1>
<p>Coucouuu ça va ? Bien dormi ? Moi oui mais il me manquait ma femme.. Je me suis levé grave tôt il était 9h, là il est 10h et je suis en pleine écriture de mon article, je charbone pour pouvoir le rendre vers midi je pense. J'ai fais a peu près 1000 mots là et j'ai pas fini encore. Avant de commencer à écrire j'ai checké vite fait un peu tout, le pdf et le site voir si Adrian ne s'était pas planté et il a oublié les mots en gras sur le site... Du coup je te le dis et là tu me dis la pire chose que tu pourrais me dire "Dis lui de le mettre" WAAAAA MAIS JE VAIS ME FAIRE SOULEVER. Bon tu sais que je ferai tout pour toi hein je vais surmonter ma peur et je vais lui dire vu que t'es occupée... Là je vais lui envoyer un message, changer de pentalon (je me serai chié dessus) prier et retourner écrire mon article. Au fait tant que j'y pense Vendredi je me fais couper les cheveux haha. Bon je te laisse je vais écrire mon testament mdrr. Bisouus !</p>
<p>Coucouu euh je t'écrire vraiment une minute après ce qu'il y a au dessus mdrr mais j'ai un soucis mon Spotify ne veux plus que j'écoute l'album Toxicity de System genre je lance l'album et ça me met une seconde de chaque son jusqu'au dernier et ça coupe, je vais mourir vraiment mdrr bon aller bisous ! Même mon père ! Est dans le coup...</p>
<img src="../img/screen_cheh_papa.png" alt="Screen de la conversation avec mon père" class="screenshot">
<p>Coucouuu ça va ? Il est 14h bientôt j'ai bien mangé, mon père a fait des pâtes et on y a mit du gruyère sauf que je sens une odeur bizarre, un fois à table. Je dis à mon père "le gruyère est pas périmé ? Mon père dit non et puis je regarde attentivement. Mdrr y avait des taches bleues dans le gruyère.. Du coup on a jetté et on s'est reservi à contre coeur... Et j'ai fini mon article je vais le mettre sur le pdf. Il fait 1600 mots donc ça va en vrai, comme celui à Célia si je dis pas de bêtises. Bref je m'y mets parce que je dois prendre une douche après ça pour aller au cinéma, je vais voir Thunderbolts* Bref Bisouuu mon amouuuur (j'ai vu que tu as fais des buddies j'suis content)</p>
<p>Coucouuu Il est 16h45 là je vais bien de fou ! J'ai tout fini sur mon article j'ai mis en page et j'ai planifié mon article. Adrian n'a toujours pas vu mon message alors qu'il a posté une note sur Insta y a 2h... On te voit en fait. Après ça j'ai pris une douche et mon frère est arrivé avec ma mamie et mon père, je les ait laisser discuter pour envoyer le message sur le groupe du Gay-Lu Times. J'ai géré de fouuu. Je t'aime mon amour, j'espère que tu es fière de moi même si tu es loin de moi... </p>
<p>Coucouu mon amour ! Je suis si bouleversé, tu m'as appelé. Mais avant je suis allé au cinéma pour voir Thunderbolts* Le film est... Je sais pas, bof je dirai. Ni nul ni bien en fait.. Après ça je suis allé au Quick et on a eu un burger gratuit, truc de fou ! Mais bon ça tu le sais déjà du coup j'ai moins de trucs à te dire ce soir... Ah si quand on rentrait au feu rouge ou y a le Legrand on avait la music A.N.U.S. de Ultra Vomit et au même moment y a un vieux aigri qui s'est arrêté à côté de nous. Mon père à monté le son progressivement en faisant exprès mdrr c'était très drole.</p>
<hr>
<p>Je t'aime mon amour, tu me manques trop je pensais que j'avais passé le cap mais j'ai pleuré quand tu as raccroché tout à l'heure. Pour te l'avouer j'avais déjà commencer avant que tu quittes (un peu comme quand on fait de l'asmr tout les deux en appel). J'aimerai trop te serrer dans mes bras, enfin ressentir la chaleur de ton corps contre le miens, goûter à tes belles et douces lèvres, désirer ton regard et observer les étoiles à travers tes yeux, caresser des belles joues et jouer avec tes soyeux cheveux. Je m'égard là.. Bref, bonne nuit mon amour je t'aime tellement</p>
<h2 id="love">Je t'aime ❤️</h2>
<p class="author">Ta crotte d'amour, Noah ❤️</p>
<div class="nav-bar">
<button class="glow-button" onclick="window.location.href='3_mardi.html'">⬅ Précédent</button>
<button class="glow-button" onclick="window.location.href='../index.html'">🏠 Accueil</button>
<button class="glow-button" onclick="window.location.href='5_jeudi.html'">➡ Suivant</button>
</div>
</div>
</body>
</html>
+29
View File
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Jour 5 💌</title>
<link rel="stylesheet" href="../style.css">
</head>
<body>
<div class="container">
<h1>Jour 5 - Jeudi 1er Mai</h1>
<p>Coucouu mon amour alors là il est 3h du matin, juste pour te dire que je vais aller me coucher mais je venais de faire le site que tu regardes là. Hehe j'suis trop fier de ce que j'ai fais c'est tout kiki, comme toi ❤️</p>
<p>Coucouuu ça va mon amour ? ❤️ J'ai bien dormi perso, je me suis levé à midi mais j'avais fais un rêve trop bizarre je me souviens pas de tout, mais je sais qu'à un moment mon frère fouille ce site là. Et à la fin je vais dans le garage de mes grands parents pour prendre une bouteille de Pepsi sauf qu'elle est chaude de fou vu qu'elle est restée au soleil, du coup je la mets au congélateur pour la refroidir un peu. Mais je remarque que depuis le début j'avais les yeux fermés et flous, tu sais comme quand tu viens de te réveiller. Du coup je cours en montant à l'étage pour me débarbouiller le visage. Et là je monte et c'est l'étage de ma maison à Feytiat, et en fait je cours parce qu'il y a quelqu'un derière moi qui veut me tuer, je sais pas qui c'est. J'arrive dans la salle de bain et je cherche un gant, j'en trouve pas du coup je fais ça avec une serviette et là le mec qui veut me tuer s'approche et me rend la bouteille de pepsi. Wesh.. Et là je me réveille... Bizarre. Bon après j'ai fais un Fifa pendant que mon père faisait à manger - c'est à dire des frites - et après ça j'ai mangé le burger en trop d'hier. On a regardé le Hot Ones avec Alain Chabat c'est trop bien. Et là il est 14h33 je sais pas ce que je vais faire, je vais surement brancher mon volant pour jouer à un jeu, pourquoi pas à BeamNG Drive. Bref je te laisse mon amour. Bisouuus</p>
<p>Je suis vraiment premier degrès en train de péter un plomb, j'en ai marre je sais pas quoi faire. J'ai littéralement fais tout ce que je pouvais faire. J'ai passé 2h sur un jeu de merde qui me plaisait pas juste parce que je savais pas quoi faire, bah j'ai vite abandonné. Et là je suis à deux doigts de casser mon écran ou de je jeter par la fenêtre, voire même de me jeter par la fenêtre. Je suis en train de devenir fou j'en peux plus. Reviens s'il te plait, je m'ennuie sans toi...</p>
<p>Euh j'allais t'écrire là mais je vois ça ⬇️ Il faut savoir que l'IA du logiciel de code prédis ce que je vais écrire. Bon là il essaye de prédire des truc nul mais wesh pourquoi il sait pour Feytiat. C'est mentionné nulle part ailleurs. Trop bizarre</p>
<img src="../img/ia.png" alt="IA qui prédit Feytiat" class="ia" width="90%">
<p>MDRRR Et là il m'a prédis la ligne pour mettre l'image en mettant le titre "IA qui prédit Feytiat" j'vais cabler</p>
<p>Bon du coup je voulais te dire. Là il est 3h du mat oui je triche on est vendredi techniquement mdrr. Je m'ennuyais trop à jouer à GT4 que du coup j'ai fais du casque et pour la vanne j'ai testé les jeux 18+. Mdrr comment c'est claqué au sol c'est juste pas pratique en fait je vois pas comment tu peux faire l'asmr en vrai en jouant à ça t'as constament les mains prises. Bref. Après ça je suis allé faire le gouter et je me suis dis que j'allais live à 20h J'ai rejoins Julien et Enzo en vocal. Enzo est parti quand j'ai lancé le live parce qu'il devait manger. Pas grave. J'ai d'abord fais du bedwars comme à l'ancienne mais mon ordi buggait trop c'est une dinguerie du coup j'ai changé pour Arcade Paradise (j'avais déjà commencé le jeu en live) Après ça Julien m'a rappelé l'existance du jeu The Exit 8 en fait ça fait un an je pense que je veux faire une vidéo dessus mais que j'y pensse pas. Du coup j'ai fais un live dessus et le concept est trop bien, y aura un montage sur ma chaine de ce gameplay. Ensuite j'ai coupé le live il était 23h30 mdrr et avec julien on a trainé sur les activités discord on a trouvé un Uno trop bien et on a joué au golf après. J'ai dis que je voulais dormir et il a lancé le tableau blanc commun mdrr. Evidemment on a fait des ref à 39-45 tu connais mdrr et après je t'écris et je vais dodo.</p>
<hr>
<p>Tu me manques trop vraiment. Aujourd'hui j'ai pas répondu à tes messages Insta et tu vas peut être trouver ça bizarre et me prendre pour un fou mais hier j'ai eu peur. Hier t'as envoyé des emojis que t'envoies jamais mais genre vraiment jamais. Ils faisaient quoi dans les récents alors ? Surtout celui qui regarde à travers ses yeux là. Tu l'envoie jamais et tu l'as envoyé à quelqu'un, je vois pas à qui ça peut être à part un amant, en mode "chut ça reste entre nous on lui dis pas"... Désolé je continue avec ça tu sais que c'est mon pire cauchemar.. Et en vrai j'ai aucune raison de pas te répondre. Je me doute trop de ce genre de choses. Mais comprends moi t'es loin si jamais tu en aurais l'envie tu aurais pu me tromper à cette distance je n'en saurai rien.. J'ai un peu déprimé aujourd'hui à cause de ça et je sais très bien que te le dire là par message n'arrangera rien parce que tu vas répéter comme d'habitude que tu n'oserai jamais faire ça. Bref désolé j'ai écris tout ça pour rien je vais effacer je pense.<br>Demain je vais chez le coiffeur à 11h fini les cheveux longs en plus après je vais acheter pleins de fringues je vais vraiment changer premier degrés ça va être cool. J'espère. En vrai j'aurai préféré faire ça avec toi, les boutiques et tout.. Bref je te laisse je vais dormir bonne nuit bisous ❤️</p>
<h2 id="love">Je t'aime ❤️</h2>
<p class="author">Ton cocu ?, Noah ❤️</p>
<div class="nav-bar">
<button class="glow-button" onclick="window.location.href='4_mercredi.html'">⬅ Précédent</button>
<button class="glow-button" onclick="window.location.href='../index.html'">🏠 Accueil</button>
<button class="glow-button" onclick="window.location.href='6_vendredi.html'">➡ Suivant</button>
</div>
</div>
</body>
</html>
+23
View File
@@ -0,0 +1,23 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Jour 6 💌</title>
<link rel="stylesheet" href="../style.css">
</head>
<body>
<div class="container">
<h1>Jour 6 - Vendredi 2 Mai</h1>
<p>Coucou mon amour ! Je vais tout t'écrire en une fois et y a plein de trucs à dire en plus ! Aujourd'hui je me suis levé et je suis allé dans la boite aux lettre récupérer le lecteur de disques durs pour pouvoir améliorer le serveur et mon ordi, je le débale je met le 2to que mon père m'a donné et je me dis que je vais mettre mon disque C dedans, remettre à 0 mon ordi pour l'ocasion. Bon j'ai que transféré là. Après ça je suis allé chez le coiffeur, elle a bien réussi ma coupe je trouve genre excatement ce à quoi je pensais. Donc nickel. Mais mon frère y est allé après et la coiffeuse à dit "Tu veux quoi comme coupe ?" Mon frère à dit "court." Bon.. ça tête ressemble à une mousse de micro mdrr, on dirait un télétubbies mais sans l'antenne bref avec mon frère on a vanné sa coupe toute la journée mdrr. Après fallait manger, moi je voulais manger à l'appart parce que flemme d'encore manger dehors. On a manger à Monsieur le Baron. Tu sais c'est le gros resto deluxe qui a pris feut pas loin du lycée. J'ai suivi mon père et mon frère à contre coeur j'en peux plus de manger des burgers mdrr. C'était bon en vrai. Après on est allés à Family Village on est allé à Inter Sport pour prendre des vetement pour moi puis à la halle puis à décatelon (on a fait une escale à boulanger pour que mon père se renseigne sur sa future télé mdrr) du coup j'ai pleins de nouveux vetements c'est trop bien. J'ai aussi pris un maillot de bain mais pas de claquette vu que je prendrais des Crocs vu que madame n'a d'yeux que pour les crocs. Je suis rentré et j'ai reset mon ordi pendant que je jouais à Mortal Kombat 1 avec mon père. J'ai galéré de fou, en fait mon ordi et sur protégé du coup pour formater bah c'est chiant. J'ai appliqué la méthode forte sauf qu'après j'avais plus rien qui marchait à part la souris et le clavier genre la luminosité de l'écran non et le wifi non plus. Après des heures de recherches j'ai rétabli le wifi le bluetooth la luminosité et d'autres trucs. J'ai mangé une petite salade et j'ai installé Need For Speed Most Wanted, la version de 2005, ce jeu est ouf pour 2005 vraiment. J'y jouais en étant en vocal avec Julien Enzo et Eudes qui est parti tôt.</p>
<hr>
<p>Je suis désolé mon amour j'ai pas osé répondre à tes messages, déjà parce que tu me les envoyais toujours au mauvais moment et en plus j'osais pas, je sais jamais quoi dire après t'avoir mis un remis, je m'en veux d'un côté mais d'un autre je trouve ça toujours aussi louche.. Désolé je force avec ça, je changerai jamais.. Bref Bisous Je t'aime mon amour dort bien❤️</p>
<h2 id="love">Je t'aime ❤️</h2>
<p class="author">Ton informaticien du dimanche, Noah ❤️</p>
<div class="nav-bar">
<button class="glow-button" onclick="window.location.href='5_jeudi.html'">⬅ Précédent</button>
<button class="glow-button" onclick="window.location.href='../index.html'">🏠 Accueil</button>
<button class="glow-button" onclick="window.location.href='7_samedi.html'">➡ Suivant</button>
</div>
</div>
</body>
</html>
+26
View File
@@ -0,0 +1,26 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Jour 7 💌</title>
<link rel="stylesheet" href="../style.css">
</head>
<body>
<div class="container">
<h1>Jour 7 - Samedi 3 Mai</h1>
<p>Coucouuu mon amouuur ! Tellement de choses à te dire alors qu'il est même pas 15h mdrr Déjà je me suis levé et jme suis fais un kiff j'ai fais le super p'tit dej comme chez ma grand mère, c'était moins bon y avait pas la vibe de chez elle mais bon. Après je me suis dis que j'allais m'attaquer à l'ordi de ma mamie justement. Alors je branche tout et là je remarque qu'elle n'a pas donné son alim... J'utilise mon alim les prises on l'air de correspondre. Sauf que, rien ça marche pas, alors je rends l'écran que j'ai volé a mon frère pour le brancher et je remets l'alim sur mon ordi. ET C'EST LE DRAME. Mon ordi ne charge plus, yess.. Je suis à ça de chialer alors je vais chercher une pince et j'essaye de remettre la tige qui n'était plus droite et là y a des étincelles mdrr. Du coup j'abandonne la mission et je dis ça à mon père. Mon père il s'énerve après ma mamie en mode "Ouais elle soule avec ses vieux trucs de merdes qui marchent pas et tout" Moi j'étais à côté en mode "ok". Du coup on va à LDLC pour voir s'ils en ont un. C'est fermé ça ouvre à 14h il est 13h20 là. Du coup on va a boulanger et on est super bien accueilli (c'est faux) par le mec qui dit "Ouais 120 balles ! Vous l'aurez Mardi en livraison ou Mercredi voire Jeudi" bon on à laissé le gars mdrr. On est aller voir les télés à Darty parce que mon père hésite à en acheter une. Et aussi pour passer le temps. Une fois qu'il est 14h on va à LDLC et là tout de suite ça change, le mec est trop sympa. Il nous donne un truc avec genre 9 embouts différents mdrr et on rentre. J'essaye.. Hallelujah !! C'est bon, ça marche ! Et du coup je t'écris là et je pense que je vais me re-regarder tous les Fast & Furious parce que j'sais pas j'ai eu envie d'un coup. Bon je te laisse bisouuuus</p>
<p>Coucouu ça va ? J'ai regardé Fast and Furious 1 j'ai aimé c'est vraiment trop bien. Je me dis qu'en vrai on pourrait les continuer tout les deux quand tu seras revenue ! Après ça j'ai rangé mes habits que j'ai acheté hier et Julien m'a proposé de venir en vocal avec Enzo et Eudes, je suis arrivé. On a fait un golf discord là et après du Gartic Phone c'était marrant. Ah oui et j'ai appris un truc. Adrian veut bien me reparler genre ça le dérangerait pas mais à une condition : que je lui donne 700 balles. Bah non mdrr il est con lui. J'ai raccroché pour aller manger j'ai mangé poulet paprika avec des patates miam. Par contre j'ai des gaz de fou genre j'arrête pas de péter et ça pue la mort en plus à chaque fois c'est infame ça me fait chier. (sans mauvais jeu de mot) Et là il est 21h40 je suis de retour en voc avec eux on va Gartic Phonner mdrr Je te laisse bisouus !</p>
<P>Bonsoiiiir je viens de faire un petit live sympa on a fait du gartic phone c'était cool. Après j'ai coupé parce qu'il était tard et de 00h à 1h30 on a jouer a des jeux discord avec julien et enzo mdrr c'était trop cool. Par contre tu m'as un peu énervé.. A absolument vouloir voir ma coupe alors que tu peux juste attendre, je voulais te faire la surprise mais t'as tout gaché. Je veux voir ta réaction moi pas juste un "Wow" qui ne répresentent que trois pauves lettres à mes yeux.. Mais non madame est trop pressée. En plus j'étais avec mes potes tu me dérangeais un peu. Plus ça va plus je me demande si ce site est une bonne idée..</P>
<hr>
<p>Aujourd'hui c'était particulier, c'était techniquement le dernier jour sans toi même si c'était chiant. Il s'est passé pas mal de trucs relou notemment l'alim de mon ordi. En plus je commence à douter de mon idée. Je suis sûr que tu vas lire tout ça mais qu'au fond tu vas t'en foutre, ou même que tu vas pas lire. Ou que tu ne trouves pas le lien du site. Puis j'écris pour rien là, il est 2h du matin faut que je dorme. Au début j'aimais bien écrire là, c'était un peu mon vide pensée, maintenant je me force un peu pour toi. Alors que tu ne liras surment pas ça. J'espère que les gateaux que je t'ai laissé étaient bon, je sais que t'aimes pas le chocolat mais j'avais rien d'autre.. Bref Bonne nuit ❤️</p>
<h2>Je t'aime ❤️</h2>
<p class="author">A quoi bon.., Noah ❤️</p>
<div class="nav-bar">
<button class="glow-button" onclick="window.location.href='6_vendredi.html'">⬅ Précédent</button>
<button class="glow-button" onclick="window.location.href='../index.html'">🏠 Accueil</button>
<button class="glow-button" onclick="window.location.href='8_dimanche.html'">➡ Suivant</button>
</div>
</div>
</body>
</html>
+21
View File
@@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Jour 8 💌</title>
<link rel="stylesheet" href="../style.css">
</head>
<body>
<div class="container">
<h1>Jour 8 - Dimanche 4 Mai</h1>
<p>Coucou mon amour, bien dormi ? Je sais que là t'es chez toi je crois (il est 17h30) mais j'ai pas eu de nouvelles, tant pis je dirai que je le mérite un peu. J'écris vite parce que je vais bientot partir pour aller chez ma mère. Aujourd'hui après m'être levé j'ai graille et j'ai fais mes sacs, mon père m'a donné un big sac qui est trop bien on peut mettre plein de trucs dedans. J'y pense un peu là mais je sais que même si on est dimanche et que c'est ton retour je pourrais pas te parler soit parce que tu auras pas le temps ou que tu m'oublira voire que tu ne veuilles pas c'est possible aussi. Même si tu me manques je dirai que j'ai grandi là dessus. Donc ne me parle pas si tu n'en as pas envie... Bisous</p>
<p>Puis aussi je vais arrêter d'écrire ici voilà, ça sert à rien, je ne te donnerai peut etre pas ce papier avec le lien du site, je vais enlever la papier de la boite à gouter quand j'y penserai. Je touche plus à ce site</p>
<h2>Je t'aime ❤️</h2>
<p class="author">, Noah ❤️</p>
<div class="nav-bar">
<button class="glow-button" onclick="window.location.href='7_samedi.html'">⬅ Précédent</button>
<button class="glow-button" onclick="window.location.href='../index.html'">🏠 Accueil</button>
</div>
</div>
</body>
</html>
+144
View File
@@ -0,0 +1,144 @@
body {
margin: 0;
padding: 0;
background: linear-gradient(to right, #ffc5ee, #ff80fb);
font-family: 'Segoe UI', sans-serif;
color: #333;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
.container {
background: white;
padding: 30px;
border-radius: 20px;
box-shadow: 0 5px 20px rgba(0,0,0,0.2);
max-width: 600px;
text-align: center;
}
h1 {
font-size: 2em;
color: #e63946;
}
.intro {
font-size: 1.2em;
margin: 20px 0;
}
.nav {
list-style: none;
padding: 0;
}
.nav li {
margin: 10px 0;
}
.nav a {
text-decoration: none;
color: #ff00bf;
font-weight: bold;
transition: color 0.3s;
}
.nav a:hover {
color: #a4007b;
}
.author {
text-align: right;
text-decoration: underline;
font-style: italic; /* optionnel si tu veux une vibe douce */
font-weight: 500;
margin-top: 40px;
color: #934c7e; /* une ptite couleur romantique */
}
h2 {
color: #ff4d6d;
text-shadow: 0 0 10px #ff4d6d, 0 0 20px #ff4d6d, 0 0 30px #ff4d6d;
animation: glow 2s ease-in-out infinite;
}
@keyframes glow {
0%, 100% {
text-shadow: 0 0 10px #ff4d6d, 0 0 20px #ff4d6d, 0 0 30px #ff4d6d;
}
50% {
text-shadow: 0 0 20px #ff85a2, 0 0 30px #ff85a2, 0 0 40px #ff85a2;
}
}
.glow-button {
padding: 12px 30px;
background-color: #ff4d6d;
color: white;
border: 2px solid #cc2f4d; /* plus foncé que le fond */
border-radius: 30px;
font-size: 16px;
font-weight: bold;
cursor: pointer;
box-shadow: 0 0 10px #ff4d6d, 0 0 20px #ff4d6d;
transition: all 0.3s ease-in-out;
}
.glow-button:hover {
background-color: #ff85a2;
border-color: #cc5a7d; /* version plus foncée du hover */
box-shadow: 0 0 20px #ff85a2, 0 0 40px #ff85a2;
transform: scale(1.07);
}
@keyframes pulse {
0%, 100% {
box-shadow: 0 0 10px #ff4d6d, 0 0 20px #ff4d6d;
}
50% {
box-shadow: 0 0 20px #ff85a2, 0 0 40px #ff85a2;
}
}
.glow-button {
animation: pulse 2s infinite;
}
.button-grid {
display: flex;
flex-direction: column;
gap: 12px;
max-width: 300px;
margin: 40px auto;
}
.button-grid button {
padding: 12px 20px;
background-color: #ffd3e0;
border: 2px solid #cc2f4d;
border-radius: 25px;
color: #b4003a;
font-size: 16px;
font-weight: bold;
cursor: pointer;
transition: all 0.2s ease;
box-shadow: 0 0 6px #ffc2d4;
}
.button-grid button:hover {
background-color: #ffc2d4;
border-color: #b4003a;
color: #800026;
transform: scale(1.05);
box-shadow: 0 0 12px #ffa3bd;
}
.nav-bar {
display: flex;
justify-content: center;
gap: 20px;
margin-top: 40px;
}
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

+15
View File
@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Pour Clara 💌</title>
<link rel="stylesheet" href="style.css">
<link rel="icon" href="img/logo.png">
</head>
<body>
<div class="container">
<h1>Rendez vous 16h ici</h1>
<p class="intro"> Coucou mon amoureuse damour que jaime tant❤️. Je sais que tu n'es pas partie mais je tenais à recommencer les journaux que je t'écrivais. Le tout nouveau site arrive à 16h accompagné du journal du jour !</p>
</div>
</body>
</html>
+31
View File
@@ -0,0 +1,31 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Jour 1 💌</title>
<link rel="stylesheet" href="../style.css">
</head>
<body>
<div class="container">
<h1>Jour 1 - Dimanche 27 Avril</h1>
<p>Là cest dimanche, tu me manques déjà beaucoup… Est-ce que cest parce que cest le début ? Ou bien mon manque est bel est bien justifié. Là il est 11h30 j’écoute Shaka Ponk en t’écrivant ses mots Lets baaaanng bang baaaang (pardon jsuis a fond) Je taime trop vraiment. Je tai envoyé deux images que mon père ma envoyé, une de moi avec Mathieu et Fabien et mon père où est en mode <a href="https://www.youtube.com/watch?v=_VfwZSygTeI&t=9s">WAAAAHH</a> (ptddr cest Waluigi) et la deuxième un meme que mon père ma envoyé qui est plutot drôle mais tu les as pas vus donc jimagine que tu dors sur la route (même si je pense que cest pas a 3h de route) ou que tu as déjà commencer. </p>
<p><em>Je viens juste de réaliser mais ce que je suis en train de te faire cest ton rêve, cest juste moi qui raconte ma vie et tu adores ça🤭.</em></p>
<p>Je te fais mon programme de la journée : Tout dabord je vais aller manger cest un bon début, pourquoi pas me laver ça serait une bonne option mdrr ensuite je pense que je vais ranger tout mon bordel dans ma chambre, ma mère me ramènera ensuite chez mon père, je rangerais tout et je retrouverai ROBEEERTT !!🤭Après jirai manger chez ma mamie je lui mettrai sa Wii ça va être drôle je pense, par contre jy reste jusqu’à mardi et ça membête un peu… Je voulais déprimer tout seul mdrr</p>
<p>Je pense que je vais laisser le document ouvert sur mon PC et des fois je viendrai t’écrire un peu. En plus j'ai mis une note sur Insta en mode "J'espère qu'elle lira tout" ahah c'est trop drôle tout le monde veut savoir pourquoi</p>
<p>Re coucouuu là il est 16h j'ai pas encore fais mon gouter mais ça ne saurait tarder ! Je suis allé voir ma mère on a jouer à un jeu rigolo avec les coques de pistaches en mode "si je la mets tu fais ça" c'était marrant mais personne n'a réussi de lancer... Après on a manger vite fait en regardant Le fabuleux destin d'Amélie Poulain je l'avais déjà vu et ça m'a fait plaisir de le revoir. Pendant le film m'a mère a voulu me faire une coupe de fou, t'as du voir les buddies même en ayant retiré les élastiques mes cheveux volaient mdrr j'en pouvais plus. Après ça ma mère m'a dit de ranger ma chambre car je vais bientôt partir, mais évidemment je me suis laisser m'égarer en fait j'ai regarder tous les images de plannings de live que Matreox avait fait et j'ai tout jugé mdrr t'aurais trop kiffé m'entendre juger je pense. Là je pense que je vais essayer de faire mon planning de lives pour cette semaine du moins un brouillon, je vais live tout les jours a partir de mardi, j'espère que tu viendras au moins pour faire un petit coucou. Je t'aime mon amour, j'espère que ça se passe bien de ton côté et que tu t'amuses. Bisouuus !❤️</p>
<p>Je pense beaucoup à toi c'est pas la première fois où je me surprends à regarder le vide tout en pensant à toi quand je m'en rends compte j'ai les yeux lourds, la boule au ventre et le coeur qui bat vite, presque en train de pleurer. Ça fait qu'un jour, c'est déjà trop long. Je passe souvent dans ma galerie pour regarder des photos de nous, on est trop mignons tous les deux. J'ai encore rien mis dans mon sac mais tant de "je t'aime" à t'écrire... Je pourrais faire ça toute la journée. Ça y est je pleure, j'ai trop regardé nos photos. Je te laisse je dois ranger ma chambre❤️</p>
<p>Coucouuu jai rangé ma chambre et mes affaires et jai fais le trajet vers chez mon père je suis vite aller dans ma chambre pour voir Robert, il était la il mattendait, je lui ai fait un gros gros calin et je suis allé me doucher. Tas déjà pleuré sous la douche toi ? Cest trop bizarre, ça mest arrivé je pensais trop à toi je crois. Jai refais mes sacs pour chez ma mamie, la je suis sur le trajet, je te dirai quand jy serai. Je taime mon amour❤️</p>
<p>Coucouuu, oh j'suis content tu m'as envoyé des messages🤭et j'ai mangé c'était bon ça va. Là je suis en voc avec Julien, il est trop happy de me montrer ce qu'il a eu sur Minecraft. J'espère qu'il va me remonter le moral. Il a fait vla les trucs vraiment, je vais rajouter des mods sinon on va s'ennuyer il a tout dans le jeu mdrr. Bon je te laisse mon amour, en plus y a peut etre Eudes et Enzo qui vont rejoindre. Bisouuus !❤️</p>
<p>Coucouu, tu dors alors je vais écrire pas trop fort. Là y a une ambiance trop chill j'adore, même s'il manque toi... Tout à l'heure j'étais en appel avec Julien, Enzo et Eudes Je te l'ai dis en plus et Eudes m'à dit que Simon à dit cette phrase "En vrai si Adrian vient pas avec nous au Pal tu pourras dire à Noah de venir" AAAAHHH Je te jure j'suis trop heureux, ça veut dire que ça va mieux avec Simon et que je vais pouvoir partir en vacances avec toi et avec mes potes, trop bien ! J'ai du bouger parce que j'étais dans la chambre de ma mamie et quand je suis revenu sur mon ordi y avait plus personne... Pas grave, alors j'ai commencé l'article d'Adrian, je te jure que j'adore faire ça genre vraiment si un jour t'as la flemme j'suis là hein (stp) Du coup là j'ai fini son article. Je suis posé sur la table à manger sur un siège de bureau avec du Shaka Ponk à fond I dont give a They dont give a We dont give a fuuuuck !! - mon frère regarde un film sur la télé et je vais continuer d'écrire mon article je pense. Ou alors je vais regarder youtube parce que je suis un peu fatigué je ferai ça demain. Putain je crois que j'ai un putain de moustique qui me tourne autour, pitié sauve moi mon amour... J'ai trop hâte de dormir parce que demain y a petit dej et le petit dej chez ma mamie c'est trop trop trop booon, donc en fait je vais dodo devant youtube, j'ai ramener Robert et Monsieur Plouf et le pull pour dormir dedans mais pas le plaid parce que le chien de ma mamie à le même plaid et elle les manges donc je veux pas qu'elle mange mon plaid.</p>
<hr>
<p>Bon je pense que je te reparlerai pas de la journée (en plus il est minuit passé là (00h20) du coup je vais te faire un débrief ! Aujourd'hui c'était dur.. J'ai pu te parler ce matin... un peu... Je pense vraiment que ce moment était le meilleur de la semaine. J'espère que ta lecture te plait jusqu'ici, je sais pas encore si je vais te le faire lire quand je serai là ou pas.. J'ai même hésiter à te faire lire un jour par jour, genre dimanche prochain tu lis que cette journée là. Je sais pas trop... Je me suis beaucoup ennuyer aujourd'hui et en plus mon père et ma mamie m'ont dit que j'avais l'air perdu toute la soirée. Je leur ai pas dis que tu me manquais, je pense que si ma mamie me demande demain je lui dirai et mon père je lui dirai sans doute mardi ou mercredi, aujourd'hui c'était pas le jour, je pouvais pas en parler sans pleurer Je l'ai dis a Julien j'ai chialer... en plus a un moment je sortais enfin de ma chambre parce que je faisais que de pleurer mon père a parlé de toi je sais plus pourquoi et j'ai couru dans ma chambre pour re pleurer. Mdrr je fais pitié je t'ai fais un word ou je te dis toutes les deux ligne que je chiale... Bonne nuit mon amour❤️</p>
<h2 id="love">Je t'aime ❤️</h2>
<p class="author">Ton amoureux d'amour, Noah ❤️</p>
<div class="nav-bar">
<button class="glow-button" onclick="window.location.href='../index.html'">🏠 Accueil</button>
<button class="glow-button" onclick="window.location.href='2_lundi.html'">➡ Suivant</button>
</div>
</div>
</body>
</html>
File diff suppressed because one or more lines are too long
+22
View File
@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Jour 3 💌</title>
<link rel="stylesheet" href="../style.css">
</head>
<body>
<div class="container">
<h1>Jour 3 - Mardi 29 Avril</h1>
<p>Coucouu, alors aujourd'hui était une journée bien plus chargée que prévu du coup j'ai pas trop pu prendre la parole ici... Là il est 23h30 et il s'est passé beaucoup de trucs. Du coup je vais tout te raconter mais rapidement parce que j'ai un peu (beaucoup) envie de faire de l'ASMR.. Désolé. Donc j'ai fais mon petit dej trop bienn dehors comme hier ensuite on a tout rangé et je me suis remis sur ma Wii qui voulait pas ajouter les nouveaux jeux à la liste je cherche mais je trouve pas. En même temps ma mamie me parle d'un de ses vieil ordi (très vieux hein de 2007) qui marchait très bien mais qui est juste bloqué. Bon pas grave je lance un transfert sur la Wii et en attendant je m'occupe de cet ordi. En l'allumant l'écran n'affiche rien, j'en conclu que l'écran est HS alors je le branche à la télé et BOUM y a un truc. Alors c'est rempli de "!!" et entre ces "!!" il y a du texte mais écrit bizarrement, on aurait dit qu'il manquait des lettre ou que certaines lettre n'étaient pas les bonnes. Je me décide de réinstaller un Windows dessus tant qu'a faire j'en mets un vieux pour pas que l'ordi lag trop je choisi un Windows 7, qui n'est certes plus assuré par les mises à jour mais qui fera bien le taff. Et là ma mamie me dit que Yannick (mon tonton) avait déjà essayé de réparer l'ordi mais n'avait pas réussi donc il a démonté le disque dur pour récupérer les photos et askip il a gardé le disque... Je démonte l'ordi et effectivement il manque le disque dur.. Merde ! Je décide de tout démonter afin de vérifier que l'ordi est entier et que mon tonton ne se soit pas servit dedans (il aurait pu le faire). Et là je vois un emplacement vide.. De la RAM en plus ? Non l'emplacement est trop petit.. Je demande à ChatGPT et d'après lui c'est un emplacement IDE. Pour l'info les disques durs de nos jours sont soit des SSD (les très rapides) soit des HDD. Aujourd'hui on connecte les HDD avec des prises SATA (comme on connecterait un téléphone en Type-C) mais avant il éxistait une antiquité, la prise IDE avec des nappes. C'était la même vitesse qu'une disquette. Bref je m'égare. En tout cas il manque rien a part le disque dûr. Ma mamie m'a donc confié l'ordi pour que je m'en occupe dans la semaine (je ferai ça Samedi ou Vendredi) Entre temps le disque dur de la Wii avait tout fini je lance et là rien... Je fouille les paramètre de l'appli Wii où y a tous mes jeux, je décoche une option et ça y est ! Ça marche !! Et là on joue a Wii Sport Resort pendant que je faisais des steaks (oui pour encore manger des burgers mdrr) et c'était marrant, genre on faisait le bowling chacun son tour, c'était assez fun. On mange dehors il fait beau il fait bon c'est cool. Je vais donc à la douche (j'ai fais ton buddies🤭) Et juste après paf on rentre pour chez mon père. Sur le chemin j'ai un peu dormi, mais vite fait j'avais juste les yeux fermés et le vent sur la tête, trop confort. On arrive je mon mes affaires enfin heureux de ENFIN retrouver ma chambre putain (et aussi de retrouver ta boîte à goûter) ma mamie boit le café vite fait puis ils s'en vont. Avec mon père on règle un problème avec le serveur puis on fait un petit apéro en finissant un spéctacle qu'on avait commencé et ensuite on va voir Pierre Emmanuel Barré. Oh j'étais trop content tu m'as appelé. Son spectacle était drôle mais je t'en dirai plus en voc j'ai un peu la flemme mon amour. On est rentré on a fait burger king mdrr j'ai branché mon ordi et je t'écris ceci avant de te parler pas messages. Là tu m'en envoies j'suis trop heureux</p>
<h2 id="love">Je t'aime ❤️</h2>
<p class="author">Ton homme, Noah ❤️</p>
<div class="nav-bar">
<button class="glow-button" onclick="window.location.href='2_lundi.html'">⬅ Précédent</button>
<button class="glow-button" onclick="window.location.href='../index.html'">🏠 Accueil</button>
<button class="glow-button" onclick="window.location.href='4_mercredi.html'">➡ Suivant</button>
</div>
</div>
</body>
</html>
+29
View File
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Jour 4 💌</title>
<link rel="stylesheet" href="../style.css">
</head>
<body>
<div class="container">
<h1>Jour 4 - Mercredi 30 Avril</h1>
<p>Coucouuu ça va ? Bien dormi ? Moi oui mais il me manquait ma femme.. Je me suis levé grave tôt il était 9h, là il est 10h et je suis en pleine écriture de mon article, je charbone pour pouvoir le rendre vers midi je pense. J'ai fais a peu près 1000 mots là et j'ai pas fini encore. Avant de commencer à écrire j'ai checké vite fait un peu tout, le pdf et le site voir si Adrian ne s'était pas planté et il a oublié les mots en gras sur le site... Du coup je te le dis et là tu me dis la pire chose que tu pourrais me dire "Dis lui de le mettre" WAAAAA MAIS JE VAIS ME FAIRE SOULEVER. Bon tu sais que je ferai tout pour toi hein je vais surmonter ma peur et je vais lui dire vu que t'es occupée... Là je vais lui envoyer un message, changer de pentalon (je me serai chié dessus) prier et retourner écrire mon article. Au fait tant que j'y pense Vendredi je me fais couper les cheveux haha. Bon je te laisse je vais écrire mon testament mdrr. Bisouus !</p>
<p>Coucouu euh je t'écrire vraiment une minute après ce qu'il y a au dessus mdrr mais j'ai un soucis mon Spotify ne veux plus que j'écoute l'album Toxicity de System genre je lance l'album et ça me met une seconde de chaque son jusqu'au dernier et ça coupe, je vais mourir vraiment mdrr bon aller bisous ! Même mon père ! Est dans le coup...</p>
<img src="../img/screen_cheh_papa.png" alt="Screen de la conversation avec mon père" class="screenshot">
<p>Coucouuu ça va ? Il est 14h bientôt j'ai bien mangé, mon père a fait des pâtes et on y a mit du gruyère sauf que je sens une odeur bizarre, un fois à table. Je dis à mon père "le gruyère est pas périmé ? Mon père dit non et puis je regarde attentivement. Mdrr y avait des taches bleues dans le gruyère.. Du coup on a jetté et on s'est reservi à contre coeur... Et j'ai fini mon article je vais le mettre sur le pdf. Il fait 1600 mots donc ça va en vrai, comme celui à Célia si je dis pas de bêtises. Bref je m'y mets parce que je dois prendre une douche après ça pour aller au cinéma, je vais voir Thunderbolts* Bref Bisouuu mon amouuuur (j'ai vu que tu as fais des buddies j'suis content)</p>
<p>Coucouuu Il est 16h45 là je vais bien de fou ! J'ai tout fini sur mon article j'ai mis en page et j'ai planifié mon article. Adrian n'a toujours pas vu mon message alors qu'il a posté une note sur Insta y a 2h... On te voit en fait. Après ça j'ai pris une douche et mon frère est arrivé avec ma mamie et mon père, je les ait laisser discuter pour envoyer le message sur le groupe du Gay-Lu Times. J'ai géré de fouuu. Je t'aime mon amour, j'espère que tu es fière de moi même si tu es loin de moi... </p>
<p>Coucouu mon amour ! Je suis si bouleversé, tu m'as appelé. Mais avant je suis allé au cinéma pour voir Thunderbolts* Le film est... Je sais pas, bof je dirai. Ni nul ni bien en fait.. Après ça je suis allé au Quick et on a eu un burger gratuit, truc de fou ! Mais bon ça tu le sais déjà du coup j'ai moins de trucs à te dire ce soir... Ah si quand on rentrait au feu rouge ou y a le Legrand on avait la music A.N.U.S. de Ultra Vomit et au même moment y a un vieux aigri qui s'est arrêté à côté de nous. Mon père à monté le son progressivement en faisant exprès mdrr c'était très drole.</p>
<hr>
<p>Je t'aime mon amour, tu me manques trop je pensais que j'avais passé le cap mais j'ai pleuré quand tu as raccroché tout à l'heure. Pour te l'avouer j'avais déjà commencer avant que tu quittes (un peu comme quand on fait de l'asmr tout les deux en appel). J'aimerai trop te serrer dans mes bras, enfin ressentir la chaleur de ton corps contre le miens, goûter à tes belles et douces lèvres, désirer ton regard et observer les étoiles à travers tes yeux, caresser des belles joues et jouer avec tes soyeux cheveux. Je m'égard là.. Bref, bonne nuit mon amour je t'aime tellement</p>
<h2 id="love">Je t'aime ❤️</h2>
<p class="author">Ta crotte d'amour, Noah ❤️</p>
<div class="nav-bar">
<button class="glow-button" onclick="window.location.href='3_mardi.html'">⬅ Précédent</button>
<button class="glow-button" onclick="window.location.href='../index.html'">🏠 Accueil</button>
<button class="glow-button" onclick="window.location.href='5_jeudi.html'">➡ Suivant</button>
</div>
</div>
</body>
</html>
+29
View File
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Jour 5 💌</title>
<link rel="stylesheet" href="../style.css">
</head>
<body>
<div class="container">
<h1>Jour 5 - Jeudi 1er Mai</h1>
<p>Coucouu mon amour alors là il est 3h du matin, juste pour te dire que je vais aller me coucher mais je venais de faire le site que tu regardes là. Hehe j'suis trop fier de ce que j'ai fais c'est tout kiki, comme toi ❤️</p>
<p>Coucouuu ça va mon amour ? ❤️ J'ai bien dormi perso, je me suis levé à midi mais j'avais fais un rêve trop bizarre je me souviens pas de tout, mais je sais qu'à un moment mon frère fouille ce site là. Et à la fin je vais dans le garage de mes grands parents pour prendre une bouteille de Pepsi sauf qu'elle est chaude de fou vu qu'elle est restée au soleil, du coup je la mets au congélateur pour la refroidir un peu. Mais je remarque que depuis le début j'avais les yeux fermés et flous, tu sais comme quand tu viens de te réveiller. Du coup je cours en montant à l'étage pour me débarbouiller le visage. Et là je monte et c'est l'étage de ma maison à Feytiat, et en fait je cours parce qu'il y a quelqu'un derière moi qui veut me tuer, je sais pas qui c'est. J'arrive dans la salle de bain et je cherche un gant, j'en trouve pas du coup je fais ça avec une serviette et là le mec qui veut me tuer s'approche et me rend la bouteille de pepsi. Wesh.. Et là je me réveille... Bizarre. Bon après j'ai fais un Fifa pendant que mon père faisait à manger - c'est à dire des frites - et après ça j'ai mangé le burger en trop d'hier. On a regardé le Hot Ones avec Alain Chabat c'est trop bien. Et là il est 14h33 je sais pas ce que je vais faire, je vais surement brancher mon volant pour jouer à un jeu, pourquoi pas à BeamNG Drive. Bref je te laisse mon amour. Bisouuus</p>
<p>Je suis vraiment premier degrès en train de péter un plomb, j'en ai marre je sais pas quoi faire. J'ai littéralement fais tout ce que je pouvais faire. J'ai passé 2h sur un jeu de merde qui me plaisait pas juste parce que je savais pas quoi faire, bah j'ai vite abandonné. Et là je suis à deux doigts de casser mon écran ou de je jeter par la fenêtre, voire même de me jeter par la fenêtre. Je suis en train de devenir fou j'en peux plus. Reviens s'il te plait, je m'ennuie sans toi...</p>
<p>Euh j'allais t'écrire là mais je vois ça ⬇️ Il faut savoir que l'IA du logiciel de code prédis ce que je vais écrire. Bon là il essaye de prédire des truc nul mais wesh pourquoi il sait pour Feytiat. C'est mentionné nulle part ailleurs. Trop bizarre</p>
<img src="../img/ia.png" alt="IA qui prédit Feytiat" class="ia" width="90%">
<p>MDRRR Et là il m'a prédis la ligne pour mettre l'image en mettant le titre "IA qui prédit Feytiat" j'vais cabler</p>
<p>Bon du coup je voulais te dire. Là il est 3h du mat oui je triche on est vendredi techniquement mdrr. Je m'ennuyais trop à jouer à GT4 que du coup j'ai fais du casque et pour la vanne j'ai testé les jeux 18+. Mdrr comment c'est claqué au sol c'est juste pas pratique en fait je vois pas comment tu peux faire l'asmr en vrai en jouant à ça t'as constament les mains prises. Bref. Après ça je suis allé faire le gouter et je me suis dis que j'allais live à 20h J'ai rejoins Julien et Enzo en vocal. Enzo est parti quand j'ai lancé le live parce qu'il devait manger. Pas grave. J'ai d'abord fais du bedwars comme à l'ancienne mais mon ordi buggait trop c'est une dinguerie du coup j'ai changé pour Arcade Paradise (j'avais déjà commencé le jeu en live) Après ça Julien m'a rappelé l'existance du jeu The Exit 8 en fait ça fait un an je pense que je veux faire une vidéo dessus mais que j'y pensse pas. Du coup j'ai fais un live dessus et le concept est trop bien, y aura un montage sur ma chaine de ce gameplay. Ensuite j'ai coupé le live il était 23h30 mdrr et avec julien on a trainé sur les activités discord on a trouvé un Uno trop bien et on a joué au golf après. J'ai dis que je voulais dormir et il a lancé le tableau blanc commun mdrr. Evidemment on a fait des ref à 39-45 tu connais mdrr et après je t'écris et je vais dodo.</p>
<hr>
<p>Tu me manques trop vraiment. Aujourd'hui j'ai pas répondu à tes messages Insta et tu vas peut être trouver ça bizarre et me prendre pour un fou mais hier j'ai eu peur. Hier t'as envoyé des emojis que t'envoies jamais mais genre vraiment jamais. Ils faisaient quoi dans les récents alors ? Surtout celui qui regarde à travers ses yeux là. Tu l'envoie jamais et tu l'as envoyé à quelqu'un, je vois pas à qui ça peut être à part un amant, en mode "chut ça reste entre nous on lui dis pas"... Désolé je continue avec ça tu sais que c'est mon pire cauchemar.. Et en vrai j'ai aucune raison de pas te répondre. Je me doute trop de ce genre de choses. Mais comprends moi t'es loin si jamais tu en aurais l'envie tu aurais pu me tromper à cette distance je n'en saurai rien.. J'ai un peu déprimé aujourd'hui à cause de ça et je sais très bien que te le dire là par message n'arrangera rien parce que tu vas répéter comme d'habitude que tu n'oserai jamais faire ça. Bref désolé j'ai écris tout ça pour rien je vais effacer je pense.<br>Demain je vais chez le coiffeur à 11h fini les cheveux longs en plus après je vais acheter pleins de fringues je vais vraiment changer premier degrés ça va être cool. J'espère. En vrai j'aurai préféré faire ça avec toi, les boutiques et tout.. Bref je te laisse je vais dormir bonne nuit bisous ❤️</p>
<h2 id="love">Je t'aime ❤️</h2>
<p class="author">Ton cocu ?, Noah ❤️</p>
<div class="nav-bar">
<button class="glow-button" onclick="window.location.href='4_mercredi.html'">⬅ Précédent</button>
<button class="glow-button" onclick="window.location.href='../index.html'">🏠 Accueil</button>
<button class="glow-button" onclick="window.location.href='6_vendredi.html'">➡ Suivant</button>
</div>
</div>
</body>
</html>
+23
View File
@@ -0,0 +1,23 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Jour 6 💌</title>
<link rel="stylesheet" href="../style.css">
</head>
<body>
<div class="container">
<h1>Jour 6 - Vendredi 2 Mai</h1>
<p>Coucou mon amour ! Je vais tout t'écrire en une fois et y a plein de trucs à dire en plus ! Aujourd'hui je me suis levé et je suis allé dans la boite aux lettre récupérer le lecteur de disques durs pour pouvoir améliorer le serveur et mon ordi, je le débale je met le 2to que mon père m'a donné et je me dis que je vais mettre mon disque C dedans, remettre à 0 mon ordi pour l'ocasion. Bon j'ai que transféré là. Après ça je suis allé chez le coiffeur, elle a bien réussi ma coupe je trouve genre excatement ce à quoi je pensais. Donc nickel. Mais mon frère y est allé après et la coiffeuse à dit "Tu veux quoi comme coupe ?" Mon frère à dit "court." Bon.. ça tête ressemble à une mousse de micro mdrr, on dirait un télétubbies mais sans l'antenne bref avec mon frère on a vanné sa coupe toute la journée mdrr. Après fallait manger, moi je voulais manger à l'appart parce que flemme d'encore manger dehors. On a manger à Monsieur le Baron. Tu sais c'est le gros resto deluxe qui a pris feut pas loin du lycée. J'ai suivi mon père et mon frère à contre coeur j'en peux plus de manger des burgers mdrr. C'était bon en vrai. Après on est allés à Family Village on est allé à Inter Sport pour prendre des vetement pour moi puis à la halle puis à décatelon (on a fait une escale à boulanger pour que mon père se renseigne sur sa future télé mdrr) du coup j'ai pleins de nouveux vetements c'est trop bien. J'ai aussi pris un maillot de bain mais pas de claquette vu que je prendrais des Crocs vu que madame n'a d'yeux que pour les crocs. Je suis rentré et j'ai reset mon ordi pendant que je jouais à Mortal Kombat 1 avec mon père. J'ai galéré de fou, en fait mon ordi et sur protégé du coup pour formater bah c'est chiant. J'ai appliqué la méthode forte sauf qu'après j'avais plus rien qui marchait à part la souris et le clavier genre la luminosité de l'écran non et le wifi non plus. Après des heures de recherches j'ai rétabli le wifi le bluetooth la luminosité et d'autres trucs. J'ai mangé une petite salade et j'ai installé Need For Speed Most Wanted, la version de 2005, ce jeu est ouf pour 2005 vraiment. J'y jouais en étant en vocal avec Julien Enzo et Eudes qui est parti tôt.</p>
<hr>
<p>Je suis désolé mon amour j'ai pas osé répondre à tes messages, déjà parce que tu me les envoyais toujours au mauvais moment et en plus j'osais pas, je sais jamais quoi dire après t'avoir mis un remis, je m'en veux d'un côté mais d'un autre je trouve ça toujours aussi louche.. Désolé je force avec ça, je changerai jamais.. Bref Bisous Je t'aime mon amour dort bien❤️</p>
<h2 id="love">Je t'aime ❤️</h2>
<p class="author">Ton informaticien du dimanche, Noah ❤️</p>
<div class="nav-bar">
<button class="glow-button" onclick="window.location.href='5_jeudi.html'">⬅ Précédent</button>
<button class="glow-button" onclick="window.location.href='../index.html'">🏠 Accueil</button>
<button class="glow-button" onclick="window.location.href='7_samedi.html'">➡ Suivant</button>
</div>
</div>
</body>
</html>
+26
View File
@@ -0,0 +1,26 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Jour 7 💌</title>
<link rel="stylesheet" href="../style.css">
</head>
<body>
<div class="container">
<h1>Jour 7 - Samedi 3 Mai</h1>
<p>Coucouuu mon amouuur ! Tellement de choses à te dire alors qu'il est même pas 15h mdrr Déjà je me suis levé et jme suis fais un kiff j'ai fais le super p'tit dej comme chez ma grand mère, c'était moins bon y avait pas la vibe de chez elle mais bon. Après je me suis dis que j'allais m'attaquer à l'ordi de ma mamie justement. Alors je branche tout et là je remarque qu'elle n'a pas donné son alim... J'utilise mon alim les prises on l'air de correspondre. Sauf que, rien ça marche pas, alors je rends l'écran que j'ai volé a mon frère pour le brancher et je remets l'alim sur mon ordi. ET C'EST LE DRAME. Mon ordi ne charge plus, yess.. Je suis à ça de chialer alors je vais chercher une pince et j'essaye de remettre la tige qui n'était plus droite et là y a des étincelles mdrr. Du coup j'abandonne la mission et je dis ça à mon père. Mon père il s'énerve après ma mamie en mode "Ouais elle soule avec ses vieux trucs de merdes qui marchent pas et tout" Moi j'étais à côté en mode "ok". Du coup on va à LDLC pour voir s'ils en ont un. C'est fermé ça ouvre à 14h il est 13h20 là. Du coup on va a boulanger et on est super bien accueilli (c'est faux) par le mec qui dit "Ouais 120 balles ! Vous l'aurez Mardi en livraison ou Mercredi voire Jeudi" bon on à laissé le gars mdrr. On est aller voir les télés à Darty parce que mon père hésite à en acheter une. Et aussi pour passer le temps. Une fois qu'il est 14h on va à LDLC et là tout de suite ça change, le mec est trop sympa. Il nous donne un truc avec genre 9 embouts différents mdrr et on rentre. J'essaye.. Hallelujah !! C'est bon, ça marche ! Et du coup je t'écris là et je pense que je vais me re-regarder tous les Fast & Furious parce que j'sais pas j'ai eu envie d'un coup. Bon je te laisse bisouuuus</p>
<p>Coucouu ça va ? J'ai regardé Fast and Furious 1 j'ai aimé c'est vraiment trop bien. Je me dis qu'en vrai on pourrait les continuer tout les deux quand tu seras revenue ! Après ça j'ai rangé mes habits que j'ai acheté hier et Julien m'a proposé de venir en vocal avec Enzo et Eudes, je suis arrivé. On a fait un golf discord là et après du Gartic Phone c'était marrant. Ah oui et j'ai appris un truc. Adrian veut bien me reparler genre ça le dérangerait pas mais à une condition : que je lui donne 700 balles. Bah non mdrr il est con lui. J'ai raccroché pour aller manger j'ai mangé poulet paprika avec des patates miam. Par contre j'ai des gaz de fou genre j'arrête pas de péter et ça pue la mort en plus à chaque fois c'est infame ça me fait chier. (sans mauvais jeu de mot) Et là il est 21h40 je suis de retour en voc avec eux on va Gartic Phonner mdrr Je te laisse bisouus !</p>
<P>Bonsoiiiir je viens de faire un petit live sympa on a fait du gartic phone c'était cool. Après j'ai coupé parce qu'il était tard et de 00h à 1h30 on a jouer a des jeux discord avec julien et enzo mdrr c'était trop cool. Par contre tu m'as un peu énervé.. A absolument vouloir voir ma coupe alors que tu peux juste attendre, je voulais te faire la surprise mais t'as tout gaché. Je veux voir ta réaction moi pas juste un "Wow" qui ne répresentent que trois pauves lettres à mes yeux.. Mais non madame est trop pressée. En plus j'étais avec mes potes tu me dérangeais un peu. Plus ça va plus je me demande si ce site est une bonne idée..</P>
<hr>
<p>Aujourd'hui c'était particulier, c'était techniquement le dernier jour sans toi même si c'était chiant. Il s'est passé pas mal de trucs relou notemment l'alim de mon ordi. En plus je commence à douter de mon idée. Je suis sûr que tu vas lire tout ça mais qu'au fond tu vas t'en foutre, ou même que tu vas pas lire. Ou que tu ne trouves pas le lien du site. Puis j'écris pour rien là, il est 2h du matin faut que je dorme. Au début j'aimais bien écrire là, c'était un peu mon vide pensée, maintenant je me force un peu pour toi. Alors que tu ne liras surment pas ça. J'espère que les gateaux que je t'ai laissé étaient bon, je sais que t'aimes pas le chocolat mais j'avais rien d'autre.. Bref Bonne nuit ❤️</p>
<h2>Je t'aime ❤️</h2>
<p class="author">A quoi bon.., Noah ❤️</p>
<div class="nav-bar">
<button class="glow-button" onclick="window.location.href='6_vendredi.html'">⬅ Précédent</button>
<button class="glow-button" onclick="window.location.href='../index.html'">🏠 Accueil</button>
<button class="glow-button" onclick="window.location.href='8_dimanche.html'">➡ Suivant</button>
</div>
</div>
</body>
</html>
+21
View File
@@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Jour 8 💌</title>
<link rel="stylesheet" href="../style.css">
</head>
<body>
<div class="container">
<h1>Jour 8 - Dimanche 4 Mai</h1>
<p>Coucou mon amour, bien dormi ? Je sais que là t'es chez toi je crois (il est 17h30) mais j'ai pas eu de nouvelles, tant pis je dirai que je le mérite un peu. J'écris vite parce que je vais bientot partir pour aller chez ma mère. Aujourd'hui après m'être levé j'ai graille et j'ai fais mes sacs, mon père m'a donné un big sac qui est trop bien on peut mettre plein de trucs dedans. J'y pense un peu là mais je sais que même si on est dimanche et que c'est ton retour je pourrais pas te parler soit parce que tu auras pas le temps ou que tu m'oublira voire que tu ne veuilles pas c'est possible aussi. Même si tu me manques je dirai que j'ai grandi là dessus. Donc ne me parle pas si tu n'en as pas envie... Bisous</p>
<p>Puis aussi je vais arrêter d'écrire ici voilà, ça sert à rien, je ne te donnerai peut etre pas ce papier avec le lien du site, je vais enlever la papier de la boite à gouter quand j'y penserai. Je touche plus à ce site</p>
<h2>Je t'aime ❤️</h2>
<p class="author">, Noah ❤️</p>
<div class="nav-bar">
<button class="glow-button" onclick="window.location.href='7_samedi.html'">⬅ Précédent</button>
<button class="glow-button" onclick="window.location.href='../index.html'">🏠 Accueil</button>
</div>
</div>
</body>
</html>
+144
View File
@@ -0,0 +1,144 @@
body {
margin: 0;
padding: 0;
background: linear-gradient(to right, #ffc5ee, #ff80fb);
font-family: 'Segoe UI', sans-serif;
color: #333;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
.container {
background: white;
padding: 30px;
border-radius: 20px;
box-shadow: 0 5px 20px rgba(0,0,0,0.2);
max-width: 600px;
text-align: center;
}
h1 {
font-size: 2em;
color: #e63946;
}
.intro {
font-size: 1.2em;
margin: 20px 0;
}
.nav {
list-style: none;
padding: 0;
}
.nav li {
margin: 10px 0;
}
.nav a {
text-decoration: none;
color: #ff00bf;
font-weight: bold;
transition: color 0.3s;
}
.nav a:hover {
color: #a4007b;
}
.author {
text-align: right;
text-decoration: underline;
font-style: italic; /* optionnel si tu veux une vibe douce */
font-weight: 500;
margin-top: 40px;
color: #934c7e; /* une ptite couleur romantique */
}
h2 {
color: #ff4d6d;
text-shadow: 0 0 10px #ff4d6d, 0 0 20px #ff4d6d, 0 0 30px #ff4d6d;
animation: glow 2s ease-in-out infinite;
}
@keyframes glow {
0%, 100% {
text-shadow: 0 0 10px #ff4d6d, 0 0 20px #ff4d6d, 0 0 30px #ff4d6d;
}
50% {
text-shadow: 0 0 20px #ff85a2, 0 0 30px #ff85a2, 0 0 40px #ff85a2;
}
}
.glow-button {
padding: 12px 30px;
background-color: #ff4d6d;
color: white;
border: 2px solid #cc2f4d; /* plus foncé que le fond */
border-radius: 30px;
font-size: 16px;
font-weight: bold;
cursor: pointer;
box-shadow: 0 0 10px #ff4d6d, 0 0 20px #ff4d6d;
transition: all 0.3s ease-in-out;
}
.glow-button:hover {
background-color: #ff85a2;
border-color: #cc5a7d; /* version plus foncée du hover */
box-shadow: 0 0 20px #ff85a2, 0 0 40px #ff85a2;
transform: scale(1.07);
}
@keyframes pulse {
0%, 100% {
box-shadow: 0 0 10px #ff4d6d, 0 0 20px #ff4d6d;
}
50% {
box-shadow: 0 0 20px #ff85a2, 0 0 40px #ff85a2;
}
}
.glow-button {
animation: pulse 2s infinite;
}
.button-grid {
display: flex;
flex-direction: column;
gap: 12px;
max-width: 300px;
margin: 40px auto;
}
.button-grid button {
padding: 12px 20px;
background-color: #ffd3e0;
border: 2px solid #cc2f4d;
border-radius: 25px;
color: #b4003a;
font-size: 16px;
font-weight: bold;
cursor: pointer;
transition: all 0.2s ease;
box-shadow: 0 0 6px #ffc2d4;
}
.button-grid button:hover {
background-color: #ffc2d4;
border-color: #b4003a;
color: #800026;
transform: scale(1.05);
box-shadow: 0 0 12px #ffa3bd;
}
.nav-bar {
display: flex;
justify-content: center;
gap: 20px;
margin-top: 40px;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
+3 -3
View File
@@ -18,10 +18,10 @@
<h4>DJ amateur depuis plus de 15 ans passionné de musique depuis petit, je me ferai un plaisir de vous aMUZer sur des MUZiques de tous styles.</h4>
</header>
<hr>
<h1>Liste de karaokés - 2024</h1>
<h1>Liste de karaokés - 2026</h1>
<p>Vous pouvez télécharger la liste des karaokés entière. Ou effectuer une recherche dans la liste tout en bas.</p>
<div class="nav">
<a href="Liste karaoké 2024.pdf" target="_BLANK">Liste Karaoké 2024</a>
<a href="Liste karaoké 2026.pdf" target="_BLANK">Liste Karaoké 2026</a>
</div>
<br>
<hr>
@@ -30,7 +30,7 @@
<ul id="results"></ul>
</div>
<div class="footer">
Copyright | Whykorp® 2021-2024
Copyright | Whykorp® 2021-2026
</div>
<script src="script.js"></script>
</body>
+1 -1
View File
@@ -3,7 +3,7 @@ document.addEventListener('DOMContentLoaded', function () {
const resultsList = document.getElementById('results');
// Charger le fichier CSV
fetch('Liste karaoké 2024.csv')
fetch('Liste karaoké 2026.csv')
.then(response => response.text())
.then(data => {
const lines = data.split('\n');
+108
View File
@@ -0,0 +1,108 @@
// ################# Ces infos sont a changer en fonction de la BDD ##########################################################
let text = document.getElementById("text");
let money_input = document.getElementById("Money");
let money = { // Se rapelle de l'argent que chaque joueur a au début de la partie
"Ender": 10000,
"Sophie": 1000,
"Léo": 1000,
"Mélanie": 1000,
"Jean": 500,
"Lucie": 1000
};
let blinds = { // Se rapelle de l'argent actuellement mis en jeu par chaque joueur
"Ender": 20,
"Sophie": 30,
"Léo": 20,
"Mélanie": 20,
"Jean": 20,
"Lucie": 20
};
let player_list = ["Ender", "Sophie", "Léo", "Mélanie", "Jean", "Lucie"]; // Liste des joueurs encore en jeu a replir avec la BDD
let current_player = "Ender"; // Joueur actuel a prendre depuis la BDD
let start_blind = 20; // Blinde de départ a prendre depuis la BDD
// ##########################################################################################################################
let current_blind = 0; // Initialistation de la blinde actuelle en variable globale, mis a jour automatiquement
function ChangePlayer(player) { // Uniquement pour les tests, à remplacer par une fonction qui change de joueur dans la Boucle de jeu
current_player = player;
}
function UpdateStatus() { // Fonction mettant à jour la blinde actuel en fonction des blinds de chaque joueur
current_blind = Math.max(...Object.values(blinds));
}
function UpdateLabels() { // Fonction pour mettre à jour les labels
let pot = Object.values(blinds).reduce((a, b) => a + b, 0);
let money_labels = {}
for (key of Object.keys(money)) {
money_labels[key] = money[key] - blinds[key];
}
// Reste à faire avec ton code
}
function SeCoucher() { // fonction pour se coucher, elle vérifie si le joueur est en jeu et si sa mise actuelle est inférieure a la blinde actuel, si c'est le cas, il se couche et est retiré de la liste des joueurs encore en jeu
UpdateStatus();
if (current_blind > blinds[current_player] && player_list.includes(current_player)) { // Si le joueur est en jeu et que sa mise actuelle est inférieure a la blinde actuel, il se couche
player_list.splice(player_list.indexOf(current_player), 1);
}
UpdateLabels();
}
function Suivre() {
if (player_list.includes(current_player)) { // Si le joueur est en jeu, il suit
UpdateStatus();
if (current_blind > blinds[current_player] && money[current_player] >= current_blind) { // Si la blinde actuelle est supérieur a la sienne et qu'il est en capacité de la payer
blinds[current_player] = current_blind;
} else {
Tapis();
}
UpdateLabels();
}
}
function Relancer() {
if (player_list.includes(current_player)) { // Si le joueur est en jeu
UpdateStatus();
if (+money_input.value >= Math.max(...Object.values(money))){
Tapis();
} else {
if (money[current_player] > (current_blind) && +money_input.value <= money[current_player] - current_blind && +money_input.value > 0 && +money_input.value % (start_blind / 2) == 0) { // Si le joueur a assez d'argent pour suivre la blinde actuelle et relancer
blinds[current_player] = current_blind + +money_input.value;
}
}
UpdateLabels();
}
}
function Tapis() {
if (player_list.includes(current_player)) { // Si le joueur est en jeu, il fait tapis
UpdateStatus();
if (money[current_player] < Math.max(...Object.values(money))) { // Si le joueur n'est pas le plus riche
blinds[current_player] = money[current_player];
} else { // Si le joueur est le plus riche
let temp_money = {...money};
temp_money[current_player] = 0;
let second_most_rich = Math.max(...Object.values(temp_money));
blinds[current_player] = second_most_rich;
}
UpdateLabels();
}
}
+145
View File
@@ -0,0 +1,145 @@
/* config.css */
:root {
--poker-green: #0e5d32;
--gold: #d4af37;
--wood: #3e2723;
--white: #ffffff;
--danger: #b71c1c;
}
body {
background-color: #121212;
background-image: radial-gradient(circle, #1a1a1a 0%, #000000 100%);
color: var(--white);
font-family: 'Segoe UI', sans-serif;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
padding: 20px;
}
.container {
background-color: var(--poker-green);
padding: 30px 50px;
border-radius: 60px;
border: 12px solid var(--wood);
box-shadow: 0 0 50px rgba(0,0,0,0.9), inset 0 0 20px rgba(0,0,0,0.5);
width: 100%;
max-width: 500px;
}
h1 {
color: var(--gold);
text-align: center;
text-transform: uppercase;
font-size: 1.8rem;
margin-bottom: 30px;
text-shadow: 2px 2px 4px rgba(0,0,0,0.5);
}
label {
display: block;
color: var(--gold);
font-weight: bold;
margin-bottom: 8px;
}
input[type="number"],
input[type="text"] {
width: 100%;
padding: 12px;
margin-bottom: 20px;
border: 2px solid var(--gold);
border-radius: 8px;
background: rgba(255, 255, 255, 0.9);
box-sizing: border-box; /* Pour que le padding ne dépasse pas */
font-size: 1rem;
}
/* Style spécifique pour la ligne joueur */
.player-row {
display: flex;
gap: 10px;
margin-bottom: 10px;
align-items: center;
}
.player-row input {
margin-bottom: 0; /* On annule la marge pour l'alignement */
}
/* Boutons */
button, input[type="submit"] {
cursor: pointer;
font-weight: bold;
transition: all 0.2s;
border: none;
}
button[type="button"] {
background-color: var(--wood);
color: var(--gold);
border: 1px solid var(--gold);
padding: 10px 15px;
border-radius: 5px;
margin-bottom: 10px;
}
button[type="button"]:hover {
background-color: #4e342e;
}
/* Bouton Poubelle */
.player-row button {
background-color: var(--danger);
color: white;
border: none;
margin-bottom: 0;
}
/* Bouton Démarrer (le gros bouton doré) */
input[type="submit"] {
width: 100%;
background: linear-gradient(135deg, #d4af37 0%, #f9e27d 50%, #d4af37 100%);
color: var(--wood);
padding: 15px;
font-size: 1.2rem;
border-radius: 30px;
margin-top: 20px;
box-shadow: 0 4px 15px rgba(0,0,0,0.3);
}
input[type="submit"]:hover {
transform: scale(1.02);
filter: brightness(1.1);
}
/* Bouton Debug discret en bas */
.btn-debug {
background: transparent !important;
color: rgba(255,255,255,0.3) !important;
border: 1px dashed rgba(255,255,255,0.3) !important;
width: 100%;
margin-top: 30px;
font-size: 0.8rem;
}
.btn-back {
position: absolute;
top: 25px; /* Ajuste selon tes goûts */
left: 35px; /* Aligné avec le bord du cadre */
color: var(--gold);
text-decoration: none;
font-weight: bold;
font-size: 0.9rem;
opacity: 0.7;
transition: opacity 0.3s, transform 0.2s;
width: 20px;
}
.btn-back:hover {
opacity: 1;
transform: translateX(-5px); /* Petit effet de glissement vers la gauche */
}
+90
View File
@@ -0,0 +1,90 @@
<?php
require_once 'db.php';
?>
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>Configuration Poker</title>
<style>
.player-row { margin-bottom: 10px; }
</style>
<link rel="stylesheet" href="config.css">
</head>
<body>
<div class="container">
<button onclick="window.location.href='index.php'" class="btn-back">⬅ Accueil</button>
<h1>Configuration de la partie</h1>
<form action="start_game.php" method="post">
<label>Somme de départ :</label>
<input type="number" name="start_money" value="1000" required><br><br>
<label>Blind :</label>
<input type="number" name="blind" value="20" required><br><br>
<label>Joueurs :</label>
<div id="players_container">
<div class="player-row">
<input type="text" name="players[]" placeholder="Nom du joueur" required>
</div>
</div>
<br>
<button type="button" onclick="addPlayer()"> Ajouter un joueur</button>
<br>
<input type="submit" value="Démarrer la partie">
</form>
</div>
<script>
function addPlayer() {
// 1. On récupère le conteneur
const container = document.getElementById('players_container');
// 2. On crée une nouvelle ligne
const newRow = document.createElement('div');
newRow.className = 'player-row';
// 3. On met le HTML dedans (avec le bouton supprimer intégré)
newRow.innerHTML = `
<input type="text" name="players[]" placeholder="Nom du joueur" required>
<button type="button" onclick="removePlayer(this)">🗑️</button>
`;
// 4. On l'ajoute au conteneur
container.appendChild(newRow);
}
function removePlayer(btn) {
// On supprime le parent du bouton (la div 'player-row')
btn.parentElement.remove();
}
function deleteGame(idPartie) {
if (confirm("Êtes-vous sûr de vouloir supprimer cette partie ? Tous les joueurs associés seront effacés.")) {
// On prépare les données à envoyer
let formData = new FormData();
formData.append('game_id', idPartie);
fetch('delete_game.php', {
method: 'POST',
body: formData // On envoie l'ID au PHP
})
.then(response => response.text())
.then(data => {
alert(data);
// Au lieu de reload, on peut rediriger vers l'accueil
window.location.href = 'index.php';
})
.catch(error => {
console.error('Erreur:', error);
alert('Impossible de supprimer la partie.');
});
}
}
</script>
</body>
</html>
+14
View File
@@ -0,0 +1,14 @@
<?php
// db.php
$host = 'localhost';
$username = 'root';
$password = '';
$database = 'poker_paf';
try {
$db = new PDO("mysql:host=$host;dbname=$database;charset=utf8", $username, $password);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("Erreur de connexion : " . $e->getMessage());
}
?>
+19
View File
@@ -0,0 +1,19 @@
<?php
require_once 'db.php';
// On récupère l'ID envoyé en POST, sinon on prend la dernière partie créée
$game_id = isset($_SESSION['game_id']) ? $_SESSION['game_id'] : null;
if ($game_id) {
$stmt = $db->prepare("DELETE FROM games WHERE id = :id");
$stmt->execute([':id' => $game_id]);
} else {
// Mode "Nettoyage" : on supprime la toute dernière entrée
$stmt = $db->prepare("DELETE FROM games ORDER BY id DESC LIMIT 1");
$stmt->execute();
}
echo "La partie a bien été supprimée de la table poker_paf.";
?>
+306
View File
@@ -0,0 +1,306 @@
:root {
--poker-green: #1a5e33;
--poker-border: #3e2723;
--gold: #d4af37;
--dark-bg: #0a0a0a;
--panel-bg: #1a1a1a;
--white: #ffffff;
}
body {
background-color: var(--dark-bg);
color: var(--white);
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
margin: 0;
height: 100vh;
display: flex;
flex-direction: column;
overflow: hidden;
}
.game-container {
display: flex;
flex-direction: column;
height: 100%;
}
/* 1. Barre de stats */
.stats-bar {
background: rgba(0,0,0,0.8);
padding: 15px 30px;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 2px solid var(--poker-border);
}
.stat-item {
font-size: 1.2rem;
color: var(--gold);
}
.btn-back {
color: var(--white);
text-decoration: none;
font-size: 0.9rem;
padding: 5px 10px;
border: 1px solid var(--poker-border);
border-radius: 4px;
}
/* 2. Table de jeu */
.table-container {
flex-grow: 1;
display: flex;
justify-content: center;
align-items: center;
position: relative;
padding: 60px; /* Espace pour les noms des joueurs */
}
.poker-table {
width: 800px;
height: 400px;
background-color: var(--poker-green);
border: 15px solid var(--poker-border);
border-radius: 200px;
position: relative;
box-shadow: inset 0 0 80px rgba(0,0,0,0.8), 0 10px 30px rgba(0,0,0,0.5);
}
.pot-area {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
pointer-events: none;
}
.total-pot {
font-size: 3rem;
font-weight: bold;
color: var(--white);
text-shadow: 2px 2px 10px rgba(0,0,0,0.8);
}
.current-bet-display {
font-size: 1.2rem;
opacity: 0.8;
}
/* 3. Positionnement des joueurs (8 slots) */
.player-slot {
position: absolute;
width: 140px;
z-index: 5;
}
.player-info {
background: rgba(0, 0, 0, 0.9);
border: 2px solid var(--gold);
border-radius: 12px;
padding: 8px;
text-align: center;
position: relative;
}
.player-info.active {
box-shadow: 0 0 25px var(--gold);
transform: scale(1.1);
border-color: #fff;
}
.player-name {
display: block;
font-weight: bold;
color: var(--gold);
font-size: 0.9rem;
}
.player-money {
font-size: 1.1rem;
font-weight: bold;
}
/* Coordonnées autour de l'ovale */
.slot-0 { top: -60px; left: 50%; transform: translateX(-50%); }
.slot-1 { top: 0%; right: -110px; }
.slot-2 { top: 50%; right: -150px; transform: translateY(-50%); }
.slot-3 { bottom: 0%; right: -110px; }
.slot-4 { bottom: -60px; left: 50%; transform: translateX(-50%); }
.slot-5 { bottom: 0%; left: -110px; }
.slot-6 { top: 50%; left: -150px; transform: translateY(-50%); }
.slot-7 { top: 0%; left: -110px; }
/* 4. Panneau d'action */
.action-panel {
background: var(--panel-bg);
border-top: 4px solid var(--gold);
padding: 20px;
text-align: center;
}
.turn-info {
margin: 0 0 15px 0;
font-size: 1.2rem;
}
.action-buttons {
display: flex;
justify-content: center;
gap: 15px;
}
.btn {
padding: 15px 30px;
border-radius: 8px;
border: none;
font-weight: bold;
cursor: pointer;
text-transform: uppercase;
transition: 0.2s;
min-width: 120px;
}
.btn-fold { background: #444; color: white; }
.btn-call { background: var(--poker-green); color: white; border: 1px solid var(--gold); }
.btn-raise { background: #1e88e5; color: white; }
.btn-allin {
background: linear-gradient(45deg, #d4af37, #f9e27d);
color: #3e2723;
box-shadow: 0 4px 15px rgba(212, 175, 55, 0.4);
}
.btn:hover {
transform: translateY(-5px);
filter: brightness(1.2);
}
/* --- Styles pour le bloc Augmenter --- */
.raise-group {
display: flex;
align-items: stretch; /* Pour que l'input et le bouton aient la même hauteur */
margin: 0 10px;
}
#raise-amount {
width: 100px;
padding: 10px;
border: 2px solid var(--gold);
border-right: none; /* On retire la bordure droite pour coller au bouton */
border-radius: 8px 0 0 8px; /* Arrondi seulement à gauche */
background: #222;
color: white;
font-weight: bold;
outline: none;
}
.btn-validate {
padding: 10px 15px;
background: var(--gold);
color: var(--poker-border);
border: 2px solid var(--gold);
border-radius: 0 8px 8px 0; /* Arrondi seulement à droite */
font-weight: bold;
cursor: pointer;
text-transform: uppercase;
transition: 0.2s;
}
.btn-validate:hover {
background: #f9e27d;
filter: brightness(1.1);
}
/* Suppression des flèches par défaut de l'input number pour un look plus propre */
#raise-amount::-webkit-inner-spin-button,
#raise-amount::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
.guide-overlay {
position: fixed;
top: 20px;
left: 50%;
transform: translateX(-50%);
background: rgba(0, 0, 0, 0.9);
border: 2px solid var(--gold);
padding: 20px;
border-radius: 15px;
z-index: 1000;
text-align: center;
box-shadow: 0 0 30px rgba(212, 175, 55, 0.5);
min-width: 300px;
}
.guide-content h2 {
margin: 0 0 15px 0;
color: white;
font-size: 1.5rem;
}
#guide-btn {
background: var(--gold);
color: black;
border: none;
padding: 10px 20px;
border-radius: 5px;
font-weight: bold;
cursor: pointer;
text-transform: uppercase;
}
.dealer-badge {
position: absolute;
top: -15px;
right: -15px;
background: linear-gradient(45deg, #ffd700, #b8860b);
color: #000;
width: 30px;
height: 30px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
font-size: 14px;
border: 2px solid #fff;
box-shadow: 0 4px 8px rgba(0,0,0,0.5);
z-index: 20;
}
/* On peut aussi ajouter un effet d'ombre sur le joueur qui commence */
.player-info.is-dealer {
border-color: #ffd700;
}
.btn-next-round {
margin-top: 15px;
padding: 10px 20px;
background: var(--gold);
border: none;
border-radius: 20px;
font-weight: bold;
cursor: pointer;
box-shadow: 0 4px 10px rgba(0,0,0,0.3);
transition: 0.3s;
z-index: 10;
}
.btn-next-round:hover {
transform: scale(1.1);
background: #fff;
z-index: 10;
}
button.btn-back {
background: transparent;
border: 1px solid var(--gold);
color: var(--gold);
padding: 5px 10px;
border-radius: 5px;
font-size: 0.9rem;
transition: background 0.3s, color 0.3s;
}
+313
View File
@@ -0,0 +1,313 @@
const mysql = require('mysql2');
const connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: 'poker_paf'
});
let actualPlayerID = null; // Variable globale pour stocker l'ID du joueur actuel
let actualGameID = null; // Variable globale pour stocker l'ID de la partie actuelle
let playerChips = {}; // Objet pour stocker les jetons de chaque joueur
let playerNames = {}; // Objet pour stocker les noms de chaque joueur
let startBlind = 20; // Blinde de départ à prendre depuis la BDD
let blinds = {}; // Objet pour stocker les blinds de chaque joueur
// ############################################################################################################################
let current_blind = 0; // Initialisation de la blinde actuelle en variable globale, mis à jour automatiquement
function hangePlayer() { // Uniquement pour les tests, à remplacer par une fonction qui change de joueur dans la Boucle de jeu
// Récupération du joueur actuel depuis la base de données
connection.connect(err => {
if (err) {
console.error('Erreur de connexion : ' + err.stack);
return;
}
console.log('Connecté à MySQL avec l\'ID ' + connection.threadId);
});
const sql = "SELECT current_player_id FROM games WHERE game_id = ?";
const values = [actualGameID];
connection.query(sql, values, (error, results) => {
if (error) {
console.error('Erreur lors de la récupération du joueur actuel : ' + error.stack);
return;
}
if (results.length > 0) {
actualPlayerID = results[0].current_player_id;
console.log('Joueur actuel : ' + actualPlayerID);
} else {
console.log('Aucun résultat trouvé pour le joueur actuel.');
}
});
// Changement du joueur actuel dans la base de données (pour les tests)
// On cherche le numéro d'ID du joueur suivant l'actuel qui a le même game_id
const sql2 = "SELECT player_id FROM players WHERE game_id = ? AND player_id > ? ORDER BY player_id ASC LIMIT 1";
const values2 = [actualGameID, actualPlayerID];
connection.query(sql2, values2, (error, results) => {
if (error) {
console.error('Erreur lors de la récupération du joueur suivant : ' + error.stack);
return;
}
if (results.length > 0) {
const nextPlayerID = results[0].player_id;
const sqlUpdate = "UPDATE games SET current_player_id = ? WHERE game_id = ?";
const valuesUpdate = [nextPlayerID, actualGameID];
connection.query(sqlUpdate, valuesUpdate, (error, results) => {
if (error) {
console.error('Erreur lors de la mise à jour du joueur actuel : ' + error.stack);
return;
}
console.log('Joueur actuel mis à jour avec succès.');
});
} else {
console.log('Aucun résultat trouvé pour le joueur suivant.');
}
});
console.log('Changement de joueur : ' + player);
}
function UpdateStatus() { // Fonction mettant à jour la blinde actuel en fonction des blinds de chaque joueur
current_blind = Math.max(...Object.values(blinds));
}
function UpdateLabels() { // Fonction pour mettre à jour les labels
let pot = Object.values(blinds).reduce((a, b) => a + b, 0);
let money_labels = {}
for (key of Object.keys(money)) {
money_labels[key] = money[key] - blinds[key];
}
for (const key of Object.keys(money_labels)) {
const label = document.getElementById(`label-${key}`);
if (label) {
label.innerText = money_labels[key] + " 🪙";
}
}
}
function SeCoucher() { // fonction pour se coucher, elle vérifie si le joueur est en jeu et si sa mise actuelle est inférieure a la blinde actuel, si c'est le cas, il se couche et est retiré de la liste des joueurs encore en jeu
UpdateStatus();
if (current_blind > blinds[current_player] && player_list.includes(current_player)) { // Si le joueur est en jeu et que sa mise actuelle est inférieure a la blinde actuel, il se couche
player_list.splice(player_list.indexOf(current_player), 1);
}
UpdateLabels();
}
function Suivre() {
if (player_list.includes(current_player)) { // Si le joueur est en jeu, il suit
UpdateStatus();
if (current_blind > blinds[current_player] && money[current_player] >= current_blind) { // Si la blinde actuelle est supérieur a la sienne et qu'il est en capacité de la payer
blinds[current_player] = current_blind;
} else {
Tapis();
}
UpdateLabels();
}
}
function Relancer() {
if (player_list.includes(current_player)) { // Si le joueur est en jeu
UpdateStatus();
if (+money_input.value >= Math.max(...Object.values(money))){
Tapis();
} else {
if (money[current_player] > (current_blind) && +money_input.value <= money[current_player] - current_blind && +money_input.value > 0 && +money_input.value % (start_blind / 2) == 0) { // Si le joueur a assez d'argent pour suivre la blinde actuelle et relancer
blinds[current_player] = current_blind + +money_input.value;
}
}
UpdateLabels();
}
}
function Tapis() {
if (player_list.includes(current_player)) { // Si le joueur est en jeu, il fait tapis
UpdateStatus();
if (money[current_player] < Math.max(...Object.values(money))) { // Si le joueur n'est pas le plus riche
blinds[current_player] = money[current_player];
} else { // Si le joueur est le plus riche
let temp_money = {...money};
temp_money[current_player] = 0;
let second_most_rich = Math.max(...Object.values(temp_money));
blinds[current_player] = second_most_rich;
}
UpdateLabels();
}
}
// Fonction pour mettre à jour les jetons (Chips)
function updateChips(playerId, amount, btnElement) {
// 1. MISE À JOUR VISUELLE IMMÉDIATE (Optimiste)
const playerCard = btnElement.closest('.player-card');
const chipsDisplay = playerCard.querySelector('.player-chips');
// On sauvegarde l'ancienne valeur au cas où le serveur plante
const oldChipsValue = chipsDisplay.innerText;
let currentChips = parseInt(oldChipsValue);
let newChips = currentChips + amount;
// On change l'affichage tout de suite
chipsDisplay.innerHTML = newChips + " 🪙";
// 2. ENVOI À LA BASE DE DONNÉES
const formData = new FormData();
formData.append('player_id', playerId);
formData.append('amount', amount);
fetch('update_chips.php', {
method: 'POST',
body: formData
})
.then(response => response.text()) // On récupère en texte pour débugger
.then(text => {
try {
const data = JSON.parse(text);
if (!data.success) {
throw new Error(data.message);
}
console.log("Sync DB OK pour joueur " + playerId);
} catch (e) {
// 3. ANNULATION SI ERREUR
console.error("Erreur serveur, retour à l'ancien solde. Réponse reçue :", text);
chipsDisplay.innerHTML = oldChipsValue;
alert("Erreur de synchronisation : " + text);
}
})
.catch(error => {
chipsDisplay.innerHTML = oldChipsValue;
console.error('Erreur réseau :', error);
});
}
let currentStep = 0;
const steps = [
{ text: "Mélangez et distribuez les cartes (2 par joueur)", btn: "C'est fait !" },
{ text: "Au tour de J1 : Posez la Petite Blind", btn: "OK" },
{ text: "Au tour de J2 : Posez la Grosse Blind", btn: "OK" },
{ text: "Place au jeu ! Suivez les tours en bas.", btn: "Masquer le guide" }
];
function nextStep() {
const guideBox = document.getElementById('game-guide');
const textZone = document.getElementById('guide-text');
const btnZone = document.getElementById('guide-btn');
if (currentStep < steps.length) {
textZone.innerText = steps[currentStep].text;
btnZone.innerText = steps[currentStep].btn;
currentStep++;
} else {
// Une fois fini, on cache le guide ou on le réduit
guideBox.style.display = 'none';
// Ici, on pourrait activer les boutons d'action (Suivre, Miser...)
enableActions(true);
}
}
function enableActions(status) {
const btns = document.querySelectorAll('.btn-action, .btn-gold, .btn-validate');
btns.forEach(b => b.disabled = !status);
if(!status) {
document.querySelector('.action-panel').style.opacity = "0.5";
} else {
document.querySelector('.action-panel').style.opacity = "1";
}
}
// Au chargement, on bloque les actions tant que le guide n'est pas fini
window.onload = () => enableActions(false);
// Ta fonction deleteGame déjà existante (rappel)
function deleteGame(idPartie) {
if (confirm("Supprimer la partie ?")) {
let formData = new FormData();
formData.append('game_id', idPartie);
fetch('delete_game.php', { method: 'POST', body: formData })
.then(() => window.location.href = 'index.php');
}
}
function playerAction(type) {
const raiseInput = document.getElementById('raise-amount');
let amount = (type === 'raise') ? raiseInput.value : 0;
const gameId = new URLSearchParams(window.location.search).get('game_id');
// On prépare les données pour le PHP
let fd = new FormData();
fd.append('action', type);
fd.append('amount', amount);
fd.append('game_id', gameId);
fetch('play_action.php', { method: 'POST', body: fd })
.then(r => r.json())
.then(data => {
if (data.success) {
// --- ÉTAPE 1 : Gérer le Halo (Tu m'as dit que ça c'est OK) ---
document.querySelectorAll('.player-info').forEach(p => p.classList.remove('active'));
// On trouve la "carte" du nouveau joueur grâce à son ID
const nextPlayerSlot = document.querySelector(`[data-id="${data.next_player_id}"]`);
const nextInfoBox = nextPlayerSlot.querySelector('.player-info');
nextInfoBox.classList.add('active');
// --- ÉTAPE 2 : Mettre à jour le NOM en bas (C'est ça qui te manque) ---
// On récupère le texte du nom à l'intérieur de la carte du nouveau joueur
const nextNameRaw = nextInfoBox.querySelector('.player-name').innerText;
// On nettoie un peu le texte (pour enlever le "J1 :" par exemple)
const cleanName = nextNameRaw.split(':').pop().trim();
// On l'injecte dans le texte "Au tour de : ..."
document.getElementById('active-player-name').innerText = cleanName;
// --- ÉTAPE 3 : Mettre à jour le POT et vider l'input ---
if(data.new_pot) document.getElementById('main-pot').innerText = data.new_pot;
if(raiseInput) raiseInput.value = "";
}
})
.catch(err => console.error("Erreur action:", err));
}
function startNewRound() {
// Récupère l'ID dans l'URL (?game_id=4)
const urlParams = new URLSearchParams(window.location.search);
const gId = urlParams.get('game_id');
if (!gId) return alert("ID de partie manquant dans l'URL !");
let fd = new FormData();
fd.append('game_id', gId);
fetch('next_round.php', {
method: 'POST',
body: fd
})
.then(r => r.json())
.then(data => {
if (data.success) {
location.reload(); // On recharge pour voir le nouveau Dealer
}
})
.catch(err => console.error("Erreur bouton :", err));
}
function closeTable() {
if (confirm("Fermer la table ?")) {
// Supprimer la partie et les joueurs associés à la partie dans la db
const gameId = new URLSearchParams(window.location.search).get('game_id');
fetch('delete_game.php', {
method: 'POST',
body: new URLSearchParams({'game_id': gameId})
})
.then(() => window.location.href = 'index.php');
}
}
+222
View File
@@ -0,0 +1,222 @@
<?php
require_once 'db.php';
session_start();
// 1. Récupération de l'ID de la partie (Session ou URL)
$game_id = $_SESSION['game_id'] ?? (isset($_GET['game_id']) ? intval($_GET['game_id']) : null);
if (!$game_id) {
die("Erreur : Aucune partie trouvée. Repassez par l'accueil.");
}
// 2. Récupération des infos de la partie
$stmt = $db->prepare("SELECT * FROM games WHERE id = ?");
$stmt->execute([$game_id]);
$game = $stmt->fetch(PDO::FETCH_ASSOC);
// 3. Récupération des joueurs
$stmt = $db->prepare("SELECT * FROM players WHERE game_id = ? ORDER BY id ASC");
$stmt->execute([$game_id]);
$players = $stmt->fetchAll(PDO::FETCH_ASSOC);
// --- LE CORRECTIF POUR LE "0" ---
if (empty($players)) {
die("Erreur : Aucun joueur dans cette partie.");
}
// Si la BDD dit 0, on force le premier joueur de la liste
if ($game['current_player_id'] == 0) {
$first_player_id = $players[0]['id'];
// On met à jour la base de données TOUT DE SUITE
$update = $db->prepare("UPDATE games SET current_player_id = ? WHERE id = ?");
$update->execute([$first_player_id, $game_id]);
// On met à jour la variable locale pour que l'affichage suive
$game['current_player_id'] = $first_player_id;
}
// 4. Trouver le nom du joueur actif pour le panneau du bas
$activePlayerName = "Inconnu";
foreach ($players as $p) {
if ($p['id'] == $game['current_player_id']) {
$activePlayerName = htmlspecialchars($p['name']);
break;
}
}
?>
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>Poker PAF - La Table</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<link rel='stylesheet' type='text/css' href='game.css'>
</head>
<body>
<div class="game-container">
<div class="stats-bar">
<div class="stat-item">POT TOTAL: <strong id="main-pot"><?php echo $game['pot'] ?? 0; ?></strong> 🪙</div>
<div class="stat-item">MISE ACTUELLE: <strong id="current-bet"><?php echo $game['last_bet'] ?? 0; ?></strong></div>
<button onclick="closeTable()" class="btn-back">Fermer la table</button>
<button onclick="changePlayer()" class="btn-back">Joueur suivant</button>
<a href="index.php" class="btn-back"> Quitter</a>
</div>
<div class="table-container">
<div class="poker-table">
<div class="pot-area">
<div class="total-pot"><?php echo $game['pot'] ?? 0; ?> 🪙</div>
<div class="current-bet-display">Mise: <?php echo $game['last_bet'] ?? 0; ?></div>
<button class="btn-next-round" onclick="startNewRound()">NOUVELLE MANCHE</button>
</div>
<?php foreach ($players as $index => $p): ?>
<div class="player-slot slot-<?php echo $index; ?>" data-id="<?php echo $p['id']; ?>">
<?php
$isActive = ((int)$p['id'] === (int)$game['current_player_id']);
?>
<div class="player-info <?php echo $isActive ? 'active' : ''; ?>">
<?php if (isset($p['is_dealer']) && $p['is_dealer']): ?>
<div class="dealer-badge">D</div>
<?php endif; ?>
<span class="player-name">J<?php echo ($index + 1); ?> : <?php echo htmlspecialchars($p['name']); ?></span>
<span class="player-money"><?php echo $p['money']; ?> 🪙</span>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
<div class="action-panel">
<?php
// On recalcule le nom du joueur actif en fonction de l'ID actuel dans $game
$activePlayerName = "Personne";
foreach ($players as $p) {
if ((int)$p['id'] === (int)$game['current_player_id']) {
$activePlayerName = htmlspecialchars($p['name']);
break;
}
}
?>
<p class="turn-info">Au tour de : <strong id="active-player-name"><?php echo $activePlayerName; ?></strong></p>
<div class="action-buttons">
<button class="btn btn-fold" onclick="SeCoucher()">Se coucher</button>
<button class="btn btn-call" onclick="Suivre()">Suivre</button>
<div class="raise-group">
<input type="number" id="raise-amount" placeholder="Mise" min="0">
<button class="btn-validate" onclick="Relancer()">OK</button>
</div>
<button class="btn btn-allin" onclick="Tapis()">TAPIS</button>
</div>
</div>
</div>
<script>
// --- VARIABLES GLOBALES (Côté Navigateur) ---
let actualGameID = new URLSearchParams(window.location.search).get('game_id');
let current_blind = 0;
let blinds = {}; // On stocke les mises en cours ici
let money = {}; // On stocke le solde des joueurs ici
// --- FONCTION POUR PARLER AU SERVEUR ---
function sendActionToServer(actionType, amount = 0) {
let formData = new FormData();
formData.append('game_id', actualGameID);
formData.append('action', actionType);
formData.append('amount', amount);
fetch('play_action.php', {
method: 'POST',
body: formData
})
.then(r => r.json())
.then(data => {
if (data.success) {
// Le serveur a validé, on rafraîchit la page pour voir le halo bouger
location.reload();
}
});
}
// --- LES FONCTIONS DE JEU (Logique visuelle) ---
function Suivre() {
console.log("Action : Suivre");
sendActionToServer('call');
}
function SeCoucher() {
console.log("Action : Se coucher");
sendActionToServer('fold');
}
function Relancer() {
let val = document.getElementById('raise-amount').value;
if (val > 0) {
sendActionToServer('raise', val);
} else {
alert("Indique un montant !");
}
}
function Tapis() {
console.log("Action : TAPIS !");
sendActionToServer('allin');
}
// Fonction pour mettre à jour les étiquettes de monnaie sur l'écran
function UpdateLabels() {
for (const id in money) {
const label = document.getElementById(`label-${id}`);
if (label) {
label.innerText = (money[id] - (blinds[id] || 0)) + " 🪙";
}
}
}
function changePlayer() {
console.log("Demande de changement de joueur...");
// On utilise la fonction générique qu'on a créée ensemble
// Si tu ne l'as pas, voici le code direct :
let formData = new FormData();
formData.append('game_id', actualGameID);
formData.append('action', 'next_player'); // On envoie une action spécifique
fetch('play_action.php', {
method: 'POST',
body: formData
})
.then(r => r.json())
.then(data => {
if (data.success) {
console.log("Joueur changé avec succès !");
location.reload(); // On recharge pour voir le halo se déplacer
} else {
alert("Erreur : " + data.message);
}
})
.catch(err => console.error("Erreur fetch:", err));
}
// Au chargement, on bloque les actions tant que le guide n'est pas fini
window.onload = () => enableActions(false);
// Ta fonction deleteGame déjà existante (rappel)
function deleteGame(idPartie) {
if (confirm("Supprimer la partie ?")) {
let formData = new FormData();
formData.append('game_id', idPartie);
fetch('delete_game.php', { method: 'POST', body: formData })
.then(() => window.location.href = 'index.php');
}
}
</script>
</body>
</html>
+119
View File
@@ -0,0 +1,119 @@
/* index.css */
:root {
--poker-green: #0e5d32;
--gold: #d4af37;
--wood: #3e2723;
--white: #ffffff;
}
body {
background-color: #121212;
background-image: radial-gradient(circle, #1a1a1a 0%, #000000 100%);
color: var(--white);
font-family: 'Segoe UI', sans-serif;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
}
.welcome-container {
background-color: var(--poker-green);
padding: 50px;
border-radius: 80px;
border: 15px solid var(--wood);
box-shadow: 0 0 60px rgba(0,0,0,0.9), inset 0 0 30px rgba(0,0,0,0.5);
text-align: center;
width: 90%;
max-width: 450px;
}
h1 {
color: var(--gold);
text-transform: uppercase;
font-size: 2.2rem;
margin-bottom: 40px;
text-shadow: 3px 3px 6px rgba(0,0,0,0.7);
}
/* Style pour le lien "Démarrer une partie" */
.btn-start {
display: inline-block;
background: linear-gradient(135deg, #d4af37 0%, #f9e27d 50%, #d4af37 100%);
color: var(--wood);
text-decoration: none;
padding: 15px 30px;
font-weight: bold;
font-size: 1.2rem;
border-radius: 40px;
margin-bottom: 40px;
transition: transform 0.2s, box-shadow 0.2s;
box-shadow: 0 5px 15px rgba(0,0,0,0.4);
}
.btn-start:hover {
transform: scale(1.05);
box-shadow: 0 0 20px rgba(212, 175, 55, 0.6);
}
/* Section rejoindre */
.join-section {
border-top: 1px solid rgba(255,255,255,0.2);
padding-top: 30px;
}
label {
display: block;
color: var(--gold);
margin-bottom: 15px;
font-weight: bold;
}
input[type="text"] {
background: rgba(255, 255, 255, 0.9);
border: 2px solid var(--gold);
border-radius: 5px;
padding: 12px;
width: 60%;
font-size: 1rem;
margin-bottom: 15px;
outline: none;
text-align: center;
}
button {
background-color: var(--wood);
color: var(--gold);
border: 2px solid var(--gold);
padding: 10px 20px;
font-weight: bold;
border-radius: 5px;
cursor: pointer;
transition: background 0.3s;
}
button:hover {
background-color: #5d3a3a;
}
.btn-join-list{
background-color: transparent;
color: var(--gold);
padding-left: 12px;
border: 1px solid var(--gold);
padding: 8px 12px;
border-radius: 5px;
margin-bottom: 10px;
}
.btn-join-list:hover {
background-color: var(--gold);
color: var(--wood);
}
li {
display: flex;
justify-content: space-between;
align-items: center;
}
+58
View File
@@ -0,0 +1,58 @@
<?php
require_once 'db.php';
session_start();
session_destroy(); // On détruit la session pour supprimer l'ID de la partie en cours
// Récupérer la liste des parties en cours
$stmt = $db->query("SELECT id, start_money, start_blind FROM games ORDER BY id DESC");
$games = $stmt->fetchAll(PDO::FETCH_ASSOC);
?>
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>Poker PAF</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<link rel='stylesheet' type='text/css' media='screen' href='index.css'>
<script src='main.js'></script>
</head>
<body>
<div class="welcome-container">
<h1>Welcome to Poker PAF</h1>
<button onclick="window.location.href='config.php'">Créer une partie</button><br><br>
<label>Rejoindre une partie :</label><br>
<input type="text" id="join_game_id" placeholder="ID de la partie">
<button onclick="joinGame()">Rejoindre</button><br><br>
<h2>Parties en cours :</h2>
<div id="games_list">
<?php if (count($games) > 0): ?>
<ul>
<?php foreach ($games as $game): ?>
<li>
ID: <?php echo $game['id']; ?> -
Start Money: <?php echo $game['start_money']; ?> -
Blind: <?php echo $game['start_blind']; ?>
<button class="btn-join-list" onclick="window.location.href='game.php?game_id=<?php echo $game['id']; ?>'">Rejoindre</button>
</li>
<?php endforeach; ?>
</ul>
<?php else: ?>
<p>Aucune partie en cours.</p>
<?php endif; ?>
</div>
</div>
</body>
<script>
function joinGame() {
const gameId = document.getElementById('join_game_id').value;
if (gameId) {
// Rediriger vers une page de jeu avec l'ID en paramètre
window.location.href = `game.php?game_id=${gameId}`;
} else {
alert('Veuillez entrer un ID de partie valide.');
}
}
</html>
+40
View File
@@ -0,0 +1,40 @@
<?php
require_once 'db.php';
header('Content-Type: application/json');
$game_id = intval($_POST['game_id']);
try {
// 1. On récupère tous les joueurs
$stmt = $db->prepare("SELECT id, is_dealer FROM players WHERE game_id = ? ORDER BY id ASC");
$stmt->execute([$game_id]);
$players = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (count($players) == 0) throw new Exception("Pas de joueurs");
// 2. On trouve l'ancien dealer pour désigner le nouveau
$oldDealerIndex = -1;
foreach ($players as $index => $p) {
if ($p['is_dealer'] == 1) { $oldDealerIndex = $index; break; }
}
$nextDealerIndex = ($oldDealerIndex + 1) % count($players);
$newDealerId = $players[$nextDealerIndex]['id'];
// 3. Qui doit parler en premier ? (Normalement c'est celui après le Dealer)
$firstPlayerIndex = ($nextDealerIndex + 1) % count($players);
$firstPlayerId = $players[$firstPlayerIndex]['id'];
// 4. MISE À JOUR DE LA BDD
// On reset les dealers
$db->prepare("UPDATE players SET is_dealer = 0 WHERE game_id = ?")->execute([$game_id]);
// On met le nouveau dealer
$db->prepare("UPDATE players SET is_dealer = 1 WHERE id = ?")->execute([$newDealerId]);
// On reset le POT, la MISE et on définit le JOUEUR ACTIF
$db->prepare("UPDATE games SET pot = 0, last_bet = 0, current_player_id = ? WHERE id = ?")
->execute([$firstPlayerId, $game_id]);
echo json_encode(['success' => true]);
} catch (Exception $e) {
echo json_encode(['success' => false, 'message' => $e->getMessage()]);
}
+100
View File
@@ -0,0 +1,100 @@
{
"name": "poker-paf",
"lockfileVersion": 3,
"requires": true,
"packages": {
"node_modules/bignumber.js": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz",
"integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==",
"license": "MIT",
"engines": {
"node": "*"
}
},
"node_modules/core-util-is": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
"license": "MIT"
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"license": "ISC"
},
"node_modules/isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
"license": "MIT"
},
"node_modules/mysql": {
"version": "2.18.1",
"resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz",
"integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==",
"license": "MIT",
"dependencies": {
"bignumber.js": "9.0.0",
"readable-stream": "2.3.7",
"safe-buffer": "5.1.2",
"sqlstring": "2.3.1"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
"license": "MIT"
},
"node_modules/readable-stream": {
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"license": "MIT",
"dependencies": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"node_modules/safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"license": "MIT"
},
"node_modules/sqlstring": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz",
"integrity": "sha512-ooAzh/7dxIG5+uDik1z/Rd1vli0+38izZhGzSa34FwR7IbelPWCCKSNIl8jlL/F7ERvy8CB2jNeM1E9i9mXMAQ==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"license": "MIT",
"dependencies": {
"safe-buffer": "~5.1.0"
}
},
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"license": "MIT"
}
}
}
+266
View File
@@ -0,0 +1,266 @@
#### 9.0.0
* 27/05/2019
* For compatibility with legacy browsers, remove `Symbol` references.
#### 8.1.1
* 24/02/2019
* [BUGFIX] #222 Restore missing `var` to `export BigNumber`.
* Allow any key in BigNumber.Instance in *bignumber.d.ts*.
#### 8.1.0
* 23/02/2019
* [NEW FEATURE] #220 Create a BigNumber using `{s, e, c}`.
* [NEW FEATURE] `isBigNumber`: if `BigNumber.DEBUG` is `true`, also check that the BigNumber instance is well-formed.
* Remove `instanceof` checks; just use `_isBigNumber` to identify a BigNumber instance.
* Add `_isBigNumber` to prototype in *bignumber.mjs*.
* Add tests for BigNumber creation from object.
* Update *API.html*.
#### 8.0.2
* 13/01/2019
* #209 `toPrecision` without argument should follow `toString`.
* Improve *Use* section of *README*.
* Optimise `toString(10)`.
* Add verson number to API doc.
#### 8.0.1
* 01/11/2018
* Rest parameter must be array type in *bignumber.d.ts*.
#### 8.0.0
* 01/11/2018
* [NEW FEATURE] Add `BigNumber.sum` method.
* [NEW FEATURE]`toFormat`: add `prefix` and `suffix` options.
* [NEW FEATURE] #178 Pass custom formatting to `toFormat`.
* [BREAKING CHANGE] #184 `toFraction`: return array of BigNumbers not strings.
* [NEW FEATURE] #185 Enable overwrite of `valueOf` to prevent accidental addition to string.
* #183 Add Node.js `crypto` requirement to documentation.
* [BREAKING CHANGE] #198 Disallow signs and whitespace in custom alphabet.
* [NEW FEATURE] #188 Implement `util.inspect.custom` for Node.js REPL.
* #170 Make `isBigNumber` a type guard in *bignumber.d.ts*.
* [BREAKING CHANGE] `BigNumber.min` and `BigNumber.max`: don't accept an array.
* Update *.travis.yml*.
* Remove *bower.json*.
#### 7.2.1
* 24/05/2018
* Add `browser` field to *package.json*.
#### 7.2.0
* 22/05/2018
* #166 Correct *.mjs* file. Remove extension from `main` field in *package.json*.
#### 7.1.0
* 18/05/2018
* Add `module` field to *package.json* for *bignumber.mjs*.
#### 7.0.2
* 17/05/2018
* #165 Bugfix: upper-case letters for bases 11-36 in a custom alphabet.
* Add note to *README* regarding creating BigNumbers from Number values.
#### 7.0.1
* 26/04/2018
* #158 Fix global object variable name typo.
#### 7.0.0
* 26/04/2018
* #143 Remove global BigNumber from typings.
* #144 Enable compatibility with `Object.freeze(Object.prototype)`.
* #148 #123 #11 Only throw on a number primitive with more than 15 significant digits if `BigNumber.DEBUG` is `true`.
* Only throw on an invalid BigNumber value if `BigNumber.DEBUG` is `true`. Return BigNumber `NaN` instead.
* #154 `exponentiatedBy`: allow BigNumber exponent.
* #156 Prevent Content Security Policy *unsafe-eval* issue.
* `toFraction`: allow `Infinity` maximum denominator.
* Comment-out some excess tests to reduce test time.
* Amend indentation and other spacing.
#### 6.0.0
* 26/01/2018
* #137 Implement `APLHABET` configuration option.
* Remove `ERRORS` configuration option.
* Remove `toDigits` method; extend `precision` method accordingly.
* Remove s`round` method; extend `decimalPlaces` method accordingly.
* Remove methods: `ceil`, `floor`, and `truncated`.
* Remove method aliases: `add`, `cmp`, `isInt`, `isNeg`, `trunc`, `mul`, `neg` and `sub`.
* Rename methods: `shift` to `shiftedBy`, `another` to `clone`, `toPower` to `exponentiatedBy`, and `equals` to `isEqualTo`.
* Rename methods: add `is` prefix to `greaterThan`, `greaterThanOrEqualTo`, `lessThan` and `lessThanOrEqualTo`.
* Add methods: `multipliedBy`, `isBigNumber`, `isPositive`, `integerValue`, `maximum` and `minimum`.
* Refactor test suite.
* Add *CHANGELOG.md*.
* Rewrite *bignumber.d.ts*.
* Redo API image.
#### 5.0.0
* 27/11/2017
* #81 Don't throw on constructor call without `new`.
#### 4.1.0
* 26/09/2017
* Remove node 0.6 from *.travis.yml*.
* Add *bignumber.mjs*.
#### 4.0.4
* 03/09/2017
* Add missing aliases to *bignumber.d.ts*.
#### 4.0.3
* 30/08/2017
* Add types: *bignumber.d.ts*.
#### 4.0.2
* 03/05/2017
* #120 Workaround Safari/Webkit bug.
#### 4.0.1
* 05/04/2017
* #121 BigNumber.default to BigNumber['default'].
#### 4.0.0
* 09/01/2017
* Replace BigNumber.isBigNumber method with isBigNumber prototype property.
#### 3.1.2
* 08/01/2017
* Minor documentation edit.
#### 3.1.1
* 08/01/2017
* Uncomment `isBigNumber` tests.
* Ignore dot files.
#### 3.1.0
* 08/01/2017
* Add `isBigNumber` method.
#### 3.0.2
* 08/01/2017
* Bugfix: Possible incorrect value of `ERRORS` after a `BigNumber.another` call (due to `parseNumeric` declaration in outer scope).
#### 3.0.1
* 23/11/2016
* Apply fix for old ipads with `%` issue, see #57 and #102.
* Correct error message.
#### 3.0.0
* 09/11/2016
* Remove `require('crypto')` - leave it to the user.
* Add `BigNumber.set` as `BigNumber.config` alias.
* Default `POW_PRECISION` to `0`.
#### 2.4.0
* 14/07/2016
* #97 Add exports to support ES6 imports.
#### 2.3.0
* 07/03/2016
* #86 Add modulus parameter to `toPower`.
#### 2.2.0
* 03/03/2016
* #91 Permit larger JS integers.
#### 2.1.4
* 15/12/2015
* Correct UMD.
#### 2.1.3
* 13/12/2015
* Refactor re global object and crypto availability when bundling.
#### 2.1.2
* 10/12/2015
* Bugfix: `window.crypto` not assigned to `crypto`.
#### 2.1.1
* 09/12/2015
* Prevent code bundler from adding `crypto` shim.
#### 2.1.0
* 26/10/2015
* For `valueOf` and `toJSON`, include the minus sign with negative zero.
#### 2.0.8
* 2/10/2015
* Internal round function bugfix.
#### 2.0.6
* 31/03/2015
* Add bower.json. Tweak division after in-depth review.
#### 2.0.5
* 25/03/2015
* Amend README. Remove bitcoin address.
#### 2.0.4
* 25/03/2015
* Critical bugfix #58: division.
#### 2.0.3
* 18/02/2015
* Amend README. Add source map.
#### 2.0.2
* 18/02/2015
* Correct links.
#### 2.0.1
* 18/02/2015
* Add `max`, `min`, `precision`, `random`, `shiftedBy`, `toDigits` and `truncated` methods.
* Add the short-forms: `add`, `mul`, `sd`, `sub` and `trunc`.
* Add an `another` method to enable multiple independent constructors to be created.
* Add support for the base 2, 8 and 16 prefixes `0b`, `0o` and `0x`.
* Enable a rounding mode to be specified as a second parameter to `toExponential`, `toFixed`, `toFormat` and `toPrecision`.
* Add a `CRYPTO` configuration property so cryptographically-secure pseudo-random number generation can be specified.
* Add a `MODULO_MODE` configuration property to enable the rounding mode used by the `modulo` operation to be specified.
* Add a `POW_PRECISION` configuration property to enable the number of significant digits calculated by the power operation to be limited.
* Improve code quality.
* Improve documentation.
#### 2.0.0
* 29/12/2014
* Add `dividedToIntegerBy`, `isInteger` and `toFormat` methods.
* Remove the following short-forms: `isF`, `isZ`, `toE`, `toF`, `toFr`, `toN`, `toP`, `toS`.
* Store a BigNumber's coefficient in base 1e14, rather than base 10.
* Add fast path for integers to BigNumber constructor.
* Incorporate the library into the online documentation.
#### 1.5.0
* 13/11/2014
* Add `toJSON` and `decimalPlaces` methods.
#### 1.4.1
* 08/06/2014
* Amend README.
#### 1.4.0
* 08/05/2014
* Add `toNumber`.
#### 1.3.0
* 08/11/2013
* Ensure correct rounding of `sqrt` in all, rather than almost all, cases.
* Maximum radix to 64.
#### 1.2.1
* 17/10/2013
* Sign of zero when x < 0 and x + (-x) = 0.
#### 1.2.0
* 19/9/2013
* Throw Error objects for stack.
#### 1.1.1
* 22/8/2013
* Show original value in constructor error message.
#### 1.1.0
* 1/8/2013
* Allow numbers with trailing radix point.
#### 1.0.1
* Bugfix: error messages with incorrect method name
#### 1.0.0
* 8/11/2012
* Initial release
+23
View File
@@ -0,0 +1,23 @@
The MIT Licence.
Copyright (c) 2019 Michael Mclaughlin
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.
+268
View File
@@ -0,0 +1,268 @@
![bignumber.js](https://raw.githubusercontent.com/MikeMcl/bignumber.js/gh-pages/bignumberjs.png)
A JavaScript library for arbitrary-precision decimal and non-decimal arithmetic.
[![Build Status](https://travis-ci.org/MikeMcl/bignumber.js.svg)](https://travis-ci.org/MikeMcl/bignumber.js)
<br />
## Features
- Integers and decimals
- Simple API but full-featured
- Faster, smaller, and perhaps easier to use than JavaScript versions of Java's BigDecimal
- 8 KB minified and gzipped
- Replicates the `toExponential`, `toFixed`, `toPrecision` and `toString` methods of JavaScript's Number type
- Includes a `toFraction` and a correctly-rounded `squareRoot` method
- Supports cryptographically-secure pseudo-random number generation
- No dependencies
- Wide platform compatibility: uses JavaScript 1.5 (ECMAScript 3) features only
- Comprehensive [documentation](http://mikemcl.github.io/bignumber.js/) and test set
![API](https://raw.githubusercontent.com/MikeMcl/bignumber.js/gh-pages/API.png)
If a smaller and simpler library is required see [big.js](https://github.com/MikeMcl/big.js/).
It's less than half the size but only works with decimal numbers and only has half the methods.
It also does not allow `NaN` or `Infinity`, or have the configuration options of this library.
See also [decimal.js](https://github.com/MikeMcl/decimal.js/), which among other things adds support for non-integer powers, and performs all operations to a specified number of significant digits.
## Load
The library is the single JavaScript file *bignumber.js* (or minified, *bignumber.min.js*).
Browser:
```html
<script src='path/to/bignumber.js'></script>
```
[Node.js](http://nodejs.org):
```bash
$ npm install bignumber.js
```
```javascript
const BigNumber = require('bignumber.js');
```
ES6 module:
```javascript
import BigNumber from "./bignumber.mjs"
```
AMD loader libraries such as [requireJS](http://requirejs.org/):
```javascript
require(['bignumber'], function(BigNumber) {
// Use BigNumber here in local scope. No global BigNumber.
});
```
## Use
The library exports a single constructor function, [`BigNumber`](http://mikemcl.github.io/bignumber.js/#bignumber), which accepts a value of type Number, String or BigNumber,
```javascript
let x = new BigNumber(123.4567);
let y = BigNumber('123456.7e-3');
let z = new BigNumber(x);
x.isEqualTo(y) && y.isEqualTo(z) && x.isEqualTo(z); // true
```
To get the string value of a BigNumber use [`toString()`](http://mikemcl.github.io/bignumber.js/#toS) or [`toFixed()`](http://mikemcl.github.io/bignumber.js/#toFix). Using `toFixed()` prevents exponential notation being returned, no matter how large or small the value.
```javascript
let x = new BigNumber('1111222233334444555566');
x.toString(); // "1.111222233334444555566e+21"
x.toFixed(); // "1111222233334444555566"
```
If the limited precision of Number values is not well understood, it is recommended to create BigNumbers from String values rather than Number values to avoid a potential loss of precision.
*In all further examples below, `let`, semicolons and `toString` calls are not shown. If a commented-out value is in quotes it means `toString` has been called on the preceding expression.*
```javascript
// Precision loss from using numeric literals with more than 15 significant digits.
new BigNumber(1.0000000000000001) // '1'
new BigNumber(88259496234518.57) // '88259496234518.56'
new BigNumber(99999999999999999999) // '100000000000000000000'
// Precision loss from using numeric literals outside the range of Number values.
new BigNumber(2e+308) // 'Infinity'
new BigNumber(1e-324) // '0'
// Precision loss from the unexpected result of arithmetic with Number values.
new BigNumber(0.7 + 0.1) // '0.7999999999999999'
```
When creating a BigNumber from a Number, note that a BigNumber is created from a Number's decimal `toString()` value not from its underlying binary value. If the latter is required, then pass the Number's `toString(2)` value and specify base 2.
```javascript
new BigNumber(Number.MAX_VALUE.toString(2), 2)
```
BigNumbers can be created from values in bases from 2 to 36. See [`ALPHABET`](http://mikemcl.github.io/bignumber.js/#alphabet) to extend this range.
```javascript
a = new BigNumber(1011, 2) // "11"
b = new BigNumber('zz.9', 36) // "1295.25"
c = a.plus(b) // "1306.25"
```
Performance is better if base 10 is NOT specified for decimal values. Only specify base 10 when it is desired that the number of decimal places of the input value be limited to the current [`DECIMAL_PLACES`](http://mikemcl.github.io/bignumber.js/#decimal-places) setting.
A BigNumber is immutable in the sense that it is not changed by its methods.
```javascript
0.3 - 0.1 // 0.19999999999999998
x = new BigNumber(0.3)
x.minus(0.1) // "0.2"
x // "0.3"
```
The methods that return a BigNumber can be chained.
```javascript
x.dividedBy(y).plus(z).times(9)
x.times('1.23456780123456789e+9').plus(9876.5432321).dividedBy('4444562598.111772').integerValue()
```
Some of the longer method names have a shorter alias.
```javascript
x.squareRoot().dividedBy(y).exponentiatedBy(3).isEqualTo(x.sqrt().div(y).pow(3)) // true
x.modulo(y).multipliedBy(z).eq(x.mod(y).times(z)) // true
```
As with JavaScript's Number type, there are [`toExponential`](http://mikemcl.github.io/bignumber.js/#toE), [`toFixed`](http://mikemcl.github.io/bignumber.js/#toFix) and [`toPrecision`](http://mikemcl.github.io/bignumber.js/#toP) methods.
```javascript
x = new BigNumber(255.5)
x.toExponential(5) // "2.55500e+2"
x.toFixed(5) // "255.50000"
x.toPrecision(5) // "255.50"
x.toNumber() // 255.5
```
A base can be specified for [`toString`](http://mikemcl.github.io/bignumber.js/#toS). Performance is better if base 10 is NOT specified, i.e. use `toString()` not `toString(10)`. Only specify base 10 when it is desired that the number of decimal places be limited to the current [`DECIMAL_PLACES`](http://mikemcl.github.io/bignumber.js/#decimal-places) setting.
```javascript
x.toString(16) // "ff.8"
```
There is a [`toFormat`](http://mikemcl.github.io/bignumber.js/#toFor) method which may be useful for internationalisation.
```javascript
y = new BigNumber('1234567.898765')
y.toFormat(2) // "1,234,567.90"
```
The maximum number of decimal places of the result of an operation involving division (i.e. a division, square root, base conversion or negative power operation) is set using the `set` or `config` method of the `BigNumber` constructor.
The other arithmetic operations always give the exact result.
```javascript
BigNumber.set({ DECIMAL_PLACES: 10, ROUNDING_MODE: 4 })
x = new BigNumber(2)
y = new BigNumber(3)
z = x.dividedBy(y) // "0.6666666667"
z.squareRoot() // "0.8164965809"
z.exponentiatedBy(-3) // "3.3749999995"
z.toString(2) // "0.1010101011"
z.multipliedBy(z) // "0.44444444448888888889"
z.multipliedBy(z).decimalPlaces(10) // "0.4444444445"
```
There is a [`toFraction`](http://mikemcl.github.io/bignumber.js/#toFr) method with an optional *maximum denominator* argument
```javascript
y = new BigNumber(355)
pi = y.dividedBy(113) // "3.1415929204"
pi.toFraction() // [ "7853982301", "2500000000" ]
pi.toFraction(1000) // [ "355", "113" ]
```
and [`isNaN`](http://mikemcl.github.io/bignumber.js/#isNaN) and [`isFinite`](http://mikemcl.github.io/bignumber.js/#isF) methods, as `NaN` and `Infinity` are valid `BigNumber` values.
```javascript
x = new BigNumber(NaN) // "NaN"
y = new BigNumber(Infinity) // "Infinity"
x.isNaN() && !y.isNaN() && !x.isFinite() && !y.isFinite() // true
```
The value of a BigNumber is stored in a decimal floating point format in terms of a coefficient, exponent and sign.
```javascript
x = new BigNumber(-123.456);
x.c // [ 123, 45600000000000 ] coefficient (i.e. significand)
x.e // 2 exponent
x.s // -1 sign
```
For advanced usage, multiple BigNumber constructors can be created, each with their own independent configuration.
```javascript
// Set DECIMAL_PLACES for the original BigNumber constructor
BigNumber.set({ DECIMAL_PLACES: 10 })
// Create another BigNumber constructor, optionally passing in a configuration object
BN = BigNumber.clone({ DECIMAL_PLACES: 5 })
x = new BigNumber(1)
y = new BN(1)
x.div(3) // '0.3333333333'
y.div(3) // '0.33333'
```
For further information see the [API](http://mikemcl.github.io/bignumber.js/) reference in the *doc* directory.
## Test
The *test/modules* directory contains the test scripts for each method.
The tests can be run with Node.js or a browser. For Node.js use
$ npm test
or
$ node test/test
To test a single method, use, for example
$ node test/methods/toFraction
For the browser, open *test/test.html*.
## Build
For Node, if [uglify-js](https://github.com/mishoo/UglifyJS2) is installed
npm install uglify-js -g
then
npm run build
will create *bignumber.min.js*.
A source map will also be created in the root directory.
## Feedback
Open an issue, or email
Michael
<a href="mailto:M8ch88l@gmail.com">M8ch88l@gmail.com</a>
## Licence
The MIT Licence.
See [LICENCE](https://github.com/MikeMcl/bignumber.js/blob/master/LICENCE).
File diff suppressed because it is too large Load Diff
+2902
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2888
View File
File diff suppressed because it is too large Load Diff
+2237
View File
File diff suppressed because it is too large Load Diff
+40
View File
@@ -0,0 +1,40 @@
{
"name": "bignumber.js",
"description": "A library for arbitrary-precision decimal and non-decimal arithmetic",
"version": "9.0.0",
"keywords": [
"arbitrary",
"precision",
"arithmetic",
"big",
"number",
"decimal",
"float",
"biginteger",
"bigdecimal",
"bignumber",
"bigint",
"bignum"
],
"repository": {
"type": "git",
"url": "https://github.com/MikeMcl/bignumber.js.git"
},
"main": "bignumber",
"module": "bignumber.mjs",
"browser": "bignumber.js",
"types": "bignumber.d.ts",
"author": {
"name": "Michael Mclaughlin",
"email": "M8ch88l@gmail.com"
},
"engines": {
"node": "*"
},
"license": "MIT",
"scripts": {
"test": "node test/test",
"build": "uglifyjs bignumber.js --source-map -c -m -o bignumber.min.js"
},
"dependencies": {}
}
+19
View File
@@ -0,0 +1,19 @@
Copyright Node.js contributors. All rights reserved.
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.
+3
View File
@@ -0,0 +1,3 @@
# core-util-is
The `util.is*` functions introduced in Node v0.12.
+107
View File
@@ -0,0 +1,107 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// 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.
// NOTE: These type checking functions intentionally don't use `instanceof`
// because it is fragile and can be easily faked with `Object.create()`.
function isArray(arg) {
if (Array.isArray) {
return Array.isArray(arg);
}
return objectToString(arg) === '[object Array]';
}
exports.isArray = isArray;
function isBoolean(arg) {
return typeof arg === 'boolean';
}
exports.isBoolean = isBoolean;
function isNull(arg) {
return arg === null;
}
exports.isNull = isNull;
function isNullOrUndefined(arg) {
return arg == null;
}
exports.isNullOrUndefined = isNullOrUndefined;
function isNumber(arg) {
return typeof arg === 'number';
}
exports.isNumber = isNumber;
function isString(arg) {
return typeof arg === 'string';
}
exports.isString = isString;
function isSymbol(arg) {
return typeof arg === 'symbol';
}
exports.isSymbol = isSymbol;
function isUndefined(arg) {
return arg === void 0;
}
exports.isUndefined = isUndefined;
function isRegExp(re) {
return objectToString(re) === '[object RegExp]';
}
exports.isRegExp = isRegExp;
function isObject(arg) {
return typeof arg === 'object' && arg !== null;
}
exports.isObject = isObject;
function isDate(d) {
return objectToString(d) === '[object Date]';
}
exports.isDate = isDate;
function isError(e) {
return (objectToString(e) === '[object Error]' || e instanceof Error);
}
exports.isError = isError;
function isFunction(arg) {
return typeof arg === 'function';
}
exports.isFunction = isFunction;
function isPrimitive(arg) {
return arg === null ||
typeof arg === 'boolean' ||
typeof arg === 'number' ||
typeof arg === 'string' ||
typeof arg === 'symbol' || // ES6 symbol
typeof arg === 'undefined';
}
exports.isPrimitive = isPrimitive;
exports.isBuffer = require('buffer').Buffer.isBuffer;
function objectToString(o) {
return Object.prototype.toString.call(o);
}
+38
View File
@@ -0,0 +1,38 @@
{
"name": "core-util-is",
"version": "1.0.3",
"description": "The `util.is*` functions introduced in Node v0.12.",
"main": "lib/util.js",
"files": [
"lib"
],
"repository": {
"type": "git",
"url": "git://github.com/isaacs/core-util-is"
},
"keywords": [
"util",
"isBuffer",
"isArray",
"isNumber",
"isString",
"isRegExp",
"isThis",
"isThat",
"polyfill"
],
"author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)",
"license": "MIT",
"bugs": {
"url": "https://github.com/isaacs/core-util-is/issues"
},
"scripts": {
"test": "tap test.js",
"preversion": "npm test",
"postversion": "npm publish",
"prepublishOnly": "git push origin --follow-tags"
},
"devDependencies": {
"tap": "^15.0.9"
}
}
+16
View File
@@ -0,0 +1,16 @@
The ISC License
Copyright (c) Isaac Z. Schlueter
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
+42
View File
@@ -0,0 +1,42 @@
Browser-friendly inheritance fully compatible with standard node.js
[inherits](http://nodejs.org/api/util.html#util_util_inherits_constructor_superconstructor).
This package exports standard `inherits` from node.js `util` module in
node environment, but also provides alternative browser-friendly
implementation through [browser
field](https://gist.github.com/shtylman/4339901). Alternative
implementation is a literal copy of standard one located in standalone
module to avoid requiring of `util`. It also has a shim for old
browsers with no `Object.create` support.
While keeping you sure you are using standard `inherits`
implementation in node.js environment, it allows bundlers such as
[browserify](https://github.com/substack/node-browserify) to not
include full `util` package to your client code if all you need is
just `inherits` function. It worth, because browser shim for `util`
package is large and `inherits` is often the single function you need
from it.
It's recommended to use this package instead of
`require('util').inherits` for any code that has chances to be used
not only in node.js but in browser too.
## usage
```js
var inherits = require('inherits');
// then use exactly as the standard one
```
## note on version ~1.0
Version ~1.0 had completely different motivation and is not compatible
neither with 2.0 nor with standard node.js `inherits`.
If you are using version ~1.0 and planning to switch to ~2.0, be
careful:
* new version uses `super_` instead of `super` for referencing
superclass
* new version overwrites current prototype while old one preserves any
existing fields on it
+9
View File
@@ -0,0 +1,9 @@
try {
var util = require('util');
/* istanbul ignore next */
if (typeof util.inherits !== 'function') throw '';
module.exports = util.inherits;
} catch (e) {
/* istanbul ignore next */
module.exports = require('./inherits_browser.js');
}
+27
View File
@@ -0,0 +1,27 @@
if (typeof Object.create === 'function') {
// implementation from standard node.js 'util' module
module.exports = function inherits(ctor, superCtor) {
if (superCtor) {
ctor.super_ = superCtor
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false,
writable: true,
configurable: true
}
})
}
};
} else {
// old school shim for old browsers
module.exports = function inherits(ctor, superCtor) {
if (superCtor) {
ctor.super_ = superCtor
var TempCtor = function () {}
TempCtor.prototype = superCtor.prototype
ctor.prototype = new TempCtor()
ctor.prototype.constructor = ctor
}
}
}
+29
View File
@@ -0,0 +1,29 @@
{
"name": "inherits",
"description": "Browser-friendly inheritance fully compatible with standard node.js inherits()",
"version": "2.0.4",
"keywords": [
"inheritance",
"class",
"klass",
"oop",
"object-oriented",
"inherits",
"browser",
"browserify"
],
"main": "./inherits.js",
"browser": "./inherits_browser.js",
"repository": "git://github.com/isaacs/inherits",
"license": "ISC",
"scripts": {
"test": "tap"
},
"devDependencies": {
"tap": "^14.2.4"
},
"files": [
"inherits.js",
"inherits_browser.js"
]
}
+1
View File
@@ -0,0 +1 @@
node_modules
+4
View File
@@ -0,0 +1,4 @@
language: node_js
node_js:
- "0.8"
- "0.10"
+6
View File
@@ -0,0 +1,6 @@
test:
@node_modules/.bin/tape test.js
.PHONY: test
+60
View File
@@ -0,0 +1,60 @@
# isarray
`Array#isArray` for older browsers.
[![build status](https://secure.travis-ci.org/juliangruber/isarray.svg)](http://travis-ci.org/juliangruber/isarray)
[![downloads](https://img.shields.io/npm/dm/isarray.svg)](https://www.npmjs.org/package/isarray)
[![browser support](https://ci.testling.com/juliangruber/isarray.png)
](https://ci.testling.com/juliangruber/isarray)
## Usage
```js
var isArray = require('isarray');
console.log(isArray([])); // => true
console.log(isArray({})); // => false
```
## Installation
With [npm](http://npmjs.org) do
```bash
$ npm install isarray
```
Then bundle for the browser with
[browserify](https://github.com/substack/browserify).
With [component](http://component.io) do
```bash
$ component install juliangruber/isarray
```
## License
(MIT)
Copyright (c) 2013 Julian Gruber &lt;julian@juliangruber.com&gt;
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.
+19
View File
@@ -0,0 +1,19 @@
{
"name" : "isarray",
"description" : "Array#isArray for older browsers",
"version" : "0.0.1",
"repository" : "juliangruber/isarray",
"homepage": "https://github.com/juliangruber/isarray",
"main" : "index.js",
"scripts" : [
"index.js"
],
"dependencies" : {},
"keywords": ["browser","isarray","array"],
"author": {
"name": "Julian Gruber",
"email": "mail@juliangruber.com",
"url": "http://juliangruber.com"
},
"license": "MIT"
}
+5
View File
@@ -0,0 +1,5 @@
var toString = {}.toString;
module.exports = Array.isArray || function (arr) {
return toString.call(arr) == '[object Array]';
};
+45
View File
@@ -0,0 +1,45 @@
{
"name": "isarray",
"description": "Array#isArray for older browsers",
"version": "1.0.0",
"repository": {
"type": "git",
"url": "git://github.com/juliangruber/isarray.git"
},
"homepage": "https://github.com/juliangruber/isarray",
"main": "index.js",
"dependencies": {},
"devDependencies": {
"tape": "~2.13.4"
},
"keywords": [
"browser",
"isarray",
"array"
],
"author": {
"name": "Julian Gruber",
"email": "mail@juliangruber.com",
"url": "http://juliangruber.com"
},
"license": "MIT",
"testling": {
"files": "test.js",
"browsers": [
"ie/8..latest",
"firefox/17..latest",
"firefox/nightly",
"chrome/22..latest",
"chrome/canary",
"opera/12..latest",
"opera/next",
"safari/5.1..latest",
"ipad/6.0..latest",
"iphone/6.0..latest",
"android-browser/4.2..latest"
]
},
"scripts": {
"test": "tape test.js"
}
}
+20
View File
@@ -0,0 +1,20 @@
var isArray = require('./');
var test = require('tape');
test('is array', function(t){
t.ok(isArray([]));
t.notOk(isArray({}));
t.notOk(isArray(null));
t.notOk(isArray(false));
var obj = {};
obj[0] = true;
t.notOk(isArray(obj));
var arr = [];
arr.foo = 'bar';
t.ok(isArray(arr));
t.end();
});
+569
View File
@@ -0,0 +1,569 @@
# Changes
This file is a manually maintained list of changes for each release. Feel free
to add your changes here when sending pull requests. Also send corrections if
you spot any mistakes.
## v2.18.1 (2020-01-23)
* Fix Amazon RDS profile for yaSSL MySQL servers with 2019 CA #2292
## v2.18.0 (2020-01-21)
* Add `localInfile` option to control `LOAD DATA LOCAL INFILE`
* Add new Amazon RDS Root 2019 CA to Amazon RDS SSL profile #2280
* Add new error codes up to MySQL 5.7.29
* Fix early detection of bad callback to `connection.query`
* Support Node.js 12.x #2211
* Support Node.js 13.x
* Support non-enumerable properties in object argument to `connection.query` #2253
* Update `bignumber.js` to 9.0.0
* Update `readable-stream` to 2.3.7
## v2.17.1 (2019-04-18)
* Update `bignumber.js` to 7.2.1 #2206
- Fix npm deprecation warning
## v2.17.0 (2019-04-17)
* Add reverse type lookup for small performance gain #2170
* Fix `connection.threadId` missing on handshake failure
* Fix duplicate packet name in debug output
* Fix no password support for old password protocol
* Remove special case for handshake in determine packet code
* Small performance improvement starting command sequence
* Support auth switch in change user flow #1776
* Support Node.js 11.x
* Update `bignumber.js` to 6.0.0
## v2.16.0 (2018-07-17)
* Add Amazon RDS GovCloud SSL certificates #1876
* Add new error codes up to MySQL 5.7.21
* Include connection ID in debug output
* Support Node.js 9.x
* Support Node.js 10.x #2003 #2024 #2026 #2034
* Update Amazon RDS SSL certificates
* Update `bignumber.js` to 4.1.0
* Update `readable-stream` to 2.3.6
* Update `sqlstring` to 2.3.1
- Fix incorrectly replacing non-placeholders in SQL
## v2.15.0 (2017-10-05)
* Add new Amazon RDS ca-central-1 certificate CA to Amazon RDS SSL profile #1809
* Add new error codes up to MySQL 5.7.19
* Add `mysql.raw()` to generate pre-escaped values #877 #1821
* Fix "changedRows" to work on non-English servers #1819
* Fix error when server sends RST on `QUIT` #1811
* Fix typo in insecure auth error message
* Support `mysql_native_password` auth switch request for Azure #1396 #1729 #1730
* Update `sqlstring` to 2.3.0
- Add `.toSqlString()` escape overriding
- Small performance improvement on `escapeId`
* Update `bignumber.js` to 4.0.4
## v2.14.1 (2017-08-01)
* Fix holding first closure for lifetime of connection #1785
## v2.14.0 (2017-07-25)
* Add new Amazon RDS ap-south-1 certificate CA to Amazon RDS SSL profile #1780
* Add new Amazon RDS eu-west-2 certificate CA to Amazon RDS SSL profile #1770
* Add `sql` property to query `Error` objects #1462 #1628 #1629
* Add `sqlMessage` property to `Error` objects #1714
* Fix the MySQL 5.7.17 error codes
* Support Node.js 8.x
* Update `bignumber.js` to 4.0.2
* Update `readable-stream` to 2.3.3
* Use `safe-buffer` for improved Buffer API
## v2.13.0 (2017-01-24)
* Accept regular expression as pool cluster pattern #1572
* Accept wildcard anywhere in pool cluster pattern #1570
* Add `acquire` and `release` events to `Pool` for tracking #1366 #1449 #1528 #1625
* Add new error codes up to MySQL 5.7.17
* Fix edge cases when determing Query result packets #1547
* Fix memory leak when using long-running domains #1619 #1620
* Remove unnecessary buffer copies when receiving large packets
* Update `bignumber.js` to 3.1.2
* Use a simple buffer list to improve performance #566 #1590
## v2.12.0 (2016-11-02)
* Accept array of type names to `dateStrings` option #605 #1481
* Add `query` method to `PoolNamespace` #1256 #1505 #1506
- Used as `cluster.of(...).query(...)`
* Add new error codes up to MySQL 5.7.16
* Fix edge cases writing certain length coded values
* Fix typo in `HANDSHAKE_NO_SSL_SUPPORT` error message #1534
* Support Node.js 7.x
* Update `bignumber.js` to 2.4.0
* Update `sqlstring` to 2.2.0
- Accept numbers and other value types in `escapeId`
- Escape invalid `Date` objects as `NULL`
- Run `buffer.toString()` through escaping
## v2.11.1 (2016-06-07)
* Fix writing truncated packets starting with large string/buffer #1438
## v2.11.0 (2016-06-06)
* Add `POOL_CLOSED` code to "Pool is closed." error
* Add `POOL_CONNLIMIT` code to "No connections available." error #1332
* Bind underlying connections in pool to same domain as pool #1242
* Bind underlying socket to same domain as connection #1243
* Fix allocation errors receiving many result rows #918 #1265 #1324 #1415
* Fix edge cases constructing long stack traces #1387
* Fix handshake inactivity timeout on Node.js v4.2.0 #1223 #1236 #1239 #1240 #1241 #1252
* Fix Query stream to emit close after ending #1349 #1350
* Fix type cast for BIGINT columns when number is negative #1376
* Performance improvements for array/object escaping in SqlString #1331
* Performance improvements for formatting in SqlString #1431
* Performance improvements for string escaping in SqlString #1390
* Performance improvements for writing packets to network
* Support Node.js 6.x
* Update `bignumber.js` to 2.3.0
* Update `readable-stream` to 1.1.14
* Use the `sqlstring` module for SQL escaping and formatting
## v2.10.2 (2016-01-12)
* Fix exception/hang from certain SSL connection errors #1153
* Update `bignumber.js` to 2.1.4
## v2.10.1 (2016-01-11)
* Add new Amazon RDS ap-northeast-2 certificate CA to Amazon RDS SSL profile #1329
## v2.10.0 (2015-12-15)
* Add new error codes up to MySQL 5.7.9 #1294
* Add new JSON type constant #1295
* Add types for fractional seconds support
* Fix `connection.destroy()` on pool connection creating sequences #1291
* Fix error code 139 `HA_ERR_TO_BIG_ROW` to be `HA_ERR_TOO_BIG_ROW`
* Fix error when call site error is missing stack #1179
* Fix reading password from MySQL URL that has bare colon #1278
* Handle MySQL servers not closing TCP connection after QUIT -> OK exchange #1277
* Minor SqlString Date to string performance improvement #1233
* Support Node.js 4.x
* Support Node.js 5.x
* Update `bignumber.js` to 2.1.2
## v2.9.0 (2015-08-19)
* Accept the `ciphers` property in connection `ssl` option #1185
* Fix bad timezone conversion from `Date` to string for certain times #1045 #1155
## v2.8.0 (2015-07-13)
* Add `connect` event to `Connection` #1129
* Default `timeout` for `connection.end` to 30 seconds #1057
* Fix a sync callback when sequence enqueue fails #1147
* Provide static require analysis
* Re-use connection from pool after `conn.changeUser` is used #837 #1088
## v2.7.0 (2015-05-27)
* Destroy/end connections removed from the pool on error
* Delay implied connect until after `.query` argument validation
* Do not remove connections with non-fatal errors from the pool
* Error early if `callback` argument to `.query` is not a function #1060
* Lazy-load modules from many entry point; reduced memory use
## v2.6.2 (2015-04-14)
* Fix `Connection.createQuery` for no SQL #1058
* Update `bignumber.js` to 2.0.7
## v2.6.1 (2015-03-26)
* Update `bignumber.js` to 2.0.5 #1037 #1038
## v2.6.0 (2015-03-24)
* Add `poolCluster.remove` to remove pools from the cluster #1006 #1007
* Add optional callback to `poolCluster.end`
* Add `restoreNodeTimeout` option to `PoolCluster` #880 #906
* Fix LOAD DATA INFILE handling in multiple statements #1036
* Fix `poolCluster.add` to throw if `PoolCluster` has been closed
* Fix `poolCluster.add` to throw if `id` already defined
* Fix un-catchable error from `PoolCluster` when MySQL server offline #1033
* Improve speed formatting SQL #1019
* Support io.js
## v2.5.5 (2015-02-23)
* Store SSL presets in JS instead of JSON #959
* Support Node.js 0.12
* Update Amazon RDS SSL certificates #1001
## v2.5.4 (2014-12-16)
* Fix error if falsy error thrown in callback handler #960
* Fix various error code strings #954
## v2.5.3 (2014-11-06)
* Fix `pool.query` streaming interface not emitting connection errors #941
## v2.5.2 (2014-10-10)
* Fix receiving large text fields #922
## v2.5.1 (2014-09-22)
* Fix `pool.end` race conditions #915
* Fix `pool.getConnection` race conditions
## v2.5.0 (2014-09-07)
* Add code `POOL_ENQUEUELIMIT` to error reaching `queueLimit`
* Add `enqueue` event to pool #716
* Add `enqueue` event to protocol and connection #381
* Blacklist unsupported connection flags #881
* Make only column names enumerable in `RowDataPacket` #549 #895
* Support Node.js 0.6 #718
## v2.4.3 (2014-08-25)
* Fix `pool.query` to use `typeCast` configuration
## v2.4.2 (2014-08-03)
* Fix incorrect sequence packet errors to be catchable #867
* Fix stray protocol packet errors to be catchable #867
* Fix timing of fatal protocol errors bubbling to user #879
## v2.4.1 (2014-07-17)
* Fix `pool.query` not invoking callback on connection error #872
## v2.4.0 (2014-07-13)
* Add code `POOL_NOEXIST` in PoolCluster error #846
* Add `acquireTimeout` pool option to specify a timeout for acquiring a connection #821 #854
* Add `connection.escapeId`
* Add `pool.escapeId`
* Add `timeout` option to all sequences #855 #863
* Default `connectTimeout` to 10 seconds
* Fix domain binding with `conn.connect`
* Fix `packet.default` to actually be a string
* Fix `PARSER_*` errors to be catchable
* Fix `PROTOCOL_PACKETS_OUT_OF_ORDER` error to be catchable #844
* Include packets that failed parsing under `debug`
* Return `Query` object from `pool.query` like `conn.query` #830
* Use `EventEmitter.listenerCount` when possible for faster counting
## v2.3.2 (2014-05-29)
* Fix pool leaking connections after `conn.changeUser` #833
## v2.3.1 (2014-05-26)
* Add database errors to error constants
* Add global errors to error constants
* Throw when calling `conn.release` multiple times #824 #827
* Update known error codes
## v2.3.0 (2014-05-16)
* Accept MySQL charset (like `UTF8` or `UTF8MB4`) in `charset` option #808
* Accept pool options in connection string to `mysql.createPool` #811
* Clone connection config for new pool connections
* Default `connectTimeout` to 2 minutes
* Reject unauthorized SSL connections (use `ssl.rejectUnauthorized` to override) #816
* Return last error when PoolCluster exhausts connection retries #818
* Remove connection from pool after `conn.changeUser` is released #806
* Throw on unknown SSL profile name #817
* User newer TLS functions when available #809
## v2.2.0 (2014-04-27)
* Use indexOf instead of for loops removing conn from pool #611
* Make callback to `pool.query` optional like `conn.query` #585
* Prevent enqueuing sequences after fatal error #400
* Fix geometry parser for empty fields #742
* Accept lower-case charset option
* Throw on unknown charset option #789
* Update known charsets
* Remove console.warn from PoolCluster #744
* Fix `pool.end` to handle queued connections #797
* Fix `pool.releaseConnection` to keep connection queue flowing #797
* Fix SSL handshake error to be catchable #800
* Add `connection.threadId` to get MySQL connection ID #602
* Ensure `pool.getConnection` retrieves good connections #434 #557 #778
* Fix pool cluster wildcard matching #627
* Pass query values through to `SqlString.format` #590
## v2.1.1 (2014-03-13)
* fix authentication w/password failure for node.js 0.10.5 #746 #752
* fix authentication w/password TypeError exception for node.js 0.10.0-0.10.4 #747
* fix specifying `values` in `conn.query({...}).on(...)` pattern #755
* fix long stack trace to include the `pool.query(...)` call #715
## v2.1.0 (2014-02-20)
* crypto.createHash fix for node.js < 11 #735
* Add `connectTimeout` option to specify a timeout for establishing a connection #726
* SSL support #481
## v2.0.1
* internal parser speed improvement #702
* domains support
* 'trace' connection option to control if long stack traces are generated #713 #710 #439
## v2.0.0 (2014-01-09)
* stream improvements:
- node 0.8 support #692
- Emit 'close' events from query streams #688
* encoding fix in streaming LOAD DATA LOCAL INFILE #670
* Doc improvements
## v2.0.0-rc2 (2013-12-07)
* Streaming LOAD DATA LOCAL INFILE #668
* Doc improvements
## v2.0.0-rc1 (2013-11-30)
* Transaction support
* Expose SqlString.format as mysql.format()
* Many bug fixes
* Better support for dates in local time zone
* Doc improvements
## v2.0.0-alpha9 (2013-08-27)
* Add query to pool to execute queries directly using the pool
* Add `sqlState` property to `Error` objects #556
* Pool option to set queue limit
* Pool sends 'connection' event when it opens a new connection
* Added stringifyObjects option to treat input as strings rather than objects (#501)
* Support for poolClusters
* Datetime improvements
* Bug fixes
## v2.0.0-alpha8 (2013-04-30)
* Switch to old mode for Streams 2 (Node.js v 0.10.x)
* Add stream method to Query Wraps events from the query object into a node v0.10.x Readable stream
* DECIMAL should also be treated as big number
* Removed slow unnecessary stack access
* Added charsets
* Added bigNumberStrings option for forcing BIGINT columns as strings
* Changes date parsing to return String if not a valid JS Date
* Adds support for ?? escape sequence to escape identifiers
* Changes Auth.token() to force password to be in binary, not utf8 (#378)
* Restrict debugging by packet types
* Add 'multipleStatements' option tracking to ConnectionConfig. Fixes GH-408
* Changes Pool to handle 'error' events and dispose connection
* Allows db.query({ sql: "..." }, [ val1, ... ], cb); (#390)
* Improved documentation
* Bug fixes
## v2.0.0-alpha7 (2013-02-03)
* Add connection pooling (#351)
## v2.0.0-alpha6 (2013-01-31)
* Add supportBigNumbers option (#381, #382)
* Accept prebuilt Query object in connection.query
* Bug fixes
## v2.0.0-alpha5 (2012-12-03)
* Add mysql.escapeId to escape identifiers (closes #342)
* Allow custom escaping mode (config.queryFormat)
* Convert DATE columns to configured timezone instead of UTC (#332)
* Convert LONGLONG and NEWDECIMAL to numbers (#333)
* Fix Connection.escape() (fixes #330)
* Changed Readme ambiguity about custom type cast fallback
* Change typeCast to receive Connection instead of Connection.config.timezone
* Fix drain event having useless err parameter
* Add Connection.statistics() back from v0.9
* Add Connection.ping() back from v0.9
## v2.0.0-alpha4 (2012-10-03)
* Fix some OOB errors on resume()
* Fix quick pause() / resume() usage
* Properly parse host denied / similar errors
* Add Connection.ChangeUser functionality
* Make sure changeUser errors are fatal
* Enable formatting nested arrays for bulk inserts
* Add Connection.escape functionality
* Renamed 'close' to 'end' event
* Return parsed object instead of Buffer for GEOMETRY types
* Allow nestTables inline (using a string instead of a boolean)
* Check for ZEROFILL_FLAG and format number accordingly
* Add timezone support (default: local)
* Add custom typeCast functionality
* Export mysql column types
* Add connection flags functionality (#237)
* Exports drain event when queue finishes processing (#272, #271, #306)
## v2.0.0-alpha3 (2012-06-12)
* Implement support for `LOAD DATA LOCAL INFILE` queries (#182).
* Support OLD\_PASSWORD() accounts like 0.9.x did. You should still upgrade any
user accounts in your your MySQL user table that has short (16 byte) Password
values. Connecting to those accounts is not secure. (#204)
* Ignore function values when escaping objects, allows to use RowDataPacket
objects as query arguments. (Alex Gorbatchev, #213)
* Handle initial error packets from server such as `ER_HOST_NOT_PRIVILEGED`.
* Treat `utf8\_bin` as a String, not Buffer. (#214)
* Handle empty strings in first row column value. (#222)
* Honor Connection#nestTables setting for queries. (#221)
* Remove `CLIENT_INTERACTIVE` flag from config. Improves #225.
* Improve docs for connections settings.
* Implement url string support for Connection configs.
## v2.0.0-alpha2 (2012-05-31)
* Specify escaping before for NaN / Infinity (they are as unquoted constants).
* Support for unix domain socket connections (use: {socketPath: '...'}).
* Fix type casting for NULL values for Date/Number fields
* Add `fields` argument to `query()` as well as `'fields'` event. This is
similar to what was available in 0.9.x.
* Support connecting to the sphinx searchd daemon as well as MariaDB (#199).
* Implement long stack trace support, will be removed / disabled if the node
core ever supports it natively.
* Implement `nestTables` option for queries, allows fetching JOIN result sets
with overlapping column names.
* Fix ? placeholder mechanism for values containing '?' characters (#205).
* Detect when `connect()` is called more than once on a connection and provide
the user with a good error message for it (#204).
* Switch to `UTF8_GENERAL_CI` (previously `UTF8_UNICODE_CI`) as the default
charset for all connections to avoid strange MySQL performance issues (#200),
and also make the charset user configurable.
* Fix BLOB type casting for `TINY_BLOB`, `MEDIUM_BLOB` and `LONG_BLOB`.
* Add support for sending and receiving large (> 16 MB) packets.
## v2.0.0-alpha (2012-05-15)
This release is a rewrite. You should carefully test your application after
upgrading to avoid problems. This release features many improvements, most
importantly:
* ~5x faster than v0.9.x for parsing query results
* Support for pause() / resume() (for streaming rows)
* Support for multiple statement queries
* Support for stored procedures
* Support for transactions
* Support for binary columns (as blobs)
* Consistent & well documented error handling
* A new Connection class that has well defined semantics (unlike the old Client class).
* Convenient escaping of objects / arrays that allows for simpler query construction
* A significantly simpler code base
* Many bug fixes & other small improvements (Closed 62 out of 66 GitHub issues)
Below are a few notes on the upgrade process itself:
The first thing you will run into is that the old `Client` class is gone and
has been replaced with a less ambitious `Connection` class. So instead of
`mysql.createClient()`, you now have to:
```js
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'me',
password : 'secret',
});
connection.query('SELECT 1', function(err, rows) {
if (err) throw err;
console.log('Query result: ', rows);
});
connection.end();
```
The new `Connection` class does not try to handle re-connects, please study the
`Server disconnects` section in the new Readme.
Other than that, the interface has stayed very similar. Here are a few things
to check out so:
* BIGINT's are now cast into strings
* Binary data is now cast to buffers
* The `'row'` event on the `Query` object is now called `'result'` and will
also be emitted for queries that produce an OK/Error response.
* Error handling is consistently defined now, check the Readme
* Escaping has become more powerful which may break your code if you are
currently using objects to fill query placeholders.
* Connections can now be established explicitly again, so you may wish to do so
if you want to handle connection errors specifically.
That should be most of it, if you run into anything else, please send a patch
or open an issue to improve this document.
## v0.9.6 (2012-03-12)
* Escape array values so they produce sql arrays (Roger Castells, Colin Smith)
* docs: mention mysql transaction stop gap solution (Blake Miner)
* docs: Mention affectedRows in FAQ (Michael Baldwin)
## v0.9.5 (2011-11-26)
* Fix #142 Driver stalls upon reconnect attempt that's immediately closed
* Add travis build
* Switch to urun as a test runner
* Switch to utest for unit tests
* Remove fast-or-slow dependency for tests
* Split integration tests into individual files again
## v0.9.4 (2011-08-31)
* Expose package.json as `mysql.PACKAGE` (#104)
## v0.9.3 (2011-08-22)
* Set default `client.user` to root
* Fix #91: Client#format should not mutate params array
* Fix #94: TypeError in client.js
* Parse decimals as string (vadimg)
## v0.9.2 (2011-08-07)
* The underlaying socket connection is now managed implicitly rather than explicitly.
* Check the [upgrading guide][] for a full list of changes.
## v0.9.1 (2011-02-20)
* Fix issue #49 / `client.escape()` throwing exceptions on objects. (Nick Payne)
* Drop < v0.4.x compatibility. From now on you need node v0.4.x to use this module.
## Older releases
These releases were done before maintaining this file:
* [v0.9.0](https://github.com/mysqljs/mysql/compare/v0.8.0...v0.9.0)
(2011-01-04)
* [v0.8.0](https://github.com/mysqljs/mysql/compare/v0.7.0...v0.8.0)
(2010-10-30)
* [v0.7.0](https://github.com/mysqljs/mysql/compare/v0.6.0...v0.7.0)
(2010-10-14)
* [v0.6.0](https://github.com/mysqljs/mysql/compare/v0.5.0...v0.6.0)
(2010-09-28)
* [v0.5.0](https://github.com/mysqljs/mysql/compare/v0.4.0...v0.5.0)
(2010-09-17)
* [v0.4.0](https://github.com/mysqljs/mysql/compare/v0.3.0...v0.4.0)
(2010-09-02)
* [v0.3.0](https://github.com/mysqljs/mysql/compare/v0.2.0...v0.3.0)
(2010-08-25)
* [v0.2.0](https://github.com/mysqljs/mysql/compare/v0.1.0...v0.2.0)
(2010-08-22)
* [v0.1.0](https://github.com/mysqljs/mysql/commits/v0.1.0)
(2010-08-22)
+19
View File
@@ -0,0 +1,19 @@
Copyright (c) 2012 Felix Geisendörfer (felix@debuggable.com) and contributors
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.
+1548
View File
File diff suppressed because it is too large Load Diff
+161
View File
@@ -0,0 +1,161 @@
var Classes = Object.create(null);
/**
* Create a new Connection instance.
* @param {object|string} config Configuration or connection string for new MySQL connection
* @return {Connection} A new MySQL connection
* @public
*/
exports.createConnection = function createConnection(config) {
var Connection = loadClass('Connection');
var ConnectionConfig = loadClass('ConnectionConfig');
return new Connection({config: new ConnectionConfig(config)});
};
/**
* Create a new Pool instance.
* @param {object|string} config Configuration or connection string for new MySQL connections
* @return {Pool} A new MySQL pool
* @public
*/
exports.createPool = function createPool(config) {
var Pool = loadClass('Pool');
var PoolConfig = loadClass('PoolConfig');
return new Pool({config: new PoolConfig(config)});
};
/**
* Create a new PoolCluster instance.
* @param {object} [config] Configuration for pool cluster
* @return {PoolCluster} New MySQL pool cluster
* @public
*/
exports.createPoolCluster = function createPoolCluster(config) {
var PoolCluster = loadClass('PoolCluster');
return new PoolCluster(config);
};
/**
* Create a new Query instance.
* @param {string} sql The SQL for the query
* @param {array} [values] Any values to insert into placeholders in sql
* @param {function} [callback] The callback to use when query is complete
* @return {Query} New query object
* @public
*/
exports.createQuery = function createQuery(sql, values, callback) {
var Connection = loadClass('Connection');
return Connection.createQuery(sql, values, callback);
};
/**
* Escape a value for SQL.
* @param {*} value The value to escape
* @param {boolean} [stringifyObjects=false] Setting if objects should be stringified
* @param {string} [timeZone=local] Setting for time zone to use for Date conversion
* @return {string} Escaped string value
* @public
*/
exports.escape = function escape(value, stringifyObjects, timeZone) {
var SqlString = loadClass('SqlString');
return SqlString.escape(value, stringifyObjects, timeZone);
};
/**
* Escape an identifier for SQL.
* @param {*} value The value to escape
* @param {boolean} [forbidQualified=false] Setting to treat '.' as part of identifier
* @return {string} Escaped string value
* @public
*/
exports.escapeId = function escapeId(value, forbidQualified) {
var SqlString = loadClass('SqlString');
return SqlString.escapeId(value, forbidQualified);
};
/**
* Format SQL and replacement values into a SQL string.
* @param {string} sql The SQL for the query
* @param {array} [values] Any values to insert into placeholders in sql
* @param {boolean} [stringifyObjects=false] Setting if objects should be stringified
* @param {string} [timeZone=local] Setting for time zone to use for Date conversion
* @return {string} Formatted SQL string
* @public
*/
exports.format = function format(sql, values, stringifyObjects, timeZone) {
var SqlString = loadClass('SqlString');
return SqlString.format(sql, values, stringifyObjects, timeZone);
};
/**
* Wrap raw SQL strings from escape overriding.
* @param {string} sql The raw SQL
* @return {object} Wrapped object
* @public
*/
exports.raw = function raw(sql) {
var SqlString = loadClass('SqlString');
return SqlString.raw(sql);
};
/**
* The type constants.
* @public
*/
Object.defineProperty(exports, 'Types', {
get: loadClass.bind(null, 'Types')
});
/**
* Load the given class.
* @param {string} className Name of class to default
* @return {function|object} Class constructor or exports
* @private
*/
function loadClass(className) {
var Class = Classes[className];
if (Class !== undefined) {
return Class;
}
// This uses a switch for static require analysis
switch (className) {
case 'Connection':
Class = require('./lib/Connection');
break;
case 'ConnectionConfig':
Class = require('./lib/ConnectionConfig');
break;
case 'Pool':
Class = require('./lib/Pool');
break;
case 'PoolCluster':
Class = require('./lib/PoolCluster');
break;
case 'PoolConfig':
Class = require('./lib/PoolConfig');
break;
case 'SqlString':
Class = require('./lib/protocol/SqlString');
break;
case 'Types':
Class = require('./lib/protocol/constants/types');
break;
default:
throw new Error('Cannot find class \'' + className + '\'');
}
// Store to prevent invoking require()
Classes[className] = Class;
return Class;
}
+529
View File
@@ -0,0 +1,529 @@
var Crypto = require('crypto');
var Events = require('events');
var Net = require('net');
var tls = require('tls');
var ConnectionConfig = require('./ConnectionConfig');
var Protocol = require('./protocol/Protocol');
var SqlString = require('./protocol/SqlString');
var Query = require('./protocol/sequences/Query');
var Util = require('util');
module.exports = Connection;
Util.inherits(Connection, Events.EventEmitter);
function Connection(options) {
Events.EventEmitter.call(this);
this.config = options.config;
this._socket = options.socket;
this._protocol = new Protocol({config: this.config, connection: this});
this._connectCalled = false;
this.state = 'disconnected';
this.threadId = null;
}
Connection.createQuery = function createQuery(sql, values, callback) {
if (sql instanceof Query) {
return sql;
}
var cb = callback;
var options = {};
if (typeof sql === 'function') {
cb = sql;
} else if (typeof sql === 'object') {
options = Object.create(sql);
if (typeof values === 'function') {
cb = values;
} else if (values !== undefined) {
Object.defineProperty(options, 'values', { value: values });
}
} else {
options.sql = sql;
if (typeof values === 'function') {
cb = values;
} else if (values !== undefined) {
options.values = values;
}
}
if (cb !== undefined) {
cb = wrapCallbackInDomain(null, cb);
if (cb === undefined) {
throw new TypeError('argument callback must be a function when provided');
}
}
return new Query(options, cb);
};
Connection.prototype.connect = function connect(options, callback) {
if (!callback && typeof options === 'function') {
callback = options;
options = {};
}
if (!this._connectCalled) {
this._connectCalled = true;
// Connect either via a UNIX domain socket or a TCP socket.
this._socket = (this.config.socketPath)
? Net.createConnection(this.config.socketPath)
: Net.createConnection(this.config.port, this.config.host);
// Connect socket to connection domain
if (Events.usingDomains) {
this._socket.domain = this.domain;
}
var connection = this;
this._protocol.on('data', function(data) {
connection._socket.write(data);
});
this._socket.on('data', wrapToDomain(connection, function (data) {
connection._protocol.write(data);
}));
this._protocol.on('end', function() {
connection._socket.end();
});
this._socket.on('end', wrapToDomain(connection, function () {
connection._protocol.end();
}));
this._socket.on('error', this._handleNetworkError.bind(this));
this._socket.on('connect', this._handleProtocolConnect.bind(this));
this._protocol.on('handshake', this._handleProtocolHandshake.bind(this));
this._protocol.on('initialize', this._handleProtocolInitialize.bind(this));
this._protocol.on('unhandledError', this._handleProtocolError.bind(this));
this._protocol.on('drain', this._handleProtocolDrain.bind(this));
this._protocol.on('end', this._handleProtocolEnd.bind(this));
this._protocol.on('enqueue', this._handleProtocolEnqueue.bind(this));
if (this.config.connectTimeout) {
var handleConnectTimeout = this._handleConnectTimeout.bind(this);
this._socket.setTimeout(this.config.connectTimeout, handleConnectTimeout);
this._socket.once('connect', function() {
this.setTimeout(0, handleConnectTimeout);
});
}
}
this._protocol.handshake(options, wrapCallbackInDomain(this, callback));
};
Connection.prototype.changeUser = function changeUser(options, callback) {
if (!callback && typeof options === 'function') {
callback = options;
options = {};
}
this._implyConnect();
var charsetNumber = (options.charset)
? ConnectionConfig.getCharsetNumber(options.charset)
: this.config.charsetNumber;
return this._protocol.changeUser({
user : options.user || this.config.user,
password : options.password || this.config.password,
database : options.database || this.config.database,
timeout : options.timeout,
charsetNumber : charsetNumber,
currentConfig : this.config
}, wrapCallbackInDomain(this, callback));
};
Connection.prototype.beginTransaction = function beginTransaction(options, callback) {
if (!callback && typeof options === 'function') {
callback = options;
options = {};
}
options = options || {};
options.sql = 'START TRANSACTION';
options.values = null;
return this.query(options, callback);
};
Connection.prototype.commit = function commit(options, callback) {
if (!callback && typeof options === 'function') {
callback = options;
options = {};
}
options = options || {};
options.sql = 'COMMIT';
options.values = null;
return this.query(options, callback);
};
Connection.prototype.rollback = function rollback(options, callback) {
if (!callback && typeof options === 'function') {
callback = options;
options = {};
}
options = options || {};
options.sql = 'ROLLBACK';
options.values = null;
return this.query(options, callback);
};
Connection.prototype.query = function query(sql, values, cb) {
var query = Connection.createQuery(sql, values, cb);
query._connection = this;
if (!(typeof sql === 'object' && 'typeCast' in sql)) {
query.typeCast = this.config.typeCast;
}
if (query.sql) {
query.sql = this.format(query.sql, query.values);
}
if (query._callback) {
query._callback = wrapCallbackInDomain(this, query._callback);
}
this._implyConnect();
return this._protocol._enqueue(query);
};
Connection.prototype.ping = function ping(options, callback) {
if (!callback && typeof options === 'function') {
callback = options;
options = {};
}
this._implyConnect();
this._protocol.ping(options, wrapCallbackInDomain(this, callback));
};
Connection.prototype.statistics = function statistics(options, callback) {
if (!callback && typeof options === 'function') {
callback = options;
options = {};
}
this._implyConnect();
this._protocol.stats(options, wrapCallbackInDomain(this, callback));
};
Connection.prototype.end = function end(options, callback) {
var cb = callback;
var opts = options;
if (!callback && typeof options === 'function') {
cb = options;
opts = null;
}
// create custom options reference
opts = Object.create(opts || null);
if (opts.timeout === undefined) {
// default timeout of 30 seconds
opts.timeout = 30000;
}
this._implyConnect();
this._protocol.quit(opts, wrapCallbackInDomain(this, cb));
};
Connection.prototype.destroy = function() {
this.state = 'disconnected';
this._implyConnect();
this._socket.destroy();
this._protocol.destroy();
};
Connection.prototype.pause = function() {
this._socket.pause();
this._protocol.pause();
};
Connection.prototype.resume = function() {
this._socket.resume();
this._protocol.resume();
};
Connection.prototype.escape = function(value) {
return SqlString.escape(value, false, this.config.timezone);
};
Connection.prototype.escapeId = function escapeId(value) {
return SqlString.escapeId(value, false);
};
Connection.prototype.format = function(sql, values) {
if (typeof this.config.queryFormat === 'function') {
return this.config.queryFormat.call(this, sql, values, this.config.timezone);
}
return SqlString.format(sql, values, this.config.stringifyObjects, this.config.timezone);
};
if (tls.TLSSocket) {
// 0.11+ environment
Connection.prototype._startTLS = function _startTLS(onSecure) {
var connection = this;
createSecureContext(this.config, function (err, secureContext) {
if (err) {
onSecure(err);
return;
}
// "unpipe"
connection._socket.removeAllListeners('data');
connection._protocol.removeAllListeners('data');
// socket <-> encrypted
var rejectUnauthorized = connection.config.ssl.rejectUnauthorized;
var secureEstablished = false;
var secureSocket = new tls.TLSSocket(connection._socket, {
rejectUnauthorized : rejectUnauthorized,
requestCert : true,
secureContext : secureContext,
isServer : false
});
// error handler for secure socket
secureSocket.on('_tlsError', function(err) {
if (secureEstablished) {
connection._handleNetworkError(err);
} else {
onSecure(err);
}
});
// cleartext <-> protocol
secureSocket.pipe(connection._protocol);
connection._protocol.on('data', function(data) {
secureSocket.write(data);
});
secureSocket.on('secure', function() {
secureEstablished = true;
onSecure(rejectUnauthorized ? this.ssl.verifyError() : null);
});
// start TLS communications
secureSocket._start();
});
};
} else {
// pre-0.11 environment
Connection.prototype._startTLS = function _startTLS(onSecure) {
// before TLS:
// _socket <-> _protocol
// after:
// _socket <-> securePair.encrypted <-> securePair.cleartext <-> _protocol
var connection = this;
var credentials = Crypto.createCredentials({
ca : this.config.ssl.ca,
cert : this.config.ssl.cert,
ciphers : this.config.ssl.ciphers,
key : this.config.ssl.key,
passphrase : this.config.ssl.passphrase
});
var rejectUnauthorized = this.config.ssl.rejectUnauthorized;
var secureEstablished = false;
var securePair = tls.createSecurePair(credentials, false, true, rejectUnauthorized);
// error handler for secure pair
securePair.on('error', function(err) {
if (secureEstablished) {
connection._handleNetworkError(err);
} else {
onSecure(err);
}
});
// "unpipe"
this._socket.removeAllListeners('data');
this._protocol.removeAllListeners('data');
// socket <-> encrypted
securePair.encrypted.pipe(this._socket);
this._socket.on('data', function(data) {
securePair.encrypted.write(data);
});
// cleartext <-> protocol
securePair.cleartext.pipe(this._protocol);
this._protocol.on('data', function(data) {
securePair.cleartext.write(data);
});
// secure established
securePair.on('secure', function() {
secureEstablished = true;
if (!rejectUnauthorized) {
onSecure();
return;
}
var verifyError = this.ssl.verifyError();
var err = verifyError;
// node.js 0.6 support
if (typeof err === 'string') {
err = new Error(verifyError);
err.code = verifyError;
}
onSecure(err);
});
// node.js 0.8 bug
securePair._cycle = securePair.cycle;
securePair.cycle = function cycle() {
if (this.ssl && this.ssl.error) {
this.error();
}
return this._cycle.apply(this, arguments);
};
};
}
Connection.prototype._handleConnectTimeout = function() {
if (this._socket) {
this._socket.setTimeout(0);
this._socket.destroy();
}
var err = new Error('connect ETIMEDOUT');
err.errorno = 'ETIMEDOUT';
err.code = 'ETIMEDOUT';
err.syscall = 'connect';
this._handleNetworkError(err);
};
Connection.prototype._handleNetworkError = function(err) {
this._protocol.handleNetworkError(err);
};
Connection.prototype._handleProtocolError = function(err) {
this.state = 'protocol_error';
this.emit('error', err);
};
Connection.prototype._handleProtocolDrain = function() {
this.emit('drain');
};
Connection.prototype._handleProtocolConnect = function() {
this.state = 'connected';
this.emit('connect');
};
Connection.prototype._handleProtocolHandshake = function _handleProtocolHandshake() {
this.state = 'authenticated';
};
Connection.prototype._handleProtocolInitialize = function _handleProtocolInitialize(packet) {
this.threadId = packet.threadId;
};
Connection.prototype._handleProtocolEnd = function(err) {
this.state = 'disconnected';
this.emit('end', err);
};
Connection.prototype._handleProtocolEnqueue = function _handleProtocolEnqueue(sequence) {
this.emit('enqueue', sequence);
};
Connection.prototype._implyConnect = function() {
if (!this._connectCalled) {
this.connect();
}
};
function createSecureContext (config, cb) {
var context = null;
var error = null;
try {
context = tls.createSecureContext({
ca : config.ssl.ca,
cert : config.ssl.cert,
ciphers : config.ssl.ciphers,
key : config.ssl.key,
passphrase : config.ssl.passphrase
});
} catch (err) {
error = err;
}
cb(error, context);
}
function unwrapFromDomain(fn) {
return function () {
var domains = [];
var ret;
while (process.domain) {
domains.shift(process.domain);
process.domain.exit();
}
try {
ret = fn.apply(this, arguments);
} finally {
for (var i = 0; i < domains.length; i++) {
domains[i].enter();
}
}
return ret;
};
}
function wrapCallbackInDomain(ee, fn) {
if (typeof fn !== 'function') {
return undefined;
}
if (fn.domain) {
return fn;
}
var domain = process.domain;
if (domain) {
return domain.bind(fn);
} else if (ee) {
return unwrapFromDomain(wrapToDomain(ee, fn));
} else {
return fn;
}
}
function wrapToDomain(ee, fn) {
return function () {
if (Events.usingDomains && ee.domain) {
ee.domain.enter();
fn.apply(this, arguments);
ee.domain.exit();
} else {
fn.apply(this, arguments);
}
};
}
+209
View File
@@ -0,0 +1,209 @@
var urlParse = require('url').parse;
var ClientConstants = require('./protocol/constants/client');
var Charsets = require('./protocol/constants/charsets');
var SSLProfiles = null;
module.exports = ConnectionConfig;
function ConnectionConfig(options) {
if (typeof options === 'string') {
options = ConnectionConfig.parseUrl(options);
}
this.host = options.host || 'localhost';
this.port = options.port || 3306;
this.localAddress = options.localAddress;
this.socketPath = options.socketPath;
this.user = options.user || undefined;
this.password = options.password || undefined;
this.database = options.database;
this.connectTimeout = (options.connectTimeout === undefined)
? (10 * 1000)
: options.connectTimeout;
this.insecureAuth = options.insecureAuth || false;
this.supportBigNumbers = options.supportBigNumbers || false;
this.bigNumberStrings = options.bigNumberStrings || false;
this.dateStrings = options.dateStrings || false;
this.debug = options.debug;
this.trace = options.trace !== false;
this.stringifyObjects = options.stringifyObjects || false;
this.timezone = options.timezone || 'local';
this.flags = options.flags || '';
this.queryFormat = options.queryFormat;
this.pool = options.pool || undefined;
this.ssl = (typeof options.ssl === 'string')
? ConnectionConfig.getSSLProfile(options.ssl)
: (options.ssl || false);
this.localInfile = (options.localInfile === undefined)
? true
: options.localInfile;
this.multipleStatements = options.multipleStatements || false;
this.typeCast = (options.typeCast === undefined)
? true
: options.typeCast;
if (this.timezone[0] === ' ') {
// "+" is a url encoded char for space so it
// gets translated to space when giving a
// connection string..
this.timezone = '+' + this.timezone.substr(1);
}
if (this.ssl) {
// Default rejectUnauthorized to true
this.ssl.rejectUnauthorized = this.ssl.rejectUnauthorized !== false;
}
this.maxPacketSize = 0;
this.charsetNumber = (options.charset)
? ConnectionConfig.getCharsetNumber(options.charset)
: options.charsetNumber || Charsets.UTF8_GENERAL_CI;
// Set the client flags
var defaultFlags = ConnectionConfig.getDefaultFlags(options);
this.clientFlags = ConnectionConfig.mergeFlags(defaultFlags, options.flags);
}
ConnectionConfig.mergeFlags = function mergeFlags(defaultFlags, userFlags) {
var allFlags = ConnectionConfig.parseFlagList(defaultFlags);
var newFlags = ConnectionConfig.parseFlagList(userFlags);
// Merge the new flags
for (var flag in newFlags) {
if (allFlags[flag] !== false) {
allFlags[flag] = newFlags[flag];
}
}
// Build flags
var flags = 0x0;
for (var flag in allFlags) {
if (allFlags[flag]) {
// TODO: Throw here on some future release
flags |= ClientConstants['CLIENT_' + flag] || 0x0;
}
}
return flags;
};
ConnectionConfig.getCharsetNumber = function getCharsetNumber(charset) {
var num = Charsets[charset.toUpperCase()];
if (num === undefined) {
throw new TypeError('Unknown charset \'' + charset + '\'');
}
return num;
};
ConnectionConfig.getDefaultFlags = function getDefaultFlags(options) {
var defaultFlags = [
'-COMPRESS', // Compression protocol *NOT* supported
'-CONNECT_ATTRS', // Does *NOT* send connection attributes in Protocol::HandshakeResponse41
'+CONNECT_WITH_DB', // One can specify db on connect in Handshake Response Packet
'+FOUND_ROWS', // Send found rows instead of affected rows
'+IGNORE_SIGPIPE', // Don't issue SIGPIPE if network failures
'+IGNORE_SPACE', // Let the parser ignore spaces before '('
'+LOCAL_FILES', // Can use LOAD DATA LOCAL
'+LONG_FLAG', // Longer flags in Protocol::ColumnDefinition320
'+LONG_PASSWORD', // Use the improved version of Old Password Authentication
'+MULTI_RESULTS', // Can handle multiple resultsets for COM_QUERY
'+ODBC', // Special handling of ODBC behaviour
'-PLUGIN_AUTH', // Does *NOT* support auth plugins
'+PROTOCOL_41', // Uses the 4.1 protocol
'+PS_MULTI_RESULTS', // Can handle multiple resultsets for COM_STMT_EXECUTE
'+RESERVED', // Unused
'+SECURE_CONNECTION', // Supports Authentication::Native41
'+TRANSACTIONS' // Expects status flags
];
if (options && options.localInfile !== undefined && !options.localInfile) {
// Disable LOCAL modifier for LOAD DATA INFILE
defaultFlags.push('-LOCAL_FILES');
}
if (options && options.multipleStatements) {
// May send multiple statements per COM_QUERY and COM_STMT_PREPARE
defaultFlags.push('+MULTI_STATEMENTS');
}
return defaultFlags;
};
ConnectionConfig.getSSLProfile = function getSSLProfile(name) {
if (!SSLProfiles) {
SSLProfiles = require('./protocol/constants/ssl_profiles');
}
var ssl = SSLProfiles[name];
if (ssl === undefined) {
throw new TypeError('Unknown SSL profile \'' + name + '\'');
}
return ssl;
};
ConnectionConfig.parseFlagList = function parseFlagList(flagList) {
var allFlags = Object.create(null);
if (!flagList) {
return allFlags;
}
var flags = !Array.isArray(flagList)
? String(flagList || '').toUpperCase().split(/\s*,+\s*/)
: flagList;
for (var i = 0; i < flags.length; i++) {
var flag = flags[i];
var offset = 1;
var state = flag[0];
if (state === undefined) {
// TODO: throw here on some future release
continue;
}
if (state !== '-' && state !== '+') {
offset = 0;
state = '+';
}
allFlags[flag.substr(offset)] = state === '+';
}
return allFlags;
};
ConnectionConfig.parseUrl = function(url) {
url = urlParse(url, true);
var options = {
host : url.hostname,
port : url.port,
database : url.pathname.substr(1)
};
if (url.auth) {
var auth = url.auth.split(':');
options.user = auth.shift();
options.password = auth.join(':');
}
if (url.query) {
for (var key in url.query) {
var value = url.query[key];
try {
// Try to parse this as a JSON expression first
options[key] = JSON.parse(value);
} catch (err) {
// Otherwise assume it is a plain string
options[key] = value;
}
}
}
return options;
};
+294
View File
@@ -0,0 +1,294 @@
var mysql = require('../');
var Connection = require('./Connection');
var EventEmitter = require('events').EventEmitter;
var Util = require('util');
var PoolConnection = require('./PoolConnection');
module.exports = Pool;
Util.inherits(Pool, EventEmitter);
function Pool(options) {
EventEmitter.call(this);
this.config = options.config;
this.config.connectionConfig.pool = this;
this._acquiringConnections = [];
this._allConnections = [];
this._freeConnections = [];
this._connectionQueue = [];
this._closed = false;
}
Pool.prototype.getConnection = function (cb) {
if (this._closed) {
var err = new Error('Pool is closed.');
err.code = 'POOL_CLOSED';
process.nextTick(function () {
cb(err);
});
return;
}
var connection;
var pool = this;
if (this._freeConnections.length > 0) {
connection = this._freeConnections.shift();
this.acquireConnection(connection, cb);
return;
}
if (this.config.connectionLimit === 0 || this._allConnections.length < this.config.connectionLimit) {
connection = new PoolConnection(this, { config: this.config.newConnectionConfig() });
this._acquiringConnections.push(connection);
this._allConnections.push(connection);
connection.connect({timeout: this.config.acquireTimeout}, function onConnect(err) {
spliceConnection(pool._acquiringConnections, connection);
if (pool._closed) {
err = new Error('Pool is closed.');
err.code = 'POOL_CLOSED';
}
if (err) {
pool._purgeConnection(connection);
cb(err);
return;
}
pool.emit('connection', connection);
pool.emit('acquire', connection);
cb(null, connection);
});
return;
}
if (!this.config.waitForConnections) {
process.nextTick(function(){
var err = new Error('No connections available.');
err.code = 'POOL_CONNLIMIT';
cb(err);
});
return;
}
this._enqueueCallback(cb);
};
Pool.prototype.acquireConnection = function acquireConnection(connection, cb) {
if (connection._pool !== this) {
throw new Error('Connection acquired from wrong pool.');
}
var changeUser = this._needsChangeUser(connection);
var pool = this;
this._acquiringConnections.push(connection);
function onOperationComplete(err) {
spliceConnection(pool._acquiringConnections, connection);
if (pool._closed) {
err = new Error('Pool is closed.');
err.code = 'POOL_CLOSED';
}
if (err) {
pool._connectionQueue.unshift(cb);
pool._purgeConnection(connection);
return;
}
if (changeUser) {
pool.emit('connection', connection);
}
pool.emit('acquire', connection);
cb(null, connection);
}
if (changeUser) {
// restore user back to pool configuration
connection.config = this.config.newConnectionConfig();
connection.changeUser({timeout: this.config.acquireTimeout}, onOperationComplete);
} else {
// ping connection
connection.ping({timeout: this.config.acquireTimeout}, onOperationComplete);
}
};
Pool.prototype.releaseConnection = function releaseConnection(connection) {
if (this._acquiringConnections.indexOf(connection) !== -1) {
// connection is being acquired
return;
}
if (connection._pool) {
if (connection._pool !== this) {
throw new Error('Connection released to wrong pool');
}
if (this._freeConnections.indexOf(connection) !== -1) {
// connection already in free connection pool
// this won't catch all double-release cases
throw new Error('Connection already released');
} else {
// add connection to end of free queue
this._freeConnections.push(connection);
this.emit('release', connection);
}
}
if (this._closed) {
// empty the connection queue
this._connectionQueue.splice(0).forEach(function (cb) {
var err = new Error('Pool is closed.');
err.code = 'POOL_CLOSED';
process.nextTick(function () {
cb(err);
});
});
} else if (this._connectionQueue.length) {
// get connection with next waiting callback
this.getConnection(this._connectionQueue.shift());
}
};
Pool.prototype.end = function (cb) {
this._closed = true;
if (typeof cb !== 'function') {
cb = function (err) {
if (err) throw err;
};
}
var calledBack = false;
var waitingClose = 0;
function onEnd(err) {
if (!calledBack && (err || --waitingClose <= 0)) {
calledBack = true;
cb(err);
}
}
while (this._allConnections.length !== 0) {
waitingClose++;
this._purgeConnection(this._allConnections[0], onEnd);
}
if (waitingClose === 0) {
process.nextTick(onEnd);
}
};
Pool.prototype.query = function (sql, values, cb) {
var query = Connection.createQuery(sql, values, cb);
if (!(typeof sql === 'object' && 'typeCast' in sql)) {
query.typeCast = this.config.connectionConfig.typeCast;
}
if (this.config.connectionConfig.trace) {
// Long stack trace support
query._callSite = new Error();
}
this.getConnection(function (err, conn) {
if (err) {
query.on('error', function () {});
query.end(err);
return;
}
// Release connection based off event
query.once('end', function() {
conn.release();
});
conn.query(query);
});
return query;
};
Pool.prototype._enqueueCallback = function _enqueueCallback(callback) {
if (this.config.queueLimit && this._connectionQueue.length >= this.config.queueLimit) {
process.nextTick(function () {
var err = new Error('Queue limit reached.');
err.code = 'POOL_ENQUEUELIMIT';
callback(err);
});
return;
}
// Bind to domain, as dequeue will likely occur in a different domain
var cb = process.domain
? process.domain.bind(callback)
: callback;
this._connectionQueue.push(cb);
this.emit('enqueue');
};
Pool.prototype._needsChangeUser = function _needsChangeUser(connection) {
var connConfig = connection.config;
var poolConfig = this.config.connectionConfig;
// check if changeUser values are different
return connConfig.user !== poolConfig.user
|| connConfig.database !== poolConfig.database
|| connConfig.password !== poolConfig.password
|| connConfig.charsetNumber !== poolConfig.charsetNumber;
};
Pool.prototype._purgeConnection = function _purgeConnection(connection, callback) {
var cb = callback || function () {};
if (connection.state === 'disconnected') {
connection.destroy();
}
this._removeConnection(connection);
if (connection.state !== 'disconnected' && !connection._protocol._quitSequence) {
connection._realEnd(cb);
return;
}
process.nextTick(cb);
};
Pool.prototype._removeConnection = function(connection) {
connection._pool = null;
// Remove connection from all connections
spliceConnection(this._allConnections, connection);
// Remove connection from free connections
spliceConnection(this._freeConnections, connection);
this.releaseConnection(connection);
};
Pool.prototype.escape = function(value) {
return mysql.escape(value, this.config.connectionConfig.stringifyObjects, this.config.connectionConfig.timezone);
};
Pool.prototype.escapeId = function escapeId(value) {
return mysql.escapeId(value, false);
};
function spliceConnection(array, connection) {
var index;
if ((index = array.indexOf(connection)) !== -1) {
// Remove connection from all connections
array.splice(index, 1);
}
}
+288
View File
@@ -0,0 +1,288 @@
var Pool = require('./Pool');
var PoolConfig = require('./PoolConfig');
var PoolNamespace = require('./PoolNamespace');
var PoolSelector = require('./PoolSelector');
var Util = require('util');
var EventEmitter = require('events').EventEmitter;
module.exports = PoolCluster;
/**
* PoolCluster
* @constructor
* @param {object} [config] The pool cluster configuration
* @public
*/
function PoolCluster(config) {
EventEmitter.call(this);
config = config || {};
this._canRetry = typeof config.canRetry === 'undefined' ? true : config.canRetry;
this._defaultSelector = config.defaultSelector || 'RR';
this._removeNodeErrorCount = config.removeNodeErrorCount || 5;
this._restoreNodeTimeout = config.restoreNodeTimeout || 0;
this._closed = false;
this._findCaches = Object.create(null);
this._lastId = 0;
this._namespaces = Object.create(null);
this._nodes = Object.create(null);
}
Util.inherits(PoolCluster, EventEmitter);
PoolCluster.prototype.add = function add(id, config) {
if (this._closed) {
throw new Error('PoolCluster is closed.');
}
var nodeId = typeof id === 'object'
? 'CLUSTER::' + (++this._lastId)
: String(id);
if (this._nodes[nodeId] !== undefined) {
throw new Error('Node ID "' + nodeId + '" is already defined in PoolCluster.');
}
var poolConfig = typeof id !== 'object'
? new PoolConfig(config)
: new PoolConfig(id);
this._nodes[nodeId] = {
id : nodeId,
errorCount : 0,
pool : new Pool({config: poolConfig}),
_offlineUntil : 0
};
this._clearFindCaches();
};
PoolCluster.prototype.end = function end(callback) {
var cb = callback !== undefined
? callback
: _cb;
if (typeof cb !== 'function') {
throw TypeError('callback argument must be a function');
}
if (this._closed) {
process.nextTick(cb);
return;
}
this._closed = true;
var calledBack = false;
var nodeIds = Object.keys(this._nodes);
var waitingClose = 0;
function onEnd(err) {
if (!calledBack && (err || --waitingClose <= 0)) {
calledBack = true;
cb(err);
}
}
for (var i = 0; i < nodeIds.length; i++) {
var nodeId = nodeIds[i];
var node = this._nodes[nodeId];
waitingClose++;
node.pool.end(onEnd);
}
if (waitingClose === 0) {
process.nextTick(onEnd);
}
};
PoolCluster.prototype.of = function(pattern, selector) {
pattern = pattern || '*';
selector = selector || this._defaultSelector;
selector = selector.toUpperCase();
if (typeof PoolSelector[selector] === 'undefined') {
selector = this._defaultSelector;
}
var key = pattern + selector;
if (typeof this._namespaces[key] === 'undefined') {
this._namespaces[key] = new PoolNamespace(this, pattern, selector);
}
return this._namespaces[key];
};
PoolCluster.prototype.remove = function remove(pattern) {
var foundNodeIds = this._findNodeIds(pattern, true);
for (var i = 0; i < foundNodeIds.length; i++) {
var node = this._getNode(foundNodeIds[i]);
if (node) {
this._removeNode(node);
}
}
};
PoolCluster.prototype.getConnection = function(pattern, selector, cb) {
var namespace;
if (typeof pattern === 'function') {
cb = pattern;
namespace = this.of();
} else {
if (typeof selector === 'function') {
cb = selector;
selector = this._defaultSelector;
}
namespace = this.of(pattern, selector);
}
namespace.getConnection(cb);
};
PoolCluster.prototype._clearFindCaches = function _clearFindCaches() {
this._findCaches = Object.create(null);
};
PoolCluster.prototype._decreaseErrorCount = function _decreaseErrorCount(node) {
var errorCount = node.errorCount;
if (errorCount > this._removeNodeErrorCount) {
errorCount = this._removeNodeErrorCount;
}
if (errorCount < 1) {
errorCount = 1;
}
node.errorCount = errorCount - 1;
if (node._offlineUntil) {
node._offlineUntil = 0;
this.emit('online', node.id);
}
};
PoolCluster.prototype._findNodeIds = function _findNodeIds(pattern, includeOffline) {
var currentTime = 0;
var foundNodeIds = this._findCaches[pattern];
if (foundNodeIds === undefined) {
var expression = patternRegExp(pattern);
var nodeIds = Object.keys(this._nodes);
foundNodeIds = nodeIds.filter(function (id) {
return id.match(expression);
});
this._findCaches[pattern] = foundNodeIds;
}
if (includeOffline) {
return foundNodeIds;
}
return foundNodeIds.filter(function (nodeId) {
var node = this._getNode(nodeId);
if (!node._offlineUntil) {
return true;
}
if (!currentTime) {
currentTime = getMonotonicMilliseconds();
}
return node._offlineUntil <= currentTime;
}, this);
};
PoolCluster.prototype._getNode = function _getNode(id) {
return this._nodes[id] || null;
};
PoolCluster.prototype._increaseErrorCount = function _increaseErrorCount(node) {
var errorCount = ++node.errorCount;
if (this._removeNodeErrorCount > errorCount) {
return;
}
if (this._restoreNodeTimeout > 0) {
node._offlineUntil = getMonotonicMilliseconds() + this._restoreNodeTimeout;
this.emit('offline', node.id);
return;
}
this._removeNode(node);
this.emit('remove', node.id);
};
PoolCluster.prototype._getConnection = function(node, cb) {
var self = this;
node.pool.getConnection(function (err, connection) {
if (err) {
self._increaseErrorCount(node);
cb(err);
return;
} else {
self._decreaseErrorCount(node);
}
connection._clusterId = node.id;
cb(null, connection);
});
};
PoolCluster.prototype._removeNode = function _removeNode(node) {
delete this._nodes[node.id];
this._clearFindCaches();
node.pool.end(_noop);
};
function getMonotonicMilliseconds() {
var ms;
if (typeof process.hrtime === 'function') {
ms = process.hrtime();
ms = ms[0] * 1e3 + ms[1] * 1e-6;
} else {
ms = process.uptime() * 1000;
}
return Math.floor(ms);
}
function isRegExp(val) {
return typeof val === 'object'
&& Object.prototype.toString.call(val) === '[object RegExp]';
}
function patternRegExp(pattern) {
if (isRegExp(pattern)) {
return pattern;
}
var source = pattern
.replace(/([.+?^=!:${}()|\[\]\/\\])/g, '\\$1')
.replace(/\*/g, '.*');
return new RegExp('^' + source + '$');
}
function _cb(err) {
if (err) {
throw err;
}
}
function _noop() {}

Some files were not shown because too many files have changed in this diff Show More