- Remove all LuCI dependencies (luci-base, rpcd, luci-lib-jsonc) - Remove LuCI-specific files (RPCD backend, ACL, menu, JS views) - Package now only provides local opkg feed and documentation - Remove Packages.sig to avoid signature verification errors - Update local-build.sh to skip signature generation for local feeds Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
669 lines
24 KiB
HTML
669 lines
24 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="fr">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Auth Guardian - Démo Interactive | SecuBox</title>
|
||
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🔐</text></svg>">
|
||
<style>
|
||
:root {
|
||
--primary: #06b6d4;
|
||
--primary-dark: #0891b2;
|
||
--success: #22c55e;
|
||
--warning: #f59e0b;
|
||
--danger: #ef4444;
|
||
--dark: #0f172a;
|
||
--darker: #020617;
|
||
--card: #1e293b;
|
||
--text: #f1f5f9;
|
||
--text-muted: #94a3b8;
|
||
--border: #334155;
|
||
}
|
||
|
||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||
|
||
body {
|
||
font-family: system-ui, sans-serif;
|
||
background: var(--darker);
|
||
color: var(--text);
|
||
min-height: 100vh;
|
||
}
|
||
|
||
.header {
|
||
background: linear-gradient(135deg, var(--primary-dark), var(--primary));
|
||
padding: 40px 24px;
|
||
text-align: center;
|
||
}
|
||
|
||
.header h1 { font-size: 36px; margin-bottom: 8px; }
|
||
.header p { opacity: 0.9; font-size: 18px; }
|
||
|
||
.back-link {
|
||
position: absolute;
|
||
top: 20px;
|
||
left: 20px;
|
||
color: white;
|
||
text-decoration: none;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
opacity: 0.8;
|
||
}
|
||
|
||
.back-link:hover { opacity: 1; }
|
||
|
||
.container {
|
||
max-width: 1400px;
|
||
margin: 0 auto;
|
||
padding: 32px 24px;
|
||
}
|
||
|
||
.demo-grid {
|
||
display: grid;
|
||
grid-template-columns: 400px 1fr;
|
||
gap: 32px;
|
||
}
|
||
|
||
/* Splash Page Preview */
|
||
.splash-preview {
|
||
background: var(--dark);
|
||
border-radius: 20px;
|
||
overflow: hidden;
|
||
box-shadow: 0 20px 40px rgba(0,0,0,0.4);
|
||
}
|
||
|
||
.splash-header {
|
||
padding: 12px;
|
||
background: var(--card);
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.splash-dot {
|
||
width: 12px;
|
||
height: 12px;
|
||
border-radius: 50%;
|
||
}
|
||
|
||
.splash-dot:nth-child(1) { background: #ef4444; }
|
||
.splash-dot:nth-child(2) { background: #f59e0b; }
|
||
.splash-dot:nth-child(3) { background: #22c55e; }
|
||
|
||
.splash-content {
|
||
padding: 48px 32px;
|
||
text-align: center;
|
||
}
|
||
|
||
.splash-logo {
|
||
font-size: 64px;
|
||
margin-bottom: 24px;
|
||
}
|
||
|
||
.splash-title {
|
||
font-size: 28px;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.splash-message {
|
||
color: var(--text-muted);
|
||
margin-bottom: 32px;
|
||
}
|
||
|
||
.oauth-buttons {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 12px;
|
||
margin-bottom: 24px;
|
||
}
|
||
|
||
.oauth-btn {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 12px;
|
||
padding: 14px;
|
||
border-radius: 12px;
|
||
border: none;
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
}
|
||
|
||
.oauth-btn:hover {
|
||
transform: translateY(-2px);
|
||
}
|
||
|
||
.oauth-google {
|
||
background: white;
|
||
color: #333;
|
||
}
|
||
|
||
.oauth-github {
|
||
background: #333;
|
||
color: white;
|
||
}
|
||
|
||
.splash-divider {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 16px;
|
||
color: var(--text-muted);
|
||
margin: 24px 0;
|
||
}
|
||
|
||
.splash-divider::before,
|
||
.splash-divider::after {
|
||
content: '';
|
||
flex: 1;
|
||
height: 1px;
|
||
background: var(--border);
|
||
}
|
||
|
||
.voucher-input {
|
||
width: 100%;
|
||
padding: 14px;
|
||
border-radius: 12px;
|
||
border: 2px solid var(--border);
|
||
background: var(--card);
|
||
color: var(--text);
|
||
font-size: 18px;
|
||
text-align: center;
|
||
letter-spacing: 4px;
|
||
text-transform: uppercase;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.voucher-input:focus {
|
||
outline: none;
|
||
border-color: var(--primary);
|
||
}
|
||
|
||
.connect-btn {
|
||
width: 100%;
|
||
padding: 14px;
|
||
border-radius: 12px;
|
||
border: none;
|
||
background: linear-gradient(135deg, var(--primary-dark), var(--primary));
|
||
color: white;
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
transition: all 0.2s;
|
||
}
|
||
|
||
.connect-btn:hover {
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 8px 20px rgba(6, 182, 212, 0.4);
|
||
}
|
||
|
||
.splash-terms {
|
||
color: var(--text-muted);
|
||
font-size: 12px;
|
||
margin-top: 24px;
|
||
}
|
||
|
||
.splash-terms a {
|
||
color: var(--primary);
|
||
text-decoration: none;
|
||
}
|
||
|
||
/* Dashboard Panel */
|
||
.dashboard {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 24px;
|
||
}
|
||
|
||
.section {
|
||
background: var(--card);
|
||
border-radius: 16px;
|
||
padding: 24px;
|
||
border: 1px solid var(--border);
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
margin-bottom: 20px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.stats-row {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, 1fr);
|
||
gap: 16px;
|
||
margin-bottom: 24px;
|
||
}
|
||
|
||
.stat-card {
|
||
background: var(--dark);
|
||
padding: 20px;
|
||
border-radius: 12px;
|
||
text-align: center;
|
||
}
|
||
|
||
.stat-value {
|
||
font-size: 28px;
|
||
font-weight: 700;
|
||
color: var(--primary);
|
||
}
|
||
|
||
.stat-label {
|
||
color: var(--text-muted);
|
||
font-size: 13px;
|
||
margin-top: 4px;
|
||
}
|
||
|
||
.session-row {
|
||
display: grid;
|
||
grid-template-columns: 1fr 140px 100px 80px 100px;
|
||
gap: 16px;
|
||
padding: 14px 16px;
|
||
background: var(--dark);
|
||
border-radius: 10px;
|
||
margin-bottom: 10px;
|
||
align-items: center;
|
||
}
|
||
|
||
.session-row.header {
|
||
background: transparent;
|
||
font-weight: 600;
|
||
color: var(--text-muted);
|
||
font-size: 12px;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.session-user {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
}
|
||
|
||
.session-avatar {
|
||
width: 36px;
|
||
height: 36px;
|
||
background: var(--border);
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 18px;
|
||
}
|
||
|
||
.badge {
|
||
padding: 4px 10px;
|
||
border-radius: 6px;
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.badge-google { background: rgba(66, 133, 244, 0.2); color: #4285f4; }
|
||
.badge-github { background: rgba(255, 255, 255, 0.1); color: #fff; }
|
||
.badge-voucher { background: rgba(34, 197, 94, 0.2); color: #22c55e; }
|
||
.badge-splash { background: rgba(245, 158, 11, 0.2); color: #f59e0b; }
|
||
|
||
.voucher-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, 1fr);
|
||
gap: 12px;
|
||
}
|
||
|
||
.voucher-card {
|
||
background: var(--dark);
|
||
padding: 20px;
|
||
border-radius: 12px;
|
||
text-align: center;
|
||
transition: all 0.2s;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.voucher-card:hover {
|
||
background: var(--border);
|
||
}
|
||
|
||
.voucher-code {
|
||
font-family: monospace;
|
||
font-size: 16px;
|
||
font-weight: 700;
|
||
color: var(--primary);
|
||
letter-spacing: 2px;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.voucher-status {
|
||
font-size: 12px;
|
||
}
|
||
|
||
.voucher-unused { color: var(--success); }
|
||
.voucher-used { color: var(--text-muted); text-decoration: line-through; }
|
||
|
||
.generate-btn {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 8px;
|
||
width: 100%;
|
||
padding: 14px;
|
||
background: var(--primary);
|
||
border: none;
|
||
border-radius: 10px;
|
||
color: white;
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
margin-top: 16px;
|
||
transition: all 0.2s;
|
||
}
|
||
|
||
.generate-btn:hover {
|
||
background: var(--primary-dark);
|
||
}
|
||
|
||
.oauth-provider {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 16px;
|
||
padding: 16px;
|
||
background: var(--dark);
|
||
border-radius: 12px;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.oauth-icon {
|
||
font-size: 32px;
|
||
}
|
||
|
||
.oauth-info {
|
||
flex: 1;
|
||
}
|
||
|
||
.oauth-name {
|
||
font-weight: 600;
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.oauth-desc {
|
||
font-size: 13px;
|
||
color: var(--text-muted);
|
||
}
|
||
|
||
.oauth-status {
|
||
padding: 6px 14px;
|
||
border-radius: 8px;
|
||
font-weight: 600;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.oauth-enabled {
|
||
background: rgba(34, 197, 94, 0.2);
|
||
color: var(--success);
|
||
}
|
||
|
||
.oauth-disabled {
|
||
background: rgba(100, 116, 139, 0.2);
|
||
color: var(--text-muted);
|
||
}
|
||
|
||
@media (max-width: 1024px) {
|
||
.demo-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.stats-row {
|
||
grid-template-columns: repeat(2, 1fr);
|
||
}
|
||
|
||
.voucher-grid {
|
||
grid-template-columns: repeat(2, 1fr);
|
||
}
|
||
|
||
.session-row {
|
||
grid-template-columns: 1fr 100px 80px;
|
||
}
|
||
|
||
.session-row > *:nth-child(4),
|
||
.session-row > *:nth-child(5) {
|
||
display: none;
|
||
}
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="header">
|
||
<a href="index.html" class="back-link" data-i18n="demo.backToMain">← Retour à l'accueil</a>
|
||
<h1>🔐 Auth Guardian</h1>
|
||
<p>Authentification, OAuth & Vouchers</p>
|
||
</div>
|
||
|
||
<div class="container">
|
||
<div class="demo-grid">
|
||
<!-- Splash Page Preview -->
|
||
<div class="splash-preview">
|
||
<div class="splash-header">
|
||
<div class="splash-dot"></div>
|
||
<div class="splash-dot"></div>
|
||
<div class="splash-dot"></div>
|
||
<span style="flex: 1; text-align: center; color: var(--text-muted); font-size: 13px;">Portail Captif</span>
|
||
</div>
|
||
<div class="splash-content">
|
||
<div class="splash-logo">🔐</div>
|
||
<h2 class="splash-title">Bienvenue</h2>
|
||
<p class="splash-message">Authentifiez-vous pour accéder au réseau</p>
|
||
|
||
<div class="oauth-buttons">
|
||
<button class="oauth-btn oauth-google">
|
||
<svg width="20" height="20" viewBox="0 0 24 24"><path fill="#4285f4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"/><path fill="#34a853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/><path fill="#fbbc05" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/><path fill="#ea4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/></svg>
|
||
Se connecter avec Google
|
||
</button>
|
||
<button class="oauth-btn oauth-github">
|
||
<svg width="20" height="20" fill="#fff" viewBox="0 0 24 24"><path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z"/></svg>
|
||
Se connecter avec GitHub
|
||
</button>
|
||
</div>
|
||
|
||
<div class="splash-divider">ou avec un code</div>
|
||
|
||
<input type="text" class="voucher-input" placeholder="WIFI-XXXX" maxlength="9" id="voucher-input">
|
||
<button class="connect-btn" onclick="tryVoucher()">Connexion</button>
|
||
|
||
<p class="splash-terms">En vous connectant, vous acceptez nos <a href="#">Conditions d'utilisation</a></p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Dashboard -->
|
||
<div class="dashboard">
|
||
<!-- Stats -->
|
||
<div class="stats-row">
|
||
<div class="stat-card">
|
||
<div class="stat-value" id="stat-sessions">24</div>
|
||
<div class="stat-label">Sessions actives</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="stat-value">156</div>
|
||
<div class="stat-label">Connexions aujourd'hui</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="stat-value">12</div>
|
||
<div class="stat-label">Vouchers utilisés</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="stat-value" style="color: var(--success);">✓</div>
|
||
<div class="stat-label">Portail actif</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Active Sessions -->
|
||
<div class="section">
|
||
<div class="section-title">👥 Sessions actives</div>
|
||
|
||
<div class="session-row header">
|
||
<div>Utilisateur</div>
|
||
<div>IP</div>
|
||
<div>Auth</div>
|
||
<div>Durée</div>
|
||
<div>Données</div>
|
||
</div>
|
||
|
||
<div class="session-row">
|
||
<div class="session-user">
|
||
<div class="session-avatar">👩</div>
|
||
<div>
|
||
<div style="font-weight: 600;">Alice Martin</div>
|
||
<div style="font-size: 12px; color: var(--text-muted);">iPhone 14 Pro</div>
|
||
</div>
|
||
</div>
|
||
<div style="font-family: monospace; font-size: 13px;">192.168.1.101</div>
|
||
<div><span class="badge badge-google">Google</span></div>
|
||
<div style="color: var(--text-muted);">2h 34m</div>
|
||
<div style="color: var(--primary);">1.2 GB</div>
|
||
</div>
|
||
|
||
<div class="session-row">
|
||
<div class="session-user">
|
||
<div class="session-avatar">👨</div>
|
||
<div>
|
||
<div style="font-weight: 600;">Bob Dupont</div>
|
||
<div style="font-size: 12px; color: var(--text-muted);">MacBook Pro</div>
|
||
</div>
|
||
</div>
|
||
<div style="font-family: monospace; font-size: 13px;">192.168.1.105</div>
|
||
<div><span class="badge badge-github">GitHub</span></div>
|
||
<div style="color: var(--text-muted);">1h 12m</div>
|
||
<div style="color: var(--primary);">3.4 GB</div>
|
||
</div>
|
||
|
||
<div class="session-row">
|
||
<div class="session-user">
|
||
<div class="session-avatar">👤</div>
|
||
<div>
|
||
<div style="font-weight: 600;">Guest-7842</div>
|
||
<div style="font-size: 12px; color: var(--text-muted);">Android</div>
|
||
</div>
|
||
</div>
|
||
<div style="font-family: monospace; font-size: 13px;">192.168.1.112</div>
|
||
<div><span class="badge badge-voucher">Voucher</span></div>
|
||
<div style="color: var(--text-muted);">45m</div>
|
||
<div style="color: var(--primary);">450 MB</div>
|
||
</div>
|
||
|
||
<div class="session-row">
|
||
<div class="session-user">
|
||
<div class="session-avatar">👤</div>
|
||
<div>
|
||
<div style="font-weight: 600;">Guest-3156</div>
|
||
<div style="font-size: 12px; color: var(--text-muted);">Windows</div>
|
||
</div>
|
||
</div>
|
||
<div style="font-family: monospace; font-size: 13px;">192.168.1.118</div>
|
||
<div><span class="badge badge-splash">Splash</span></div>
|
||
<div style="color: var(--text-muted);">12m</div>
|
||
<div style="color: var(--primary);">85 MB</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Vouchers -->
|
||
<div class="section">
|
||
<div class="section-title">🎟️ Vouchers</div>
|
||
|
||
<div class="voucher-grid">
|
||
<div class="voucher-card">
|
||
<div class="voucher-code">WIFI-A7B2</div>
|
||
<div class="voucher-status voucher-unused">✓ Disponible</div>
|
||
</div>
|
||
<div class="voucher-card">
|
||
<div class="voucher-code">WIFI-C9D4</div>
|
||
<div class="voucher-status voucher-unused">✓ Disponible</div>
|
||
</div>
|
||
<div class="voucher-card">
|
||
<div class="voucher-code">WIFI-E5F8</div>
|
||
<div class="voucher-status voucher-used">Utilisé</div>
|
||
</div>
|
||
<div class="voucher-card">
|
||
<div class="voucher-code">WIFI-G1H6</div>
|
||
<div class="voucher-status voucher-unused">✓ Disponible</div>
|
||
</div>
|
||
</div>
|
||
|
||
<button class="generate-btn" onclick="generateVoucher()">
|
||
➕ Générer un nouveau voucher
|
||
</button>
|
||
</div>
|
||
|
||
<!-- OAuth Providers -->
|
||
<div class="section">
|
||
<div class="section-title">🔑 Fournisseurs OAuth</div>
|
||
|
||
<div class="oauth-provider">
|
||
<div class="oauth-icon">🔵</div>
|
||
<div class="oauth-info">
|
||
<div class="oauth-name">Google</div>
|
||
<div class="oauth-desc">Connexion avec compte Google</div>
|
||
</div>
|
||
<div class="oauth-status oauth-enabled">Activé</div>
|
||
</div>
|
||
|
||
<div class="oauth-provider">
|
||
<div class="oauth-icon">⚫</div>
|
||
<div class="oauth-info">
|
||
<div class="oauth-name">GitHub</div>
|
||
<div class="oauth-desc">Connexion avec compte GitHub</div>
|
||
</div>
|
||
<div class="oauth-status oauth-enabled">Activé</div>
|
||
</div>
|
||
|
||
<div class="oauth-provider">
|
||
<div class="oauth-icon">🔷</div>
|
||
<div class="oauth-info">
|
||
<div class="oauth-name">Facebook</div>
|
||
<div class="oauth-desc">Connexion avec compte Facebook</div>
|
||
</div>
|
||
<div class="oauth-status oauth-disabled">Désactivé</div>
|
||
</div>
|
||
|
||
<div class="oauth-provider">
|
||
<div class="oauth-icon">🐦</div>
|
||
<div class="oauth-info">
|
||
<div class="oauth-name">Twitter/X</div>
|
||
<div class="oauth-desc">Connexion avec compte Twitter</div>
|
||
</div>
|
||
<div class="oauth-status oauth-disabled">Désactivé</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
function generateVoucher() {
|
||
const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
|
||
let code = 'WIFI-';
|
||
for (let i = 0; i < 4; i++) {
|
||
code += chars.charAt(Math.floor(Math.random() * chars.length));
|
||
}
|
||
alert('Nouveau voucher généré: ' + code);
|
||
}
|
||
|
||
function tryVoucher() {
|
||
const input = document.getElementById('voucher-input').value.toUpperCase();
|
||
if (input.match(/^WIFI-[A-Z0-9]{4}$/)) {
|
||
alert('✅ Voucher valide! Connexion en cours...');
|
||
} else {
|
||
alert('❌ Code invalide. Format: WIFI-XXXX');
|
||
}
|
||
}
|
||
|
||
// Simulate active sessions count
|
||
setInterval(() => {
|
||
const sessions = 20 + Math.floor(Math.random() * 10);
|
||
document.getElementById('stat-sessions').textContent = sessions;
|
||
}, 5000);
|
||
</script>
|
||
|
||
<!-- Multi-language System -->
|
||
<script src="/i18n.js"></script>
|
||
</body>
|
||
</html>
|