部分界面預覽

前端實用工具類 - 不負好時光 -_#html


前端實用工具類 - 不負好時光 -_#前端_02


前端實用工具類 - 不負好時光 -_JSON_03


前端實用工具類 - 不負好時光 -_#前端_04

1. 整體架構設計

1.1 HTML結構

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <!-- 元數據和樣式 -->
</head>
<body>
    <div class="container">
        <div class="header-actions">
            <h1>全能前端處理工具</h1>
            <div class="theme-switch">
                <!-- 暗黑模式切換 -->
            </div>
        </div>
        
        <div class="tabs">
            <!-- 6個功能標籤頁 -->
        </div>
        
        <!-- 各個功能區域 -->
        <div id="text-tools" class="tab-content active">
            <!-- 文本處理功能 -->
        </div>
        
        <!-- 其他5個功能區域 -->
    </div>
    <script>
        // 所有JavaScript代碼
    </script>
</body>
</html>
  • 使用語義化的HTML5文檔結構
  • 採用標籤頁(tab)設計,將功能分為六大類:
  • 文本處理
  • JSON工具
  • Base64工具
  • 編碼/加密
  • ASCII工具
  • 時間工具

1.2 核心功能分析

文本處理功能
  • 文本統計:實時計算字符數、單詞數、行數等
  • 大小寫轉換:支持多種格式轉換
  • 正則表達式測試:支持多種標誌和替換功能
  • HTML轉義/反轉義
  • URL編碼/解碼
JSON工具
  • 格式化與壓縮:美化或壓縮JSON數據
  • 格式轉換:JSON轉XML、CSV、YAML
  • 路徑查詢:簡單的JSON路徑查詢功能
Base64工具
  • 文本編碼/解碼
  • 文件編碼:將文件轉換為Base64
  • 圖片預覽:直接預覽Base64編碼的圖片
編碼/加密工具
  • 哈希計算:支持MD5、SHA-1、SHA-256、SHA-512
  • AES加密/解密:使用Web Crypto API實現
ASCII工具
  • 文本與ASCII碼互轉:支持多種輸出格式
  • ASCII碼錶:動態生成完整的ASCII碼錶
時間工具
  • 時間戳轉換:Unix時間戳與日期互轉
  • 日期計算:計算兩個日期之間的差值

2. CSS設計

2. CSS設計系統

  • 使用CSS變量定義主題色彩,便於維護和切換
  • 響應式設計,適配不同屏幕尺寸
  • 暗黑模式支持
  • 清晰的視覺層次和交互反饋
CSS變量定義
:root {
    --primary-color: #4a6fa5;
    --secondary-color: #6b8cae;
    --light-color: #f8f9fa;
    --dark-color: #343a40;
    --success-color: #28a745;
    --danger-color: #dc3545;
    --warning-color: #ffc107;
    --info-color: #17a2b8;
}

使用CSS變量統一管理主題色,便於維護和主題切換。

響應式設計
@media (max-width: 768px) {
    .container {
        padding: 15px;
    }
    
    .split-container {
        flex-direction: column;
    }
    
    .header-actions {
        flex-direction: column;
        align-items: flex-start;
        gap: 10px;
    }
}

媒體查詢實現移動端適配,在小屏幕上調整佈局。

暗黑模式實現
body.dark-mode {
    background-color: #1a1a1a;
    color: #e0e0e0;
}

body.dark-mode .container {
    background-color: #2d2d2d;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
}

通過body類名切換實現完整的暗黑主題。

3. JavaScript核心功能實現

3.1 初始化與狀態管理

document.addEventListener('DOMContentLoaded', function() {
    // 暗黑模式切換
    const darkModeToggle = document.getElementById('dark-mode-toggle');
    darkModeToggle.addEventListener('change', () => {
        document.body.classList.toggle('dark-mode', darkModeToggle.checked);
        localStorage.setItem('darkMode', darkModeToggle.checked);
    });
    
    // 初始化暗黑模式狀態
    if (localStorage.getItem('darkMode')) {
        darkModeToggle.checked = localStorage.getItem('darkMode') === 'true';
        document.body.classList.toggle('dark-mode', darkModeToggle.checked);
    }
});

使用localStorage持久化用户偏好設置。

3.2 標籤頁系統

// 標籤頁切換
const tabs = document.querySelectorAll('.tab');
const tabContents = document.querySelectorAll('.tab-content');

tabs.forEach(tab => {
    tab.addEventListener('click', () => {
        // 移除所有active類
        tabs.forEach(t => t.classList.remove('active'));
        tabContents.forEach(content => content.classList.remove('active'));
        
        // 添加active類到當前標籤和內容
        tab.classList.add('active');
        const tabId = tab.getAttribute('data-tab');
        document.getElementById(tabId).classList.add('active');
        
        // 保存當前標籤頁
        localStorage.setItem('lastTab', tabId);
    });
});

通過data屬性關聯標籤和內容,實現簡單的SPA效果。

3.3 文本處理功能詳解

實時文本統計
statsInput.addEventListener('input', () => {
    const text = statsInput.value;
    document.getElementById('char-count').textContent = text.length;
    
    const words = text.trim() ? text.trim().split(/\s+/) : [];
    document.getElementById('word-count').textContent = words.length;
    
    const lines = text.split('\n');
    document.getElementById('line-count').textContent = lines.length;
    
    const nonEmptyLines = lines.filter(line => line.trim());
    document.getElementById('non-empty-line-count').textContent = nonEmptyLines.length;
});

使用input事件實時更新統計信息,正則表達式/\s+/分割單詞。

正則表達式測試
document.getElementById('test-regex').addEventListener('click', () => {
    try {
        const text = regexInput.value;
        const pattern = document.getElementById('regex-pattern').value;
        const flags = document.getElementById('regex-flags').value;
        const regex = new RegExp(pattern, flags);
        const matches = text.match(regex);
        
        if (matches) {
            regexOutput.value = `找到 ${matches.length} 處匹配:\n${matches.join('\n')}`;
            
            // 高亮顯示匹配內容
            let highlighted = text;
            matches.forEach(match => {
                highlighted = highlighted.replaceAll(match, `<span class="match-highlight">${match}</span>`);
            });
            
            regexMatches.innerHTML = `<h4>匹配位置:</h4><div style="border:1px solid #ddd;padding:10px;">${highlighted}</div>`;
        }
    } catch (e) {
        // 錯誤處理
    }
});

動態創建正則表達式,提供可視化匹配結果。

3.4 JSON工具實現

JSON格式化與驗證
document.getElementById('format-json').addEventListener('click', () => {
    try {
        const jsonObj = JSON.parse(jsonInput.value);
        jsonOutput.value = JSON.stringify(jsonObj, null, 2); // 縮進2空格
        showStatus(jsonStatus, 'JSON格式化成功!', 'success');
    } catch (e) {
        showStatus(jsonStatus, `JSON格式化失敗: ${e.message}`, 'error');
    }
});

利用JSON.parse和JSON.stringify實現格式化和驗證。

JSON轉XML
function jsonToXml(jsonObj, nodeName = 'root') {
    let xml = '';
    
    if (typeof jsonObj === 'object' && jsonObj !== null) {
        if (Array.isArray(jsonObj)) {
            jsonObj.forEach((item, index) => {
                xml += jsonToXml(item, nodeName + '_' + index);
            });
        } else {
            xml += '<' + nodeName + '>';
            for (const key in jsonObj) {
                if (jsonObj.hasOwnProperty(key)) {
                    xml += jsonToXml(jsonObj[key], key);
                }
            }
            xml += '</' + nodeName + '>';
        }
    } else {
        xml += '<' + nodeName + '>' + jsonObj + '</' + nodeName + '>';
    }
    
    return xml;
}

遞歸遍歷JSON對象,構建XML字符串。

3.5 Base64文件處理

文件編碼
document.getElementById('encode-file').addEventListener('click', () => {
    const file = fileUpload.files[0];
    if (!file) {
        showStatus(document.getElementById('file-status'), '請先選擇文件', 'error');
        return;
    }
    
    const reader = new FileReader();
    reader.onload = (e) => {
        const base64 = e.target.result.split(',')[1]; // 移除data URL前綴
        document.getElementById('file-output').value = base64;
        showStatus(document.getElementById('file-status'), '文件編碼成功!', 'success');
    };
    reader.readAsDataURL(file);
});

使用FileReader API讀取文件並轉換為Base64。

3.6 加密功能實現

哈希計算
async function calculateHash(text, algorithm) {
    // 使用Web Crypto API計算哈希
    const encoder = new TextEncoder();
    const data = encoder.encode(text);
    const hashBuffer = await crypto.subtle.digest(algorithm, data);
    const hashArray = Array.from(new Uint8Array(hashBuffer));
    return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}

使用現代Web Crypto API,支持多種哈希算法。

AES加密
async function aesEncrypt(text, key, iv) {
    const encoder = new TextEncoder();
    const keyMaterial = await crypto.subtle.importKey(
        'raw',
        encoder.encode(key),
        { name: 'AES-CBC' },
        false,
        ['encrypt']
    );
    
    const ivArray = iv ? encoder.encode(iv) : crypto.getRandomValues(new Uint8Array(16));
    const data = encoder.encode(text);
    
    const encrypted = await crypto.subtle.encrypt(
        {
            name: 'AES-CBC',
            iv: ivArray
        },
        keyMaterial,
        data
    );
    
    // 返回IV和加密數據的Base64組合
    const result = new Uint8Array(ivArray.length + encrypted.byteLength);
    result.set(ivArray, 0);
    result.set(new Uint8Array(encrypted), ivArray.length);
    
    return btoa(String.fromCharCode.apply(null, result));
}

完整的AES-CBC加密實現,包含IV處理。

3.7 輔助函數系統

狀態顯示
function showStatus(element, message, type) {
    element.textContent = message;
    element.className = 'status-message ' + type;
    setTimeout(() => {
        element.textContent = '';
        element.className = 'status-message';
    }, 3000);
}

統一的用户反饋機制,3秒後自動消失。

剪貼板操作
function copyToClipboard(element) {
    element.select();
    document.execCommand('copy');
    
    // 取消選中
    if (window.getSelection) {
        window.getSelection().removeAllRanges();
    } else if (document.selection) {
        document.selection.empty();
    }
}

兼容多種瀏覽器的複製功能實現。

4. 技術亮點總結

  1. 用户體驗優化
  • 實時統計更新
  • 操作狀態反饋
  • 一鍵複製功能
  • 暗黑模式切換
  1. 代碼質量
  • 功能模塊化
  • 錯誤處理完善
  • 代碼複用度高
  1. 現代Web技術應用
  • 使用SS GridFlexbox佈局
  • 利用Web Crypto API進行加密
  • 使用File API處理文件

內部細節

  1. 完整的錯誤處理:所有操作都有try-catch包裝
  2. 用户體驗優化:實時反饋、狀態提示、一鍵複製
  3. 現代API使用FileReaderCryptolocalStorage
  4. 代碼複用性:輔助函數封裝良好
  5. 響應式設計:完美適配各種屏幕尺寸
  6. 主題系統:完整的亮色/暗色主題支持

這個工具網頁展示了前端開發的多個重要方面:DOM操作、事件處理、數據轉換、文件處理、加密算法等,功能全面,是一個很好的學習範例。

5. 源代碼

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>全能前端處理工具</title>
    <style>
        :root {
            --primary-color: #4a6fa5;
            --secondary-color: #6b8cae;
            --light-color: #f8f9fa;
            --dark-color: #343a40;
            --success-color: #28a745;
            --danger-color: #dc3545;
            --warning-color: #ffc107;
            --info-color: #17a2b8;
        }
        
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }
        
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            line-height: 1.6;
            background-color: #f5f5f5;
            color: var(--dark-color);
            padding: 20px;
        }
        
        .container {
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            background-color: white;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
        }
        
        h1 {
            text-align: center;
            margin-bottom: 30px;
            color: var(--primary-color);
        }
        
        .header-actions {
            display: flex;
            justify-content: space-between;
            margin-bottom: 20px;
            align-items: center;
        }
        
        .theme-switch {
            display: flex;
            align-items: center;
        }
        
        .theme-switch label {
            margin-right: 10px;
        }
        
        .tabs {
            display: flex;
            margin-bottom: 20px;
            border-bottom: 1px solid #ddd;
            flex-wrap: wrap;
        }
        
        .tab {
            padding: 10px 20px;
            cursor: pointer;
            background-color: #4a6fa5;
            border: none;
            border-radius: 5px 5px 0 0;
            margin-right: 5px;
            transition: all 0.3s;
            margin-bottom: 5px;
        }
        
        .tab:hover {
            background-color: #1782B8;
        }
        
        .tab.active {
            background-color: var(--primary-color); 
            background-color: #28A745;
            color: white;
        }
        
        .tab-content {
            display: none;
            padding: 20px;
            border: 1px solid #ddd;
            border-radius: 0 0 5px 5px;
            background-color: white;
        }
        
        .tab-content.active {
            display: block;
        }
        
        .tool-section {
            margin-bottom: 30px;
            border-bottom: 1px dashed #eee;
            padding-bottom: 20px;
        }
        
        .tool-section h2 {
            margin-bottom: 15px;
            color: var(--secondary-color);
            font-size: 1.3rem;
        }
        
        textarea {
            width: 100%;
            min-height: 150px;
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 4px;
            resize: vertical;
            font-family: Consolas, Monaco, 'Andale Mono', monospace;
            font-size: 14px;
        }
        
        .input-group {
            display: flex;
            gap: 10px;
            margin: 10px 0;
            align-items: center;
        }
        
        .input-group input, .input-group select {
            padding: 8px 12px;
            border: 1px solid #ddd;
            border-radius: 4px;
        }
        
        .button-group {
            display: flex;
            gap: 10px;
            margin: 10px 0;
            flex-wrap: wrap;
        }
        
        button {
            padding: 8px 15px;
            background-color: var(--primary-color);
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            transition: all 0.3s;
            display: flex;
            align-items: center;
            gap: 5px;
        }
        
        button:hover {
            background-color: var(--secondary-color);
        }
        
        button.secondary {
            background-color: #6c757d;
        }
        
        button.secondary:hover {
            background-color: #5a6268;
        }
        
        button.success {
            background-color: var(--success-color);
        }
        
        button.success:hover {
            background-color: #218838;
        }
        
        button.danger {
            background-color: var(--danger-color);
        }
        
        button.danger:hover {
            background-color: #c82333;
        }
        
        button.warning {
            background-color: var(--warning-color);
            color: var(--dark-color);
        }
        
        button.warning:hover {
            background-color: #e0a800;
        }
        
        button.info {
            background-color: var(--info-color);
        }
        
        button.info:hover {
            background-color: #138496;
        }
        
        .result-area {
            margin-top: 20px;
        }
        
        .copy-btn {
            margin-top: 10px;
        }
        
        .status-message {
            margin-top: 10px;
            padding: 8px;
            border-radius: 4px;
            display: none;
        }
        
        .status-message.success {
            display: block;
            background-color: #d4edda;
            color: #155724;
        }
        
        .status-message.error {
            display: block;
            background-color: #f8d7da;
            color: #721c24;
        }
        
        .status-message.info {
            display: block;
            background-color: #d1ecf1;
            color: #0c5460;
        }
        
        .match-highlight {
            background-color: yellow;
            padding: 0 2px;
        }
        
        .file-upload {
            display: none;
        }
        
        .file-upload-label {
            display: inline-block;
            padding: 8px 15px;
            background-color: var(--info-color);
            color: white;
            border-radius: 4px;
            cursor: pointer;
            transition: background-color 0.3s;
        }
        
        .file-upload-label:hover {
            background-color: #138496;
        }
        
        .file-info {
            margin-left: 10px;
            font-size: 0.9em;
            color: #666;
        }
        
        .split-container {
            display: flex;
            gap: 20px;
        }
        
        .split-panel {
            flex: 1;
        }
        
        .stats-container {
            display: flex;
            gap: 15px;
            margin-top: 10px;
            flex-wrap: wrap;
        }
        
        .stat-box {
            background-color: #f8f9fa;
            border: 1px solid #ddd;
            border-radius: 4px;
            padding: 8px 12px;
            min-width: 120px;
        }
        
        .stat-label {
            font-size: 0.8em;
            color: #666;
        }
        
        .stat-value {
            font-weight: bold;
            font-size: 1.2em;
        }
        
        /* ASCII碼錶樣式 */
        .ascii-table {
            width: 100%;
            border-collapse: collapse;
            margin-top: 15px;
        }
        
        .ascii-table th, .ascii-table td {
            border: 1px solid #ddd;
            padding: 8px;
            text-align: center;
        }
        
        .ascii-table th {
            background-color: var(--primary-color);
            color: white;
        }
        
        .ascii-table tr:nth-child(even) {
            background-color: #f2f2f2;
        }
        
        .ascii-table tr:hover {
            background-color: #e9e9e9;
        }
        
        .ascii-char {
            font-weight: bold;
        }
        
        .ascii-control {
            color: #666;
            font-style: italic;
        }
        
        /* 暗黑模式 */
        body.dark-mode {
            background-color: #1a1a1a;
            color: #e0e0e0;
        }
        
        body.dark-mode .container {
            background-color: #2d2d2d;
            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
        }
        
        body.dark-mode .tab {
            background-color: #3d3d3d;
            color: #e0e0e0;
        }
        
        body.dark-mode .tab:hover {
            background-color: #4d4d4d;
        }
        
        body.dark-mode .tab.active {
            background-color: var(--primary-color);
        }
        
        body.dark-mode .tab-content {
            background-color: #2d2d2d;
            border-color: #444;
        }
        
        body.dark-mode textarea {
            background-color: #333;
            color: #e0e0e0;
            border-color: #444;
        }
        
        body.dark-mode .input-group input, 
        body.dark-mode .input-group select {
            background-color: #333;
            color: #e0e0e0;
            border-color: #444;
        }
        
        body.dark-mode .stat-box {
            background-color: #333;
            border-color: #444;
        }
        
        body.dark-mode .match-highlight {
            background-color: #705700;
            color: #fff;
        }
        
        body.dark-mode .ascii-table th,
        body.dark-mode .ascii-table td {
            border-color: #444;
        }
        
        body.dark-mode .ascii-table th {
            background-color: #3d3d3d;
        }
        
        body.dark-mode .ascii-table tr:nth-child(even) {
            background-color: #333;
        }
        
        body.dark-mode .ascii-table tr:hover {
            background-color: #3a3a3a;
        }
        
        body.dark-mode .ascii-control {
            color: #aaa;
        }
        
        @media (max-width: 768px) {
            .container {
                padding: 15px;
            }
            
            .split-container {
                flex-direction: column;
            }
            
            .header-actions {
                flex-direction: column;
                align-items: flex-start;
                gap: 10px;
            }
            
            .input-group {
                flex-direction: column;
                align-items: flex-start;
            }
            
            .input-group input, .input-group select {
                width: 100%;
            }
            
            .ascii-table {
                font-size: 0.8em;
            }
            
            .ascii-table th, .ascii-table td {
                padding: 4px;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header-actions">
            <h1>全能前端處理工具</h1>
            <div class="theme-switch">
                <label for="dark-mode-toggle">暗黑模式:</label>
                <label class="switch">
                    <input type="checkbox" id="dark-mode-toggle">
                    <span class="slider round"></span>
                </label>
            </div>
        </div>
        
        <div class="tabs">
            <button class="tab active" data-tab="text-tools">文本處理</button>
            <button class="tab" data-tab="json-tools">JSON工具</button>
            <button class="tab" data-tab="base64-tools">Base64工具</button>
            <button class="tab" data-tab="encode-tools">編碼/加密</button>
            <button class="tab" data-tab="ascii-tools">ASCII工具</button>
            <button class="tab" data-tab="date-tools">時間工具</button>
        </div>
        
        <!-- 文本處理工具 -->
        <div id="text-tools" class="tab-content active">
            <div class="tool-section">
                <h2>文本統計</h2>
                <textarea id="stats-input" placeholder="輸入要統計的文本..."></textarea>
                <div class="stats-container">
                    <div class="stat-box">
                        <div class="stat-label">字符數</div>
                        <div class="stat-value" id="char-count">0</div>
                    </div>
                    <div class="stat-box">
                        <div class="stat-label">單詞數</div>
                        <div class="stat-value" id="word-count">0</div>
                    </div>
                    <div class="stat-box">
                        <div class="stat-label">行數</div>
                        <div class="stat-value" id="line-count">0</div>
                    </div>
                    <div class="stat-box">
                        <div class="stat-label">非空行</div>
                        <div class="stat-value" id="non-empty-line-count">0</div>
                    </div>
                </div>
            </div>
            
            <div class="tool-section">
                <h2>文本大小寫轉換</h2>
                <textarea id="text-input" placeholder="請輸入要處理的文本..."></textarea>
                <div class="button-group">
                    <button id="to-upper">轉換為大寫</button>
                    <button id="to-lower">轉換為小寫</button>
                    <button id="capitalize">首字母大寫</button>
                    <button id="title-case">標題格式</button>
                    <button id="trim-text">去除空格</button>
                    <button id="reverse-text">反轉文本</button>
                </div>
                <div class="result-area">
                    <label for="text-output">處理結果:</label>
                    <textarea id="text-output" readonly></textarea>
                    <button id="copy-text" class="copy-btn">複製結果</button>
                </div>
                <div id="text-status" class="status-message"></div>
            </div>
                
            <div class="tool-section">
                <h2>正則表達式測試</h2>
                <textarea id="regex-input" placeholder="輸入要測試的文本..."></textarea>
                <div class="input-group">
                    <input type="text" id="regex-pattern" placeholder="正則表達式" style="flex: 2;">
                    <input type="text" id="regex-replace" placeholder="替換文本(可選)" style="flex: 1;">
                    <select id="regex-flags">
                        <option value="g">全局(g)</option>
                        <option value="i">不區分大小寫(i)</option>
                        <option value="m">多行(m)</option>
                        <option value="gi">全局+不區分大小寫(gi)</option>
                        <option value="gm">全局+多行(gm)</option>
                        <option value="im">不區分大小寫+多行(im)</option>
                        <option value="gim">全部(gim)</option>
                    </select>
                </div>
                <div class="button-group">
                    <button id="test-regex" class="success">測試匹配</button>
                    <button id="replace-regex">替換文本</button>
                    <button id="regex-help" class="info">正則幫助</button>
                </div>
                <div class="result-area">
                    <label for="regex-output">結果:</label>
                    <textarea id="regex-output" readonly></textarea>
                    <div id="regex-matches" style="margin-top: 10px;"></div>
                    <button id="copy-regex" class="copy-btn">複製結果</button>
                </div>
                <div id="regex-status" class="status-message"></div>
            </div>
            
            <div class="tool-section">
                <h2>HTML轉義/反轉義</h2>
                <div class="split-container">
                    <div class="split-panel">
                        <label for="html-raw">原始HTML:</label>
                        <textarea id="html-raw" placeholder="輸入原始HTML..."></textarea>
                    </div>
                    <div class="split-panel">
                        <label for="html-escaped">轉義結果:</label>
                        <textarea id="html-escaped" placeholder="轉義後的HTML..."></textarea>
                    </div>
                </div>
                <div class="button-group">
                    <button id="escape-html" class="success">轉義HTML</button>
                    <button id="unescape-html" class="secondary">反轉義HTML</button>
                    <button id="copy-html-escaped" class="copy-btn">複製轉義結果</button>
                    <button id="copy-html-raw" class="copy-btn">複製原始HTML</button>
                </div>
            </div>
            
            <div class="tool-section">
                <h2>URL編碼/解碼</h2>
                <div class="split-container">
                    <div class="split-panel">
                        <label for="url-decoded">原始URL:</label>
                        <textarea id="url-decoded" placeholder="輸入原始URL..."></textarea>
                    </div>
                    <div class="split-panel">
                        <label for="url-encoded">編碼結果:</label>
                        <textarea id="url-encoded" placeholder="編碼後的URL..."></textarea>
                    </div>
                </div>
                <div class="button-group">
                    <button id="encode-url" class="success">編碼URL</button>
                    <button id="decode-url" class="secondary">解碼URL</button>
                    <button id="copy-url-encoded" class="copy-btn">複製編碼結果</button>
                    <button id="copy-url-decoded" class="copy-btn">複製原始URL</button>
                </div>
            </div>
        </div>
        
        <!-- JSON工具 -->
        <div id="json-tools" class="tab-content">
            <div class="tool-section">
                <h2>JSON格式化與壓縮</h2>
                <textarea id="json-input" placeholder='請輸入JSON字符串,例如: {"name":"John","age":30}'></textarea>
                <div class="button-group">
                    <button id="format-json" class="success">格式化JSON</button>
                    <button id="minify-json" class="secondary">壓縮JSON</button>
                    <button id="validate-json" class="secondary">驗證JSON</button>
                    <button id="clear-json" class="danger">清空</button>
                </div>
                <div class="result-area">
                    <label for="json-output">處理結果:</label>
                    <textarea id="json-output" readonly></textarea>
                    <button id="copy-json" class="copy-btn">複製結果</button>
                </div>
                <div id="json-status" class="status-message"></div>
            </div>
            
            <div class="tool-section">
                <h2>JSON轉換</h2>
                <textarea id="json-convert-input" placeholder='輸入要轉換的JSON...'></textarea>
                <div class="button-group">
                    <button id="json-to-xml" class="success">轉XML</button>
                    <button id="json-to-csv" class="success">轉CSV</button>
                    <button id="json-to-yaml" class="success">轉YAML</button>
                    <button id="clear-json-convert" class="danger">清空</button>
                </div>
                <div class="result-area">
                    <label for="json-convert-output">轉換結果:</label>
                    <textarea id="json-convert-output" readonly></textarea>
                    <button id="copy-json-convert" class="copy-btn">複製結果</button>
                </div>
                <div id="json-convert-status" class="status-message"></div>
            </div>
            
            <div class="tool-section">
                <h2>JSON路徑查詢</h2>
                <textarea id="json-path-input" placeholder='輸入JSON數據...'></textarea>
                <div class="input-group">
                    <input type="text" id="json-path" placeholder="JSON路徑 (如 $.store.book[0].title)" style="flex: 1;">
                    <button id="execute-json-path" class="success">查詢</button>
                </div>
                <div class="result-area">
                    <label for="json-path-output">查詢結果:</label>
                    <textarea id="json-path-output" readonly></textarea>
                    <button id="copy-json-path" class="copy-btn">複製結果</button>
                </div>
                <div id="json-path-status" class="status-message"></div>
            </div>
        </div>
        
        <!-- Base64工具 -->
        <div id="base64-tools" class="tab-content">
            <div class="tool-section">
                <h2>Base64文本編碼/解碼</h2>
                <textarea id="base64-input" placeholder="請輸入要編碼或解碼的文本..."></textarea>
                <div class="button-group">
                    <button id="encode-base64" class="success">Base64編碼</button>
                    <button id="decode-base64" class="secondary">Base64解碼</button>
                    <button id="clear-base64" class="danger">清空</button>
                </div>
                <div class="result-area">
                    <label for="base64-output">處理結果:</label>
                    <textarea id="base64-output" readonly></textarea>
                    <button id="copy-base64" class="copy-btn">複製結果</button>
                </div>
                <div id="base64-status" class="status-message"></div>
            </div>
            
            <div class="tool-section">
                <h2>Base64文件編碼</h2>
                <div class="input-group">
                    <label for="file-upload" class="file-upload-label">
                        <span>選擇文件</span>
                        <input type="file" id="file-upload" class="file-upload">
                    </label>
                    <span id="file-info" class="file-info">未選擇文件</span>
                </div>
                <div class="button-group">
                    <button id="encode-file" class="success">編碼文件</button>
                    <button id="clear-file" class="danger">清空</button>
                </div>
                <div class="result-area">
                    <label for="file-output">Base64編碼結果:</label>
                    <textarea id="file-output" readonly></textarea>
                    <button id="copy-file" class="copy-btn">複製結果</button>
                </div>
                <div id="file-status" class="status-message"></div>
            </div>
            
            <div class="tool-section">
                <h2>Base64圖片預覽</h2>
                <textarea id="image-base64-input" placeholder="輸入Base64編碼的圖片數據 (以data:image/開頭)..."></textarea>
                <div class="button-group">
                    <button id="preview-image" class="success">預覽圖片</button>
                    <button id="clear-image" class="danger">清空</button>
                </div>
                <div class="result-area">
                    <label>圖片預覽:</label>
                    <div id="image-preview-container" style="margin-top: 10px; text-align: center;">
                        <img id="image-preview" style="max-width: 100%; max-height: 300px; display: none;">
                        <div id="image-error" style="color: var(--danger-color); display: none;"></div>
                    </div>
                </div>
            </div>
        </div>
        
        <!-- 編碼/加密工具 -->
        <div id="encode-tools" class="tab-content">
            <div class="tool-section">
                <h2>哈希計算</h2>
                <textarea id="hash-input" placeholder="輸入要計算哈希的文本..."></textarea>
                <div class="button-group">
                    <button id="md5-hash" class="success">MD5</button>
                    <button id="sha1-hash" class="success">SHA-1</button>
                    <button id="sha256-hash" class="success">SHA-256</button>
                    <button id="sha512-hash" class="success">SHA-512</button>
                    <button id="clear-hash" class="danger">清空</button>
                </div>
                <div class="result-area">
                    <label for="hash-output">哈希結果:</label>
                    <textarea id="hash-output" readonly></textarea>
                    <button id="copy-hash" class="copy-btn">複製結果</button>
                </div>
            </div>
            
            <div class="tool-section">
                <h2>AES加密/解密</h2>
                <textarea id="aes-input" placeholder="輸入要加密/解密的文本..."></textarea>
                <div class="input-group">
                    <input type="password" id="aes-key" placeholder="密鑰" style="flex: 1;">
                    <input type="text" id="aes-iv" placeholder="IV (可選)" style="flex: 1;">
                </div>
                <div class="button-group">
                    <button id="aes-encrypt" class="success">AES加密</button>
                    <button id="aes-decrypt" class="secondary">AES解密</button>
                    <button id="clear-aes" class="danger">清空</button>
                </div>
                <div class="result-area">
                    <label for="aes-output">結果:</label>
                    <textarea id="aes-output" readonly></textarea>
                    <button id="copy-aes" class="copy-btn">複製結果</button>
                </div>
                <div id="aes-status" class="status-message"></div>
            </div>
        </div>
        
        <!-- ASCII工具 -->
        <div id="ascii-tools" class="tab-content">
            <div class="tool-section">
                <h2>字符串與ASCII碼轉換</h2>
                <div class="split-container">
                    <div class="split-panel">
                        <label for="ascii-text-input">文本:</label>
                        <textarea id="ascii-text-input" placeholder="輸入要轉換的文本..."></textarea>
                    </div>
                    <div class="split-panel">
                        <label for="ascii-code-input">ASCII碼 (空格或逗號分隔):</label>
                        <textarea id="ascii-code-input" placeholder="輸入ASCII碼,如: 72 101 108 108 111 或 72,101,108,108,111"></textarea>
                    </div>
                </div>
                <div class="button-group">
                    <button id="text-to-ascii" class="success">文本 → ASCII碼</button>
                    <button id="ascii-to-text" class="secondary">ASCII碼 → 文本</button>
                    <button id="clear-ascii" class="danger">清空</button>
                    <button id="copy-ascii-text" class="copy-btn">複製文本</button>
                    <button id="copy-ascii-code" class="copy-btn">複製ASCII碼</button>
                </div>
                <div class="input-group">
                    <label for="ascii-format">輸出格式:</label>
                    <select id="ascii-format">
                        <option value="space">空格分隔 (72 101 108 108 111)</option>
                        <option value="comma">逗號分隔 (72,101,108,108,111)</option>
                        <option value="hex">十六進制 (0x48 0x65 0x6C 0x6C 0x6F)</option>
                        <option value="hex-no-prefix">十六進制無前綴 (48 65 6C 6C 6F)</option>
                    </select>
                </div>
                <div id="ascii-status" class="status-message"></div>
            </div>
            
            <div class="tool-section">
                <h2>ASCII碼錶</h2>
                <div id="ascii-table" style="overflow-x: auto;">
                    <!-- ASCII碼錶將通過JavaScript動態生成 -->
                </div>
            </div>
        </div>
        
        <!-- 時間工具 -->
        <div id="date-tools" class="tab-content">
            <div class="tool-section">
                <h2>時間戳轉換</h2>
                <div class="input-group">
                    <input type="number" id="timestamp-input" placeholder="輸入Unix時間戳...">
                    <button id="timestamp-to-date" class="success">轉日期</button>
                    <button id="current-timestamp" class="secondary">當前時間戳</button>
                </div>
                <div class="input-group" style="margin-top: 10px;">
                    <input type="datetime-local" id="date-input">
                    <button id="date-to-timestamp" class="success">轉時間戳</button>
                </div>
                <div class="result-area">
                    <label for="timestamp-output">結果:</label>
                    <textarea id="timestamp-output" readonly></textarea>
                    <button id="copy-timestamp" class="copy-btn">複製結果</button>
                </div>
            </div>
            
            <div class="tool-section">
                <h2>日期計算</h2>
                <div class="input-group">
                    <input type="datetime-local" id="date-start">
                    <input type="datetime-local" id="date-end">
                    <button id="calculate-diff" class="success">計算差值</button>
                </div>
                <div class="result-area">
                    <label for="date-diff-output">時間差:</label>
                    <textarea id="date-diff-output" readonly></textarea>
                </div>
            </div>
        </div>
    </div>

    <script>
        document.addEventListener('DOMContentLoaded', function() {
            // 暗黑模式切換
            const darkModeToggle = document.getElementById('dark-mode-toggle');
            darkModeToggle.addEventListener('change', () => {
                document.body.classList.toggle('dark-mode', darkModeToggle.checked);
                localStorage.setItem('darkMode', darkModeToggle.checked);
            });
            
            // 初始化暗黑模式狀態
            if (localStorage.getItem('darkMode')) {
                darkModeToggle.checked = localStorage.getItem('darkMode') === 'true';
                document.body.classList.toggle('dark-mode', darkModeToggle.checked);
            }
            
            // 標籤頁切換
            const tabs = document.querySelectorAll('.tab');
            const tabContents = document.querySelectorAll('.tab-content');
            
            tabs.forEach(tab => {
                tab.addEventListener('click', () => {
                    // 移除所有active類
                    tabs.forEach(t => t.classList.remove('active'));
                    tabContents.forEach(content => content.classList.remove('active'));
                    
                    // 添加active類到當前標籤和內容
                    tab.classList.add('active');
                    const tabId = tab.getAttribute('data-tab');
                    document.getElementById(tabId).classList.add('active');
                    
                    // 保存當前標籤頁
                    localStorage.setItem('lastTab', tabId);
                });
            });
            
            // 恢復上次打開的標籤頁
            const lastTab = localStorage.getItem('lastTab') || 'text-tools';
            document.querySelector(`.tab[data-tab="${lastTab}"]`).click();
            
            // 文本處理功能
            const textInput = document.getElementById('text-input');
            const textOutput = document.getElementById('text-output');
            const textStatus = document.getElementById('text-status');
            
            document.getElementById('to-upper').addEventListener('click', () => {
                textOutput.value = textInput.value.toUpperCase();
                showStatus(textStatus, '轉換為大寫成功!', 'success');
            });
            
            document.getElementById('to-lower').addEventListener('click', () => {
                textOutput.value = textInput.value.toLowerCase();
                showStatus(textStatus, '轉換為小寫成功!', 'success');
            });
            
            document.getElementById('capitalize').addEventListener('click', () => {
                if (textInput.value.length > 0) {
                    textOutput.value = textInput.value.charAt(0).toUpperCase() + textInput.value.slice(1).toLowerCase();
                    showStatus(textStatus, '首字母大寫成功!', 'success');
                }
            });
            
            document.getElementById('title-case').addEventListener('click', () => {
                textOutput.value = textInput.value.toLowerCase().split(' ').map(word => 
                    word.charAt(0).toUpperCase() + word.slice(1)
                ).join(' ');
                showStatus(textStatus, '標題格式轉換成功!', 'success');
            });
            
            document.getElementById('trim-text').addEventListener('click', () => {
                textOutput.value = textInput.value.replace(/\s/g, '');
                showStatus(textStatus, '去除空格成功!', 'success');
            });
            
            document.getElementById('reverse-text').addEventListener('click', () => {
                textOutput.value = textInput.value.split('').reverse().join('');
                showStatus(textStatus, '文本反轉成功!', 'success');
            });
            
            document.getElementById('copy-text').addEventListener('click', () => {
                if (textOutput.value) {
                    copyToClipboard(textOutput);
                    showStatus(textStatus, '結果已複製到剪貼板!', 'success');
                }
            });
            
            // 文本統計功能
            const statsInput = document.getElementById('stats-input');
            
            statsInput.addEventListener('input', () => {
                const text = statsInput.value;
                document.getElementById('char-count').textContent = text.length;
                
                const words = text.trim() ? text.trim().split(/\s+/) : [];
                document.getElementById('word-count').textContent = words.length;
                
                const lines = text.split('\n');
                document.getElementById('line-count').textContent = lines.length;
                
                const nonEmptyLines = lines.filter(line => line.trim());
                document.getElementById('non-empty-line-count').textContent = nonEmptyLines.length;
            });
            
            // 正則表達式功能
            const regexInput = document.getElementById('regex-input');
            const regexOutput = document.getElementById('regex-output');
            const regexStatus = document.getElementById('regex-status');
            const regexMatches = document.getElementById('regex-matches');
            
            document.getElementById('test-regex').addEventListener('click', () => {
                try {
                    const text = regexInput.value;
                    const pattern = document.getElementById('regex-pattern').value;
                    const flags = document.getElementById('regex-flags').value;
                    const regex = new RegExp(pattern, flags);
                    const matches = text.match(regex);
                    
                    if (matches) {
                        regexOutput.value = `找到 ${matches.length} 處匹配:\n${matches.join('\n')}`;
                        
                        // 高亮顯示匹配內容
                        let highlighted = text;
                        matches.forEach(match => {
                            highlighted = highlighted.replaceAll(match, `<span class="match-highlight">${match}</span>`);
                        });
                        
                        regexMatches.innerHTML = `<h4>匹配位置:</h4><div style="border:1px solid #ddd;padding:10px;">${highlighted}</div>`;
                    } else {
                        regexOutput.value = "沒有找到匹配內容";
                        regexMatches.innerHTML = '';
                    }
                    showStatus(regexStatus, '正則匹配成功!', 'success');
                } catch (e) {
                    regexOutput.value = `正則表達式錯誤: ${e.message}`;
                    showStatus(regexStatus, `正則匹配失敗: ${e.message}`, 'error');
                }
            });
            
            document.getElementById('replace-regex').addEventListener('click', () => {
                try {
                    const text = regexInput.value;
                    const pattern = document.getElementById('regex-pattern').value;
                    const replacement = document.getElementById('regex-replace').value || '';
                    const flags = document.getElementById('regex-flags').value;
                    const regex = new RegExp(pattern, flags);
                    
                    regexOutput.value = text.replace(regex, replacement);
                    showStatus(regexStatus, '替換成功!', 'success');
                } catch (e) {
                    regexOutput.value = `替換錯誤: ${e.message}`;
                    showStatus(regexStatus, `替換失敗: ${e.message}`, 'error');
                }
            });
            
            document.getElementById('regex-help').addEventListener('click', () => {
                const helpText = `
常用正則表達式示例:
• 數字: \\d 或 [0-9]
• 非數字: \\D 或 [^0-9]
• 單詞字符: \\w 或 [a-zA-Z0-9_]
• 非單詞字符: \\W
• 空白字符: \\s
• 非空白字符: \\S
• 開始: ^
• 結束: $
• 任意字符: .
• 量詞: * (0或多個), + (1或多個), ? (0或1個), {n} (n個), {n,} (至少n個), {n,m} (n到m個)

示例:
• 郵箱: ^[\\w.-]+@[\\w.-]+\\.[a-zA-Z]{2,}$
• 手機號: ^1[3-9]\\d{9}$
• URL: ^https?:\\/\\/[\\w.-]+\\.[a-zA-Z]{2,}(\\/\\S*)?$
                `;
                regexOutput.value = helpText;
                showStatus(regexStatus, '正則表達式幫助已顯示', 'info');
            });
            
            document.getElementById('copy-regex').addEventListener('click', () => {
                if (regexOutput.value) {
                    copyToClipboard(regexOutput);
                    showStatus(regexStatus, '結果已複製到剪貼板!', 'success');
                }
            });
            
            // HTML轉義/反轉義
            document.getElementById('escape-html').addEventListener('click', () => {
                const raw = document.getElementById('html-raw').value;
                document.getElementById('html-escaped').value = escapeHtml(raw);
            });
            
            document.getElementById('unescape-html').addEventListener('click', () => {
                const escaped = document.getElementById('html-escaped').value;
                document.getElementById('html-raw').value = unescapeHtml(escaped);
            });
            
            document.getElementById('copy-html-escaped').addEventListener('click', () => {
                copyToClipboard(document.getElementById('html-escaped'));
            });
            
            document.getElementById('copy-html-raw').addEventListener('click', () => {
                copyToClipboard(document.getElementById('html-raw'));
            });
            
            // URL編碼/解碼
            document.getElementById('encode-url').addEventListener('click', () => {
                const decoded = document.getElementById('url-decoded').value;
                document.getElementById('url-encoded').value = encodeURIComponent(decoded);
            });
            
            document.getElementById('decode-url').addEventListener('click', () => {
                const encoded = document.getElementById('url-encoded').value;
                document.getElementById('url-decoded').value = decodeURIComponent(encoded);
            });
            
            document.getElementById('copy-url-encoded').addEventListener('click', () => {
                copyToClipboard(document.getElementById('url-encoded'));
            });
            
            document.getElementById('copy-url-decoded').addEventListener('click', () => {
                copyToClipboard(document.getElementById('url-decoded'));
            });
            
            // JSON處理功能
            const jsonInput = document.getElementById('json-input');
            const jsonOutput = document.getElementById('json-output');
            const jsonStatus = document.getElementById('json-status');
            
            document.getElementById('format-json').addEventListener('click', () => {
                try {
                    const jsonObj = JSON.parse(jsonInput.value);
                    jsonOutput.value = JSON.stringify(jsonObj, null, 2);
                    showStatus(jsonStatus, 'JSON格式化成功!', 'success');
                } catch (e) {
                    showStatus(jsonStatus, `JSON格式化失敗: ${e.message}`, 'error');
                }
            });
            
            document.getElementById('minify-json').addEventListener('click', () => {
                try {
                    const jsonObj = JSON.parse(jsonInput.value);
                    jsonOutput.value = JSON.stringify(jsonObj);
                    showStatus(jsonStatus, 'JSON壓縮成功!', 'success');
                } catch (e) {
                    showStatus(jsonStatus, `JSON壓縮失敗: ${e.message}`, 'error');
                }
            });
            
            document.getElementById('validate-json').addEventListener('click', () => {
                try {
                    JSON.parse(jsonInput.value);
                    showStatus(jsonStatus, 'JSON驗證成功!', 'success');
                } catch (e) {
                    showStatus(jsonStatus, `JSON驗證失敗: ${e.message}`, 'error');
                }
            });
            
            document.getElementById('clear-json').addEventListener('click', () => {
                jsonInput.value = '';
                jsonOutput.value = '';
                jsonStatus.textContent = '';
                jsonStatus.className = 'status-message';
            });
            
            document.getElementById('copy-json').addEventListener('click', () => {
                if (jsonOutput.value) {
                    copyToClipboard(jsonOutput);
                    showStatus(jsonStatus, '結果已複製到剪貼板!', 'success');
                }
            });
            
            // JSON轉換功能
            document.getElementById('json-to-xml').addEventListener('click', () => {
                try {
                    const jsonObj = JSON.parse(document.getElementById('json-convert-input').value);
                    document.getElementById('json-convert-output').value = jsonToXml(jsonObj);
                    showStatus(document.getElementById('json-convert-status'), 'JSON轉XML成功!', 'success');
                } catch (e) {
                    showStatus(document.getElementById('json-convert-status'), `JSON轉XML失敗: ${e.message}`, 'error');
                }
            });
            
            document.getElementById('json-to-csv').addEventListener('click', () => {
                try {
                    const jsonObj = JSON.parse(document.getElementById('json-convert-input').value);
                    document.getElementById('json-convert-output').value = jsonToCsv(jsonObj);
                    showStatus(document.getElementById('json-convert-status'), 'JSON轉CSV成功!', 'success');
                } catch (e) {
                    showStatus(document.getElementById('json-convert-status'), `JSON轉CSV失敗: ${e.message}`, 'error');
                }
            });
            
            document.getElementById('json-to-yaml').addEventListener('click', () => {
                try {
                    const jsonObj = JSON.parse(document.getElementById('json-convert-input').value);
                    document.getElementById('json-convert-output').value = jsonToYaml(jsonObj);
                    showStatus(document.getElementById('json-convert-status'), 'JSON轉YAML成功!', 'success');
                } catch (e) {
                    showStatus(document.getElementById('json-convert-status'), `JSON轉YAML失敗: ${e.message}`, 'error');
                }
            });
            
            document.getElementById('clear-json-convert').addEventListener('click', () => {
                document.getElementById('json-convert-input').value = '';
                document.getElementById('json-convert-output').value = '';
                document.getElementById('json-convert-status').textContent = '';
                document.getElementById('json-convert-status').className = 'status-message';
            });
            
            document.getElementById('copy-json-convert').addEventListener('click', () => {
                if (document.getElementById('json-convert-output').value) {
                    copyToClipboard(document.getElementById('json-convert-output'));
                    showStatus(document.getElementById('json-convert-status'), '結果已複製到剪貼板!', 'success');
                }
            });
            
            // JSON路徑查詢
            document.getElementById('execute-json-path').addEventListener('click', () => {
                try {
                    const jsonObj = JSON.parse(document.getElementById('json-path-input').value);
                    const path = document.getElementById('json-path').value;
                    
                    if (!path) {
                        showStatus(document.getElementById('json-path-status'), '請輸入JSON路徑', 'error');
                        return;
                    }
                    
                    // 簡單的JSON路徑查詢實現
                    const result = evaluateJsonPath(jsonObj, path);
                    document.getElementById('json-path-output').value = JSON.stringify(result, null, 2);
                    showStatus(document.getElementById('json-path-status'), '查詢成功!', 'success');
                } catch (e) {
                    showStatus(document.getElementById('json-path-status'), `查詢失敗: ${e.message}`, 'error');
                }
            });
            
            document.getElementById('copy-json-path').addEventListener('click', () => {
                if (document.getElementById('json-path-output').value) {
                    copyToClipboard(document.getElementById('json-path-output'));
                    showStatus(document.getElementById('json-path-status'), '結果已複製到剪貼板!', 'success');
                }
            });
            
            // Base64處理功能
            const base64Input = document.getElementById('base64-input');
            const base64Output = document.getElementById('base64-output');
            const base64Status = document.getElementById('base64-status');
            
            document.getElementById('encode-base64').addEventListener('click', () => {
                try {
                    base64Output.value = btoa(unescape(encodeURIComponent(base64Input.value)));
                    showStatus(base64Status, 'Base64編碼成功!', 'success');
                } catch (e) {
                    showStatus(base64Status, `Base64編碼失敗: ${e.message}`, 'error');
                }
            });
            
            document.getElementById('decode-base64').addEventListener('click', () => {
                try {
                    base64Output.value = decodeURIComponent(escape(atob(base64Input.value)));
                    showStatus(base64Status, 'Base64解碼成功!', 'success');
                } catch (e) {
                    showStatus(base64Status, `Base64解碼失敗: ${e.message}`, 'error');
                }
            });
            
            document.getElementById('clear-base64').addEventListener('click', () => {
                base64Input.value = '';
                base64Output.value = '';
                base64Status.textContent = '';
                base64Status.className = 'status-message';
            });
            
            document.getElementById('copy-base64').addEventListener('click', () => {
                if (base64Output.value) {
                    copyToClipboard(base64Output);
                    showStatus(base64Status, '結果已複製到剪貼板!', 'success');
                }
            });
            
            // Base64文件編碼
            const fileUpload = document.getElementById('file-upload');
            const fileInfo = document.getElementById('file-info');
            
            fileUpload.addEventListener('change', (e) => {
                const file = e.target.files[0];
                if (file) {
                    fileInfo.textContent = `${file.name} (${formatFileSize(file.size)})`;
                } else {
                    fileInfo.textContent = '未選擇文件';
                }
            });
            
            document.getElementById('encode-file').addEventListener('click', () => {
                const file = fileUpload.files[0];
                if (!file) {
                    showStatus(document.getElementById('file-status'), '請先選擇文件', 'error');
                    return;
                }
                
                const reader = new FileReader();
                reader.onload = (e) => {
                    const base64 = e.target.result.split(',')[1];
                    document.getElementById('file-output').value = base64;
                    showStatus(document.getElementById('file-status'), '文件編碼成功!', 'success');
                };
                reader.onerror = () => {
                    showStatus(document.getElementById('file-status'), '文件讀取失敗', 'error');
                };
                reader.readAsDataURL(file);
            });
            
            document.getElementById('clear-file').addEventListener('click', () => {
                fileUpload.value = '';
                fileInfo.textContent = '未選擇文件';
                document.getElementById('file-output').value = '';
                document.getElementById('file-status').textContent = '';
                document.getElementById('file-status').className = 'status-message';
            });
            
            document.getElementById('copy-file').addEventListener('click', () => {
                if (document.getElementById('file-output').value) {
                    copyToClipboard(document.getElementById('file-output'));
                    showStatus(document.getElementById('file-status'), '結果已複製到剪貼板!', 'success');
                }
            });
            
            // Base64圖片預覽
            document.getElementById('preview-image').addEventListener('click', () => {
                const base64 = document.getElementById('image-base64-input').value.trim();
                const imgPreview = document.getElementById('image-preview');
                const imgError = document.getElementById('image-error');
                
                if (!base64) {
                    imgError.textContent = '請輸入Base64編碼的圖片數據';
                    imgError.style.display = 'block';
                    imgPreview.style.display = 'none';
                    return;
                }
                
                try {
                    imgPreview.src = base64.startsWith('data:image/') ? base64 : `data:image/png;base64,${base64}`;
                    imgPreview.style.display = 'block';
                    imgError.style.display = 'none';
                } catch (e) {
                    imgError.textContent = `圖片預覽失敗: ${e.message}`;
                    imgError.style.display = 'block';
                    imgPreview.style.display = 'none';
                }
            });
            
            document.getElementById('clear-image').addEventListener('click', () => {
                document.getElementById('image-base64-input').value = '';
                document.getElementById('image-preview').style.display = 'none';
                document.getElementById('image-error').style.display = 'none';
            });
            
            // 哈希計算
            document.getElementById('md5-hash').addEventListener('click', async () => {
                const text = document.getElementById('hash-input').value;
                if (!text) {
                    document.getElementById('hash-output').value = '請輸入要計算哈希的文本';
                    return;
                }
                
                try {
                    const hash = await calculateHash(text, 'MD5');
                    document.getElementById('hash-output').value = hash;
                } catch (e) {
                    document.getElementById('hash-output').value = `MD5計算失敗: ${e.message}`;
                }
            });
            
            document.getElementById('sha1-hash').addEventListener('click', async () => {
                const text = document.getElementById('hash-input').value;
                if (!text) {
                    document.getElementById('hash-output').value = '請輸入要計算哈希的文本';
                    return;
                }
                
                try {
                    const hash = await calculateHash(text, 'SHA-1');
                    document.getElementById('hash-output').value = hash;
                } catch (e) {
                    document.getElementById('hash-output').value = `SHA-1計算失敗: ${e.message}`;
                }
            });
            
            document.getElementById('sha256-hash').addEventListener('click', async () => {
                const text = document.getElementById('hash-input').value;
                if (!text) {
                    document.getElementById('hash-output').value = '請輸入要計算哈希的文本';
                    return;
                }
                
                try {
                    const hash = await calculateHash(text, 'SHA-256');
                    document.getElementById('hash-output').value = hash;
                } catch (e) {
                    document.getElementById('hash-output').value = `SHA-256計算失敗: ${e.message}`;
                }
            });
            
            document.getElementById('sha512-hash').addEventListener('click', async () => {
                const text = document.getElementById('hash-input').value;
                if (!text) {
                    document.getElementById('hash-output').value = '請輸入要計算哈希的文本';
                    return;
                }
                
                try {
                    const hash = await calculateHash(text, 'SHA-512');
                    document.getElementById('hash-output').value = hash;
                } catch (e) {
                    document.getElementById('hash-output').value = `SHA-512計算失敗: ${e.message}`;
                }
            });
            
            document.getElementById('clear-hash').addEventListener('click', () => {
                document.getElementById('hash-input').value = '';
                document.getElementById('hash-output').value = '';
            });
            
            document.getElementById('copy-hash').addEventListener('click', () => {
                copyToClipboard(document.getElementById('hash-output'));
            });
            
            // AES加密/解密
            document.getElementById('aes-encrypt').addEventListener('click', async () => {
                try {
                    const text = document.getElementById('aes-input').value;
                    const key = document.getElementById('aes-key').value;
                    const iv = document.getElementById('aes-iv').value || undefined;
                    
                    if (!text || !key) {
                        showStatus(document.getElementById('aes-status'), '請輸入文本和密鑰', 'error');
                        return;
                    }
                    
                    const encrypted = await aesEncrypt(text, key, iv);
                    document.getElementById('aes-output').value = encrypted;
                    showStatus(document.getElementById('aes-status'), 'AES加密成功!', 'success');
                } catch (e) {
                    document.getElementById('aes-output').value = `AES加密失敗: ${e.message}`;
                    showStatus(document.getElementById('aes-status'), `AES加密失敗: ${e.message}`, 'error');
                }
            });
            
            document.getElementById('aes-decrypt').addEventListener('click', async () => {
                try {
                    const text = document.getElementById('aes-input').value;
                    const key = document.getElementById('aes-key').value;
                    const iv = document.getElementById('aes-iv').value || undefined;
                    
                    if (!text || !key) {
                        showStatus(document.getElementById('aes-status'), '請輸入文本和密鑰', 'error');
                        return;
                    }
                    
                    const decrypted = await aesDecrypt(text, key, iv);
                    document.getElementById('aes-output').value = decrypted;
                    showStatus(document.getElementById('aes-status'), 'AES解密成功!', 'success');
                } catch (e) {
                    document.getElementById('aes-output').value = `AES解密失敗: ${e.message}`;
                    showStatus(document.getElementById('aes-status'), `AES解密失敗: ${e.message}`, 'error');
                }
            });
            
            document.getElementById('clear-aes').addEventListener('click', () => {
                document.getElementById('aes-input').value = '';
                document.getElementById('aes-output').value = '';
                document.getElementById('aes-key').value = '';
                document.getElementById('aes-iv').value = '';
                document.getElementById('aes-status').textContent = '';
                document.getElementById('aes-status').className = 'status-message';
            });
            
            document.getElementById('copy-aes').addEventListener('click', () => {
                copyToClipboard(document.getElementById('aes-output'));
            });
            
            // 時間戳轉換
            document.getElementById('timestamp-to-date').addEventListener('click', () => {
                const timestamp = parseInt(document.getElementById('timestamp-input').value);
                if (isNaN(timestamp)) {
                    document.getElementById('timestamp-output').value = '請輸入有效的時間戳';
                    return;
                }
                
                const date = new Date(timestamp * 1000);
                document.getElementById('timestamp-output').value = date.toLocaleString();
                document.getElementById('date-input').value = formatDateTimeLocal(date);
            });
            
            document.getElementById('current-timestamp').addEventListener('click', () => {
                const now = Math.floor(Date.now() / 1000);
                document.getElementById('timestamp-input').value = now;
                document.getElementById('timestamp-output').value = new Date(now * 1000).toLocaleString();
                document.getElementById('date-input').value = formatDateTimeLocal(new Date());
            });
            
            document.getElementById('date-to-timestamp').addEventListener('click', () => {
                const dateStr = document.getElementById('date-input').value;
                if (!dateStr) {
                    document.getElementById('timestamp-output').value = '請選擇日期時間';
                    return;
                }
                
                const date = new Date(dateStr);
                const timestamp = Math.floor(date.getTime() / 1000);
                document.getElementById('timestamp-input').value = timestamp;
                document.getElementById('timestamp-output').value = `時間戳: ${timestamp}\n本地時間: ${date.toLocaleString()}`;
            });
            
            document.getElementById('copy-timestamp').addEventListener('click', () => {
                copyToClipboard(document.getElementById('timestamp-output'));
            });
            
            // 日期計算
            document.getElementById('calculate-diff').addEventListener('click', () => {
                const startStr = document.getElementById('date-start').value;
                const endStr = document.getElementById('date-end').value;
                
                if (!startStr || !endStr) {
                    document.getElementById('date-diff-output').value = '請選擇開始和結束日期時間';
                    return;
                }
                
                const start = new Date(startStr);
                const end = new Date(endStr);
                
                if (start > end) {
                    document.getElementById('date-diff-output').value = '結束時間必須晚於開始時間';
                    return;
                }
                
                const diffMs = end - start;
                const diffSec = Math.floor(diffMs / 1000);
                const diffMin = Math.floor(diffSec / 60);
                const diffHour = Math.floor(diffMin / 60);
                const diffDay = Math.floor(diffHour / 24);
                
                const result = [
                    `總毫秒數: ${diffMs}`,
                    `總秒數: ${diffSec}`,
                    `總分鐘數: ${diffMin}`,
                    `總小時數: ${diffHour}`,
                    `總天數: ${diffDay}`,
                    `詳細: ${diffDay}天 ${diffHour % 24}小時 ${diffMin % 60}分鐘 ${diffSec % 60}秒`
                ].join('\n');
                
                document.getElementById('date-diff-output').value = result;
            });
            
            // 初始化日期時間輸入為當前時間
            document.getElementById('date-input').value = formatDateTimeLocal(new Date());
            document.getElementById('date-start').value = formatDateTimeLocal(new Date());
            document.getElementById('date-end').value = formatDateTimeLocal(new Date(Date.now() + 3600000)); // 1小時後
            
            // ASCII工具功能
            const asciiTextInput = document.getElementById('ascii-text-input');
            const asciiCodeInput = document.getElementById('ascii-code-input');
            const asciiStatus = document.getElementById('ascii-status');
            
            // 文本轉ASCII碼
            document.getElementById('text-to-ascii').addEventListener('click', () => {
                const text = asciiTextInput.value;
                if (!text) {
                    showStatus(asciiStatus, '請輸入要轉換的文本', 'error');
                    return;
                }
                
                const format = document.getElementById('ascii-format').value;
                let asciiCodes = [];
                
                for (let i = 0; i < text.length; i++) {
                    asciiCodes.push(text.charCodeAt(i));
                }
                
                let result;
                switch (format) {
                    case 'space':
                        result = asciiCodes.join(' ');
                        break;
                    case 'comma':
                        result = asciiCodes.join(',');
                        break;
                    case 'hex':
                        result = asciiCodes.map(c => '0x' + c.toString(16).toUpperCase()).join(' ');
                        break;
                    case 'hex-no-prefix':
                        result = asciiCodes.map(c => c.toString(16).toUpperCase()).join(' ');
                        break;
                    default:
                        result = asciiCodes.join(' ');
                }
                
                asciiCodeInput.value = result;
                showStatus(asciiStatus, '文本轉換為ASCII碼成功!', 'success');
            });
            
            // ASCII碼轉文本
            document.getElementById('ascii-to-text').addEventListener('click', () => {
                const codeStr = asciiCodeInput.value.trim();
                if (!codeStr) {
                    showStatus(asciiStatus, '請輸入要轉換的ASCII碼', 'error');
                    return;
                }
                
                try {
                    // 處理不同格式的ASCII碼輸入
                    let codes = [];
                    if (codeStr.includes(',')) {
                        // 逗號分隔
                        codes = codeStr.split(',').map(s => parseInt(s.trim()));
                    } else if (codeStr.includes(' ')) {
                        // 空格分隔
                        codes = codeStr.split(/\s+/).map(s => {
                            // 處理十六進制格式 (0x... 或 純十六進制)
                            if (s.startsWith('0x') || s.startsWith('0X')) {
                                return parseInt(s, 16);
                            } else if (/^[0-9A-Fa-f]+$/.test(s)) {
                                // 可能是十六進制無前綴
                                return parseInt(s, 16);
                            } else {
                                return parseInt(s);
                            }
                        });
                    } else {
                        // 單個ASCII碼
                        codes = [parseInt(codeStr)];
                    }
                    
                    // 檢查是否有無效的ASCII碼
                    if (codes.some(isNaN)) {
                        throw new Error('包含無效的ASCII碼');
                    }
                    
                    // 將ASCII碼轉換為字符串
                    let text = '';
                    for (const code of codes) {
                        if (code < 0 || code > 255) {
                            throw new Error(`ASCII碼 ${code} 超出範圍 (0-255)`);
                        }
                        text += String.fromCharCode(code);
                    }
                    
                    asciiTextInput.value = text;
                    showStatus(asciiStatus, 'ASCII碼轉換為文本成功!', 'success');
                } catch (e) {
                    showStatus(asciiStatus, `轉換失敗: ${e.message}`, 'error');
                }
            });
            
            // 清空ASCII工具
            document.getElementById('clear-ascii').addEventListener('click', () => {
                asciiTextInput.value = '';
                asciiCodeInput.value = '';
                asciiStatus.textContent = '';
                asciiStatus.className = 'status-message';
            });
            
            // 複製ASCII文本
            document.getElementById('copy-ascii-text').addEventListener('click', () => {
                if (asciiTextInput.value) {
                    copyToClipboard(asciiTextInput);
                    showStatus(asciiStatus, '文本已複製到剪貼板!', 'success');
                }
            });
            
            // 複製ASCII碼
            document.getElementById('copy-ascii-code').addEventListener('click', () => {
                if (asciiCodeInput.value) {
                    copyToClipboard(asciiCodeInput);
                    showStatus(asciiStatus, 'ASCII碼已複製到剪貼板!', 'success');
                }
            });
            
            // 生成ASCII碼錶
            generateAsciiTable();
            
            // 輔助函數
            function showStatus(element, message, type) {
                element.textContent = message;
                element.className = 'status-message ' + type;
                setTimeout(() => {
                    element.textContent = '';
                    element.className = 'status-message';
                }, 3000);
            }
            
            function copyToClipboard(element) {
                element.select();
                document.execCommand('copy');
                
                // 取消選中
                if (window.getSelection) {
                    window.getSelection().removeAllRanges();
                } else if (document.selection) {
                    document.selection.empty();
                }
            }
            
            function escapeHtml(text) {
                const div = document.createElement('div');
                div.textContent = text;
                return div.innerHTML;
            }
            
            function unescapeHtml(html) {
                const div = document.createElement('div');
                div.innerHTML = html;
                return div.textContent;
            }
            
            function formatFileSize(bytes) {
                if (bytes === 0) return '0 Bytes';
                const k = 1024;
                const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
                const i = Math.floor(Math.log(bytes) / Math.log(k));
                return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
            }
            
            function jsonToXml(jsonObj, nodeName = 'root') {
                let xml = '';
                
                if (typeof jsonObj === 'object' && jsonObj !== null) {
                    if (Array.isArray(jsonObj)) {
                        jsonObj.forEach((item, index) => {
                            xml += jsonToXml(item, nodeName + '_' + index);
                        });
                    } else {
                        xml += '<' + nodeName + '>';
                        for (const key in jsonObj) {
                            if (jsonObj.hasOwnProperty(key)) {
                                xml += jsonToXml(jsonObj[key], key);
                            }
                        }
                        xml += '</' + nodeName + '>';
                    }
                } else {
                    xml += '<' + nodeName + '>' + jsonObj + '</' + nodeName + '>';
                }
                
                return xml;
            }
            
            function jsonToCsv(jsonObj) {
                if (Array.isArray(jsonObj)) {
                    if (jsonObj.length === 0) return '';
                    
                    // 獲取所有可能的鍵作為表頭
                    const headers = new Set();
                    jsonObj.forEach(item => {
                        if (typeof item === 'object' && item !== null) {
                            Object.keys(item).forEach(key => headers.add(key));
                        }
                    });
                    
                    const headerArray = Array.from(headers);
                    let csv = headerArray.join(',') + '\n';
                    
                    // 添加數據行
                    jsonObj.forEach(item => {
                        const row = headerArray.map(header => {
                            const value = item[header];
                            if (value === undefined || value === null) return '';
                            // 處理包含逗號或引號的值
                            const strValue = String(value).replace(/"/g, '""');
                            return `"${strValue}"`;
                        });
                        csv += row.join(',') + '\n';
                    });
                    
                    return csv;
                } else if (typeof jsonObj === 'object' && jsonObj !== null) {
                    // 單個對象轉換為單行CSV
                    const headers = Object.keys(jsonObj);
                    const row = headers.map(header => {
                        const value = jsonObj[header];
                        if (value === undefined || value === null) return '';
                        const strValue = String(value).replace(/"/g, '""');
                        return `"${strValue}"`;
                    });
                    return headers.join(',') + '\n' + row.join(',');
                } else {
                    return String(jsonObj);
                }
            }
            
            function jsonToYaml(jsonObj, indent = 0) {
                const spaces = '  '.repeat(indent);
                
                if (typeof jsonObj === 'object' && jsonObj !== null) {
                    if (Array.isArray(jsonObj)) {
                        if (jsonObj.length === 0) return '[]';
                        
                        let yaml = '';
                        jsonObj.forEach(item => {
                            yaml += spaces + '- ' + jsonToYaml(item, indent + 1).trimStart() + '\n';
                        });
                        return yaml;
                    } else {
                        const keys = Object.keys(jsonObj);
                        if (keys.length === 0) return '{}';
                        
                        let yaml = '';
                        keys.forEach(key => {
                            const value = jsonObj[key];
                            yaml += spaces + key + ': ' + jsonToYaml(value, indent + 1).trimStart() + '\n';
                        });
                        return yaml;
                    }
                } else if (typeof jsonObj === 'string') {
                    // 簡單字符串處理
                    if (jsonObj.includes('\n')) {
                        return '|\n' + spaces + '  ' + jsonObj.replace(/\n/g, '\n' + spaces + '  ');
                    }
                    return jsonObj;
                } else if (jsonObj === null) {
                    return 'null';
                } else {
                    return String(jsonObj);
                }
            }
            
            function evaluateJsonPath(obj, path) {
                // 簡單實現,不支持完整JSONPath語法
                try {
                    // 嘗試作為JavaScript表達式執行
                    const func = new Function('obj', 'return obj' + (path.startsWith('$') ? path.slice(1) : path));
                    return func(obj);
                } catch (e) {
                    throw new Error('不支持的JSON路徑表達式');
                }
            }
            
            async function calculateHash(text, algorithm) {
                // 使用Web Crypto API計算哈希
                const encoder = new TextEncoder();
                const data = encoder.encode(text);
                const hashBuffer = await crypto.subtle.digest(algorithm, data);
                const hashArray = Array.from(new Uint8Array(hashBuffer));
                return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
            }
            
            async function aesEncrypt(text, key, iv) {
                const encoder = new TextEncoder();
                const keyMaterial = await crypto.subtle.importKey(
                    'raw',
                    encoder.encode(key),
                    { name: 'AES-CBC' },
                    false,
                    ['encrypt']
                );
                
                const ivArray = iv ? encoder.encode(iv) : crypto.getRandomValues(new Uint8Array(16));
                const data = encoder.encode(text);
                
                const encrypted = await crypto.subtle.encrypt(
                    {
                        name: 'AES-CBC',
                        iv: ivArray
                    },
                    keyMaterial,
                    data
                );
                
                // 返回IV和加密數據的Base64組合
                const result = new Uint8Array(ivArray.length + encrypted.byteLength);
                result.set(ivArray, 0);
                result.set(new Uint8Array(encrypted), ivArray.length);
                
                return btoa(String.fromCharCode.apply(null, result));
            }
            
            async function aesDecrypt(encryptedText, key) {
                try {
                    const encoder = new TextEncoder();
                    const decoder = new TextDecoder();
                    
                    // 解碼Base64
                    const binaryString = atob(encryptedText);
                    const bytes = new Uint8Array(binaryString.length);
                    for (let i = 0; i < binaryString.length; i++) {
                        bytes[i] = binaryString.charCodeAt(i);
                    }
                    
                    // 提取IV (前16字節)和加密數據
                    const iv = bytes.slice(0, 16);
                    const data = bytes.slice(16);
                    
                    const keyMaterial = await crypto.subtle.importKey(
                        'raw',
                        encoder.encode(key),
                        { name: 'AES-CBC' },
                        false,
                        ['decrypt']
                    );
                    
                    const decrypted = await crypto.subtle.decrypt(
                        {
                            name: 'AES-CBC',
                            iv: iv
                        },
                        keyMaterial,
                        data
                    );
                    
                    return decoder.decode(decrypted);
                } catch (e) {
                    throw new Error('解密失敗: ' + e.message);
                }
            }
            
            function formatDateTimeLocal(date) {
                const year = date.getFullYear();
                const month = String(date.getMonth() + 1).padStart(2, '0');
                const day = String(date.getDate()).padStart(2, '0');
                const hours = String(date.getHours()).padStart(2, '0');
                const minutes = String(date.getMinutes()).padStart(2, '0');
                
                return `${year}-${month}-${day}T${hours}:${minutes}`;
            }
            
            function generateAsciiTable() {
                const table = document.createElement('table');
                table.className = 'ascii-table';
                
                // 表頭
                const thead = document.createElement('thead');
                const headerRow = document.createElement('tr');
                ['十進制', '十六進制', '字符', '描述'].forEach(text => {
                    const th = document.createElement('th');
                    th.textContent = text;
                    headerRow.appendChild(th);
                });
                thead.appendChild(headerRow);
                table.appendChild(thead);
                
                // 表體
                const tbody = document.createElement('tbody');
                
                // 生成0-127的ASCII碼
                for (let i = 0; i <= 127; i++) {
                    const tr = document.createElement('tr');
                    
                    // 十進制
                    const tdDec = document.createElement('td');
                    tdDec.textContent = i;
                    tr.appendChild(tdDec);
                    
                    // 十六進制
                    const tdHex = document.createElement('td');
                    tdHex.textContent = '0x' + i.toString(16).toUpperCase();
                    tr.appendChild(tdHex);
                    
                    // 字符
                    const tdChar = document.createElement('td');
                    const charSpan = document.createElement('span');
                    charSpan.className = i < 32 ? 'ascii-control' : 'ascii-char';
                    
                    if (i < 32) {
                        // 控制字符
                        charSpan.textContent = getControlCharName(i);
                    } else if (i === 32) {
                        charSpan.textContent = 'Space';
                    } else if (i === 127) {
                        charSpan.textContent = 'DEL';
                    } else {
                        charSpan.textContent = String.fromCharCode(i);
                    }
                    
                    tdChar.appendChild(charSpan);
                    tr.appendChild(tdChar);
                    
                    // 描述
                    const tdDesc = document.createElement('td');
                    tdDesc.textContent = getAsciiDescription(i);
                    tr.appendChild(tdDesc);
                    
                    tbody.appendChild(tr);
                }
                
                table.appendChild(tbody);
                document.getElementById('ascii-table').appendChild(table);
            }
            
            function getControlCharName(code) {
                const controlChars = [
                    'NUL', 'SOH', 'STX', 'ETX', 'EOT', 'ENQ', 'ACK', 'BEL',
                    'BS', 'HT', 'LF', 'VT', 'FF', 'CR', 'SO', 'SI',
                    'DLE', 'DC1', 'DC2', 'DC3', 'DC4', 'NAK', 'SYN', 'ETB',
                    'CAN', 'EM', 'SUB', 'ESC', 'FS', 'GS', 'RS', 'US'
                ];
                return controlChars[code] || '';
            }
            
            function getAsciiDescription(code) {
                const descriptions = {
                    0: '空字符',
                    1: '標題開始',
                    2: '正文開始',
                    3: '正文結束',
                    4: '傳輸結束',
                    5: '請求',
                    6: '確認迴應',
                    7: '響鈴',
                    8: '退格',
                    9: '水平製表符',
                    10: '換行',
                    11: '垂直製表符',
                    12: '換頁',
                    13: '回車',
                    14: '取消變換',
                    15: '啓用變換',
                    16: '數據鏈路轉義',
                    17: '設備控制1',
                    18: '設備控制2',
                    19: '設備控制3',
                    20: '設備控制4',
                    21: '拒絕接收',
                    22: '同步空閒',
                    23: '傳輸塊結束',
                    24: '取消',
                    25: '介質中斷',
                    26: '替換',
                    27: '逃逸',
                    28: '文件分隔符',
                    29: '組分隔符',
                    30: '記錄分隔符',
                    31: '單元分隔符',
                    32: '空格',
                    127: '刪除'
                };
                
                return descriptions[code] || (code >= 33 && code <= 126 ? '可打印字符' : '');
            }
        });
    </script>
</body>
</html>