【python】クローラー型検索エンジン

import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin, urlparse
import sqlite3
import threading
import queue
import tkinter as tk
from tkinter import ttk, messagebox

# データベース設定
DB_NAME = "gui_search_engine.db"
conn = sqlite3.connect(DB_NAME, check_same_thread=False)
cursor = conn.cursor()

# テーブル作成
cursor.execute("""
CREATE TABLE IF NOT EXISTS pages (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    url TEXT UNIQUE,
    title TEXT,
    description TEXT,
    content TEXT
)
""")
conn.commit()

# グローバル変数
visited = set()
visited_lock = threading.Lock()
task_queue = queue.Queue()
MAX_THREADS = 5

# ページをデータベースに保存
def save_page_to_db(url, title, description, content):
    try:
        cursor.execute("INSERT INTO pages (url, title, description, content) VALUES (?, ?, ?, ?)",
                       (url, title, description, content))
        conn.commit()
    except sqlite3.IntegrityError:
        pass  # URL重複時は無視

# URL正規化
def normalize_url(base, link):
    return urljoin(base, link).split('#')[0]

# クローラー
def crawl(url, domain, status_label):
    with visited_lock:
        if url in visited:
            return
        visited.add(url)

    try:
        response = requests.get(url, timeout=10)
        soup = BeautifulSoup(response.content, "html.parser")

        # メタデータ収集
        title = soup.title.string if soup.title else "No Title"
        description_tag = soup.find("meta", attrs={"name": "description"})
        description = description_tag["content"] if description_tag else "No Description"
        content = soup.get_text()

        # データベースに保存
        save_page_to_db(url, title, description, content)

        # ステータス更新
        status_label.config(text=f"Crawling: {url}")

        # 次のURLを収集
        for link in soup.find_all('a', href=True):
            full_url = normalize_url(url, link['href'])
            if urlparse(full_url).netloc == domain:
                task_queue.put(full_url)
    except Exception as e:
        print(f"Error crawling {url}: {e}")

# 並列クローリング
def start_crawling(start_url, domain, status_label):
    visited.clear()
    task_queue.put(start_url)

    def worker():
        while not task_queue.empty():
            url = task_queue.get()
            crawl(url, domain, status_label)
        status_label.config(text="Crawling Complete")

    threads = []
    for _ in range(MAX_THREADS):
        thread = threading.Thread(target=worker)
        threads.append(thread)
        thread.start()
    for thread in threads:
        thread.join()

# 検索機能
def search(query, results_box):
    cursor.execute("SELECT url, title, description FROM pages WHERE content LIKE ?", (f"%{query}%",))
    results = cursor.fetchall()
    results_box.delete(*results_box.get_children())  # 結果をクリア

    if not results:
        messagebox.showinfo("検索結果", "該当する結果はありませんでした。")
    else:
        for url, title, description in results:
            results_box.insert("", "end", values=(title, url, description[:100]))

# GUI設計
def create_gui():
    root = tk.Tk()
    root.title("クローラー型検索エンジン")

    # フレーム構成
    frame_crawl = ttk.Frame(root, padding=10)
    frame_crawl.grid(row=0, column=0, sticky="ew")
    frame_search = ttk.Frame(root, padding=10)
    frame_search.grid(row=1, column=0, sticky="nsew")

    # クローリングセクション
    ttk.Label(frame_crawl, text="スタートURL:").grid(row=0, column=0, padx=5, pady=5, sticky="w")
    url_entry = ttk.Entry(frame_crawl, width=50)
    url_entry.grid(row=0, column=1, padx=5, pady=5, sticky="w")

    status_label = ttk.Label(frame_crawl, text="Status: Ready", foreground="blue")
    status_label.grid(row=1, column=0, columnspan=2, padx=5, pady=5, sticky="w")

    def on_crawl():
        start_url = url_entry.get().strip()
        if not start_url:
            messagebox.showerror("Error", "スタートURLを入力してください。")
            return

        # スキーム補完
        if not start_url.startswith(("http://", "https://")):
            start_url = "https://" + start_url

        # ドメインを取得
        domain = urlparse(start_url).netloc
        status_label.config(text="Crawling in Progress...")
        threading.Thread(target=start_crawling, args=(start_url, domain, status_label)).start()

    ttk.Button(frame_crawl, text="クローリング開始", command=on_crawl).grid(row=0, column=2, padx=5, pady=5)

    # 検索セクション
    ttk.Label(frame_search, text="検索クエリ:").grid(row=0, column=0, padx=5, pady=5, sticky="w")
    query_entry = ttk.Entry(frame_search, width=30)
    query_entry.grid(row=0, column=1, padx=5, pady=5, sticky="w")

    results_box = ttk.Treeview(frame_search, columns=("Title", "URL", "Description"), show="headings")
    results_box.heading("Title", text="タイトル")
    results_box.heading("URL", text="URL")
    results_box.heading("Description", text="説明")
    results_box.grid(row=1, column=0, columnspan=3, padx=5, pady=5, sticky="nsew")

    def on_search():
        query = query_entry.get().strip()
        if not query:
            messagebox.showerror("Error", "検索クエリを入力してください。")
            return
        search(query, results_box)

    ttk.Button(frame_search, text="検索", command=on_search).grid(row=0, column=2, padx=5, pady=5)

    # ウィンドウサイズ調整
    root.columnconfigure(0, weight=1)
    frame_search.rowconfigure(1, weight=1)

    root.mainloop()

# GUI起動
if __name__ == "__main__":
    create_gui()

    # データベース接続を閉じる
    conn.close()

PHP トレイト

<?php
trait LogTrait
{
    public function log()
    {
        echo "Instance created" . PHP_EOL;
    }
}

abstract class Score
{
    use LogTrait;

    private $subject;
    protected $points;

    public function __construct($subject, $points)
    {
        $this->subject = $subject;
        $this->points = $points;
        $this->log();
    }

    abstract protected function getResult();

    public function getInfo()
    {
        return "{$this->subject}, {$this->points}, {$this->getResult()}";
    }
}

class MathScore extends Score
{
    public function __construct($points)
    {
        parent::__construct("Math", $points);
    }

    protected function getResult()
    {
        echo "MathScore method" . PHP_EOL;
        return $this->points >= 50 ? "Pass" : "Fail";
    }
}

class EnglishScore extends Score
{
    public function __construct($points)
    {
        parent::__construct("English", $points);
    }

    protected function getResult()
    {
        echo "EnglishScore method" . PHP_EOL;
        return $this->points >= 95 ? "Pass" : "Fail";
    }
}

class User
{
    use LogTrait;

    private $name;
    private $score;

    public function __construct($name, $score)
    {
        $this->name = $name;
        $this->score = $score;
        $this->log();
    }

    public function getInfo()
    {
        return "{$this->name}, {$this->score->getInfo()}";
    }
}

$user1 = new User("Taro", new MathScore(70));
$user2 = new User("Jiro", new EnglishScore(90));

echo $user1->getInfo() . PHP_EOL;
echo $user2->getInfo() . PHP_EOL;

PHP logメソッド

<?php
interface Loggable
{
    public function log();
}

abstract class Score implements Loggable
{
    private $subject;
    protected $points;

    public function __construct($subject, $points)
    {
        $this->subject = $subject;
        $this->points = $points;
        $this->log();
    }
    public function log()
    {
        echo "Instance created: {$this->subject}" . PHP_EOL;
    }

    abstract protected function getResult();

    public function getInfo()
    {
        return "{$this->subject}, {$this->points}, {$this->getResult()}";
    }
}

class MathScore extends Score
{
    public function __construct($points)
    {
        parent::__construct("Math", $points);
    }

    protected function getResult()
    {
        echo "MathScore method" . PHP_EOL;
        return $this->points >= 50 ? "Pass" : "Fail";
    }
}

class EnglishScore extends Score
{
    public function __construct($points)
    {
        parent::__construct("English", $points);
    }

    protected function getResult()
    {
        echo "EnglishScore method" . PHP_EOL;
        return $this->points >= 95 ? "Pass" : "Fail";
    }
}

class User implements Loggable
{
    private $name;
    private $score;

    public function __construct($name, $score)
    {
        $this->name = $name;
        $this->score = $score;
        $this->log();
    }
    public function log()
    {
        echo "Instance created: {$this->name}" . PHP_EOL;
    }
    public function getInfo()
    {
        return "{$this->name}, {$this->score->getInfo()}";
    }
}

$user1 = new User("Taro", new MathScore(70));
$user2 = new User("Jiro", new EnglishScore(90));

echo $user1->getInfo() . PHP_EOL;
echo $user2->getInfo() . PHP_EOL;

神と対話するAI

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>神と対話するAI</title>
  <style>
    /* 神秘的な背景とエフェクト */
    body {
      font-family: 'Georgia', serif;
      background-color: #1a1a2e;
      color: #d1d1e9;
      display: flex;
      align-items: center;
      justify-content: center;
      height: 100vh;
      margin: 0;
      overflow: hidden;
    }
    .chat-container {
      width: 100%;
      max-width: 600px;
      background-color: rgba(43, 43, 63, 0.9);
      border-radius: 10px;
      box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.6);
      padding: 20px;
      position: relative;
      overflow: hidden;
    }
    .messages {
      height: 300px;
      overflow-y: auto;
      margin-bottom: 10px;
      padding-right: 10px;
    }
    .message {
      margin: 10px 0;
      line-height: 1.5;
    }
    .user-message {
      text-align: right;
      color: #00aaff;
    }
    .ai-message {
      text-align: left;
      color: #e6e6fa;
      font-style: italic;
    }
    .typing-indicator {
      font-size: 1.5em;
      color: #e6e6fa;
    }
    .input-container {
      display: flex;
    }
    input[type="text"] {
      flex: 1;
      padding: 10px;
      border-radius: 5px;
      border: 1px solid #555;
      background-color: #444;
      color: #e6e6fa;
      margin-right: 10px;
    }
    button {
      padding: 10px 20px;
      border: none;
      border-radius: 5px;
      background-color: #5a5adb;
      color: white;
      cursor: pointer;
    }
    /* 背景アニメーション */
    .background-animation {
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background: radial-gradient(circle, rgba(255,255,255,0.1), rgba(0,0,0,0) 70%);
      animation: glow 5s infinite alternate;
      pointer-events: none;
    }
    @keyframes glow {
      from {
        opacity: 0.4;
      }
      to {
        opacity: 0.7;
      }
    }
  </style>
</head>
<body>

<div class="chat-container">
  <h2>神と対話するAI</h2>
  <div class="messages" id="messages"></div>
  <div class="input-container">
    <input type="text" id="userInput" placeholder="質問を入力してください...">
    <button onclick="sendMessage()">送信</button>
  </div>
  <div class="background-animation"></div>
</div>

<script>
  const messagesContainer = document.getElementById("messages");

  function addMessage(content, className) {
    const message = document.createElement("div");
    message.className = "message " + className;
    message.innerHTML = content;
    messagesContainer.appendChild(message);
    messagesContainer.scrollTop = messagesContainer.scrollHeight;
  }

  function getAIResponse(userMessage) {
    const responses = {
      "目的": [
        "あなたの目的はあなたの選択の中にあります。心を澄まし、その小さな声に耳を傾けなさい。",
        "目的は定まっているものではなく、あなたが形作るものです。勇気を持って探し続けなさい。"
      ],
      "未来": [
        "未来は揺れ動く霧のようなもの…手の中にありながら捉えられぬもの。だが、あなたの意思がその霧を晴らすだろう。",
        "未来は、あなたの内にある希望が灯し出すもの。信じる道を歩みなさい。"
      ],
      "愛": [
        "愛とは、無限に与えること。光のようにあなたを包み、他者を受け入れるものです。",
        "愛とは、心の中の静けさと繋がり、他者の存在をただあるがままに受け入れること。"
      ],
      "default": [
        "その問いの答えは、あなた自身が見つけ出すもの。内なる声を信じなさい。",
        "すべての答えは既にあなたの心の中にあります。耳を澄まし、その声に従いなさい。"
      ]
    };

    const keywords = Object.keys(responses);
    for (let keyword of keywords) {
      if (userMessage.includes(keyword)) {
        const possibleResponses = responses[keyword];
        return possibleResponses[Math.floor(Math.random() * possibleResponses.length)];
      }
    }
    
    const defaultResponses = responses["default"];
    return defaultResponses[Math.floor(Math.random() * defaultResponses.length)];
  }

  function sendMessage() {
    const userInput = document.getElementById("userInput").value.trim();
    if (userInput === "") return;

    addMessage(userInput, "user-message");
    document.getElementById("userInput").value = "";

    const aiResponse = getAIResponse(userInput);

    // タイピングエフェクトを表示
    setTimeout(() => {
      addMessage(`<span class="typing-indicator">...</span>`, "ai-message");
      setTimeout(() => {
        messagesContainer.lastChild.remove();
        addMessage(aiResponse, "ai-message");
      }, 2000); // タイピングエフェクト表示後の応答
    }, 800); // 遅延で自然な応答
  }
</script>

</body>
</html>

PHP クラスメソッド

<?php
class User
{
    public $name;
    public $score;
    private static $count = 0;

    public function __construct($name, $score)
    {
        $this->name = $name;
        $this->score = $score;
        User::$count++;
    }

    public static function getUserCount()
    {
        return User::$count;
    }
}

$user1 = new User("Taro", 70);
$user2 = new User("Jiro", 90);

//User::$count++;
//echo User::$count . PHP_EOL;
echo User::getUserCount() . PHP_EOL;

PHP クラスプロパティ

<?php
class User
{
    public $name;
    public $score;
    public static $count = 0;

    public function __construct($name, $score)
    {
        $this->name = $name;
        $this->score = $score;
        User::$count++;
    }
}

// $count = 0;
$user1 = new User("Taro", 70);
// $count++;
$user2 = new User("Jiro", 90);
// $count++;

// echo $count . PHP_EOL;
echo User::$count . PHP_EOL;

PHP setScoreメソッド

<?php
class User
{
    public $name;
    public $score;

    public function __construct($name, $score)
    {
        $this->name = $name;
        $this->score = $score;
    }

    public function getInfo()
    {
        return "{$this->name}, {$this->score}";
    }
}

$user1 = new User("Taro", 70);
$user2 = new User("Jiro", 90);

$user1->score = 900;

echo $user1->getInfo() . PHP_EOL;
echo $user2->getInfo() . PHP_EOL;

NekoNekodouga.html

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ねこねこ動画 - 動画共有サイト</title>
    <style>
        /* ベーススタイル */
        body {
            font-family: Arial, sans-serif;
            margin: 0;
            padding: 0;
            background-color: #f4f4f4;
        }

        header {
            background-color: #333;
            color: white;
            padding: 10px;
            text-align: center;
            position: fixed;
            width: 100%;
            top: 0;
            z-index: 100;
        }

        header h1 {
            margin: 0;
            font-size: 24px;
        }

        nav ul {
            list-style-type: none;
            padding: 0;
            margin: 10px 0 0 0;
            text-align: center;
        }

        nav ul li {
            display: inline-block;
            margin-right: 15px;
        }

        nav ul li a {
            color: white;
            text-decoration: none;
            font-size: 16px;
        }

        #searchBar {
            margin-top: 10px;
            padding: 5px;
            width: 300px;
            max-width: 80%;
            border: none;
            border-radius: 4px;
        }

        .container {
            margin-top: 100px;
            padding: 20px;
            max-width: 1200px;
            margin-left: auto;
            margin-right: auto;
        }

        .upload-container, .video-info, .description, .comments, .related-videos, .gallery {
            background-color: white;
            padding: 20px;
            margin-top: 20px;
            border-radius: 10px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
        }

        .upload-container h2, .video-info h2, .description h2, .comments h2, .related-videos h2, .gallery h2 {
            margin-top: 0;
        }

        .upload-container form input[type="file"],
        .upload-container form input[type="text"],
        .upload-container form textarea,
        .upload-container form select {
            width: 100%;
            padding: 10px;
            margin-bottom: 10px;
            border-radius: 4px;
            border: 1px solid #ccc;
        }

        .upload-container form button {
            padding: 10px 20px;
            background-color: #333;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            transition: background-color 0.3s ease;
        }

        .upload-container form button:hover {
            background-color: #555;
        }

        .video-container {
            position: relative;
            text-align: center;
            width: 100%;
            max-width: 800px;
            margin: 0 auto;
        }

        .video-container video {
            width: 100%;
            height: auto;
            border-radius: 10px;
        }

        .comment-overlay {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            pointer-events: none;
            z-index: 10;
        }

        .comment {
            position: absolute;
            white-space: nowrap;
            font-size: 20px;
            text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
            animation: moveComment linear forwards;
        }

        @keyframes moveComment {
            from {
                left: 100%;
            }
            to {
                left: -100%;
            }
        }

        .description p, .comments p, .gallery p {
            margin: 10px 0;
        }

        .comments form textarea {
            width: 100%;
            padding: 10px;
            border-radius: 4px;
            border: 1px solid #ccc;
            resize: vertical;
            margin-bottom: 10px;
        }

        .comments form select {
            width: 100%;
            padding: 10px;
            margin-bottom: 10px;
            border-radius: 4px;
        }

        .comments form button {
            padding: 10px 20px;
            background-color: #333;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            transition: background-color 0.3s ease;
        }

        .comments form button:hover {
            background-color: #555;
        }

        .comment-list .comment {
            background-color: #f9f9f9;
            padding: 10px;
            margin-bottom: 10px;
            border-radius: 5px;
        }

        .like-button, .dislike-button {
            background-color: #333;
            color: white;
            border: none;
            padding: 5px 10px;
            margin: 5px;
            border-radius: 5px;
            cursor: pointer;
            transition: background-color 0.3s ease;
        }

        .like-button:hover, .dislike-button:hover {
            background-color: #555;
        }

        footer {
            background-color: #333;
            color: white;
            text-align: center;
            padding: 20px;
            margin-top: 40px;
        }

        footer p {
            margin: 0;
        }

        @media (max-width: 768px) {
            nav ul li {
                display: block;
                margin: 10px 0;
            }

            #searchBar {
                width: 80%;
            }

            .video-container {
                max-width: 100%;
            }
        }
    </style>
</head>
<body>

    <!-- ヘッダー開始 -->
    <header>
        <h1>ねこねこ動画</h1>
        <nav>
            <ul>
                <li><a href="#">ホーム</a></li>
                <li><a href="#">人気動画</a></li>
                <li><a href="#">カテゴリ</a></li>
                <li><a href="#">ログイン</a></li>
            </ul>
        </nav>
        <input type="text" id="searchBar" placeholder="動画を検索..." />
    </header>
    <!-- ヘッダー終了 -->

    <div class="container">

        <!-- 動画アップロードエリア -->
        <div class="upload-container">
            <h2>動画をアップロード</h2>
            <form id="uploadForm" enctype="multipart/form-data">
                <input type="file" id="videoFile" name="video" accept="video/*" required><br>
                <input type="text" id="videoTitle" name="title" placeholder="動画タイトル" required><br>
                <textarea id="videoDescription" name="description" rows="4" placeholder="動画の説明" required></textarea><br>
                <button type="submit">アップロード</button>
            </form>
            <div id="uploadStatus"></div>
        </div>

        <!-- プレビューエリア -->
        <div class="video-container" id="previewContainer" style="display: none;">
            <h2 id="previewTitle">プレビュー: 動画タイトル</h2>
            <video controls id="videoPreview"></video>
            <div class="comment-overlay" id="commentOverlay"></div>
            <p id="previewDescription">プレビュー: 動画の説明</p>
        </div>

        <!-- コメント投稿エリア -->
        <div class="comments">
            <h2>コメントを投稿</h2>
            <form id="commentForm">
                <textarea id="commentText" rows="4" cols="50" placeholder="コメントを追加..." required></textarea><br>
                <label for="commentTime">表示タイミング (秒):</label>
                <input type="number" id="commentTime" placeholder="0" min="0" required><br>
                <label for="commentColor">コメントの色:</label>
                <select id="commentColor">
                    <option value="white">白</option>
                    <option value="red">赤</option>
                    <option value="blue">青</option>
                    <option value="green">緑</option>
                    <option value="yellow">黄色</option>
                </select><br>
                <label for="commentFontSize">フォントサイズ:</label>
                <select id="commentFontSize">
                    <option value="20px">小</option>
                    <option value="24px">中</option>
                    <option value="28px">大</option>
                </select><br>
                <label for="commentSpeed">表示速度 (秒):</label>
                <input type="number" id="commentSpeed" placeholder="10" min="5" max="20" required><br>
                <button type="submit">投稿</button>
            </form>
            <div id="commentList" class="comment-list"></div>
        </div>

        <!-- 評価機能 -->
        <div class="rating">
            <button class="like-button" id="likeButton">👍 いいね</button>
            <span id="likeCount">0</span>
            <button class="dislike-button" id="dislikeButton">👎 バッド</button>
            <span id="dislikeCount">0</span>
        </div>

    </div>

    <!-- フッター開始 -->
    <footer>
        <p>&copy; 2023 ねこねこ動画. All Rights Reserved.</p>
    </footer>
    <!-- フッター終了 -->

    <script>
        let comments = [];

        // 動画のアップロードとプレビュー処理
        document.getElementById("uploadForm").addEventListener("submit", function(event) {
            event.preventDefault();

            const fileInput = document.getElementById("videoFile");
            const file = fileInput.files[0];
            const title = document.getElementById("videoTitle").value;
            const description = document.getElementById("videoDescription").value;

            if (!file) {
                alert("動画ファイルを選択してください。");
                return;
            }

            const reader = new FileReader();
            reader.onload = function(e) {
                const videoData = e.target.result;
                document.getElementById("previewContainer").style.display = "block";
                document.getElementById("videoPreview").src = videoData;
                document.getElementById("previewTitle").textContent = "プレビュー: " + title;
                document.getElementById("previewDescription").textContent = "プレビュー: " + description;
            };
            reader.readAsDataURL(file);
        });

        // コメント投稿処理
        document.getElementById("commentForm").addEventListener("submit", function(event) {
            event.preventDefault();

            const commentText = document.getElementById("commentText").value;
            const commentTime = parseInt(document.getElementById("commentTime").value);
            const commentColor = document.getElementById("commentColor").value;
            const commentFontSize = document.getElementById("commentFontSize").value;
            const commentSpeed = parseInt(document.getElementById("commentSpeed").value);

            if (commentText && commentTime >= 0) {
                const comment = {
                    text: commentText,
                    time: commentTime,
                    color: commentColor,
                    fontSize: commentFontSize,
                    speed: commentSpeed
                };

                comments.push(comment);
                displayCommentInList(comment);
                document.getElementById("commentForm").reset();
            }
        });

        // コメントリストに表示
        function displayCommentInList(comment) {
            const commentList = document.getElementById("commentList");
            const commentDiv = document.createElement("div");
            commentDiv.classList.add("comment");
            commentDiv.textContent = `タイミング: ${comment.time}秒 - ${comment.text}`;
            commentList.appendChild(commentDiv);
        }

        // 動画の再生に合わせてコメントを表示
        const videoElement = document.getElementById("videoPreview");
        videoElement.addEventListener("timeupdate", function() {
            const currentTime = Math.floor(videoElement.currentTime);
            comments.forEach(comment => {
                if (comment.time === currentTime) {
                    displayCommentOnVideo(comment);
                }
            });
        });

        // 動画上にコメントを流す
        function displayCommentOnVideo(comment) {
            const overlay = document.getElementById("commentOverlay");
            const commentElement = document.createElement("div");
            commentElement.classList.add("comment");
            commentElement.textContent = comment.text;
            commentElement.style.color = comment.color;
            commentElement.style.fontSize = comment.fontSize;
            commentElement.style.animationDuration = `${comment.speed}s`;
            commentElement.style.top = Math.random() * 80 + "%"; // ランダムな位置
            overlay.appendChild(commentElement);

            // 一定時間後にコメントを削除
            setTimeout(() => {
                commentElement.remove();
            }, comment.speed * 1000);
        }

        // いいね・バッド機能
        document.getElementById("likeButton").addEventListener("click", function() {
            let likeCount = parseInt(document.getElementById("likeCount").textContent);
            likeCount++;
            document.getElementById("likeCount").textContent = likeCount;
        });

        document.getElementById("dislikeButton").addEventListener("click", function() {
            let dislikeCount = parseInt(document.getElementById("dislikeCount").textContent);
            dislikeCount++;
            document.getElementById("dislikeCount").textContent = dislikeCount;
        });

    </script>

</body>
</html>