feat: Implement new design and features for the main page
- Redesigned the main page with a modern look and feel. - Added search and filtering functionality for drills. - Implemented pagination for browsing drills. - Added the ability for users to mark drills as favorites.
35
admin/delete_user.php
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
require_once '../partials/header.php';
|
||||||
|
require_once '../db/config.php';
|
||||||
|
require_once '../auth.php';
|
||||||
|
|
||||||
|
// Ensure the user is logged in and is an admin
|
||||||
|
if (!is_logged_in() || !is_admin()) {
|
||||||
|
header('Location: ../login.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_GET['id']) && is_numeric($_GET['id'])) {
|
||||||
|
$user_id = $_GET['id'];
|
||||||
|
|
||||||
|
// Prevent admin from deleting their own account
|
||||||
|
if ($user_id == $_SESSION['user_id']) {
|
||||||
|
header('Location: users.php?error=' . urlencode('You cannot delete your own account.'));
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$db = db();
|
||||||
|
$stmt = $db->prepare("DELETE FROM users WHERE id = ?");
|
||||||
|
$stmt->execute([$user_id]);
|
||||||
|
|
||||||
|
header('Location: users.php?success=' . urlencode('User deleted successfully.'));
|
||||||
|
exit();
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
header('Location: users.php?error=' . urlencode('Error deleting user.'));
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
header('Location: users.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
123
admin/edit_user.php
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/../partials/header.php';
|
||||||
|
|
||||||
|
// Require admin role
|
||||||
|
if (!is_admin()) {
|
||||||
|
header('Location: ../index.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$user_id = $_GET['id'] ?? null;
|
||||||
|
|
||||||
|
if (!$user_id) {
|
||||||
|
header('Location: users.php?error=No user specified');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
$stmt = $pdo->prepare("SELECT id, name, email, role FROM users WHERE id = ?");
|
||||||
|
$stmt->execute([$user_id]);
|
||||||
|
$user = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (!$user) {
|
||||||
|
header('Location: users.php?error=User not found');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
error_log("Database error: " . $e->getMessage());
|
||||||
|
header('Location: users.php?error=A database error occurred.');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$pageTitle = 'Edit User';
|
||||||
|
$errors = [];
|
||||||
|
$roles = ['user', 'admin'];
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
$name = trim($_POST['name'] ?? '');
|
||||||
|
$email = trim($_POST['email'] ?? '');
|
||||||
|
$role = trim($_POST['role'] ?? '');
|
||||||
|
|
||||||
|
if (empty($name)) $errors[] = 'Name is required.';
|
||||||
|
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) $errors[] = 'A valid email is required.';
|
||||||
|
if (!in_array($role, $roles)) $errors[] = 'Invalid role selected.';
|
||||||
|
|
||||||
|
// Prevent admin from changing their own role
|
||||||
|
if ($user['id'] == get_user_id() && $role !== 'admin') {
|
||||||
|
$errors[] = 'You cannot change your own role from admin.';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (empty($errors)) {
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
$stmt = $pdo->prepare('UPDATE users SET name = ?, email = ?, role = ? WHERE id = ?');
|
||||||
|
$stmt->execute([$name, $email, $role, $user_id]);
|
||||||
|
|
||||||
|
header("Location: users.php?success=User updated successfully");
|
||||||
|
exit;
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
if ($e->errorInfo[1] == 1062) {
|
||||||
|
$errors[] = 'This email address is already in use by another user.';
|
||||||
|
} else {
|
||||||
|
$errors[] = "Database error: " . $e->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<header class="py-5 text-center container-fluid">
|
||||||
|
<div class="row py-lg-5">
|
||||||
|
<div class="col-lg-6 col-md-8 mx-auto">
|
||||||
|
<h1 class="display-4 fw-bold">Edit User</h1>
|
||||||
|
<p class="lead text-muted">Update user details.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="container">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-lg-6">
|
||||||
|
<div class="card shadow-sm mb-5">
|
||||||
|
<div class="card-body p-4">
|
||||||
|
<?php if (!empty($errors)) : ?>
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<ul class="mb-0">
|
||||||
|
<?php foreach ($errors as $error) : ?>
|
||||||
|
<li><?php echo htmlspecialchars($error); ?></li>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<form action="edit_user.php?id=<?php echo $user_id; ?>" method="POST" novalidate>
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<input type="text" class="form-control" id="name" name="name" placeholder="Full Name" required value="<?php echo htmlspecialchars($user['name']); ?>">
|
||||||
|
<label for="name">Name</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<input type="email" class="form-control" id="email" name="email" placeholder="name@example.com" required value="<?php echo htmlspecialchars($user['email']); ?>">
|
||||||
|
<label for="email">Email</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<select class="form-select" id="role" name="role" required>
|
||||||
|
<?php foreach ($roles as $r) : ?>
|
||||||
|
<option value="<?php echo $r; ?>" <?php echo ($user['role'] === $r) ? 'selected' : ''; ?>><?php echo ucfirst($r); ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
<label for="role">Role</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-grid">
|
||||||
|
<button type="submit" class="btn btn-primary btn-lg">Save Changes</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<?php require_once __DIR__ . '/../partials/footer.php'; ?>
|
||||||
91
admin/users.php
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once __DIR__ . '/../partials/header.php';
|
||||||
|
|
||||||
|
// Require admin role
|
||||||
|
if (!is_admin()) {
|
||||||
|
header('Location: ../index.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$pageTitle = 'Manage Users';
|
||||||
|
|
||||||
|
// Fetch all users
|
||||||
|
$users = [];
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
$stmt = $pdo->query("SELECT id, name, email, role, created_at FROM users ORDER BY created_at DESC");
|
||||||
|
$users = $stmt->fetchAll();
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
error_log("Database error: " . $e->getMessage());
|
||||||
|
// You could show a friendly error message to the user
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
<header class="py-5 text-center container-fluid">
|
||||||
|
<div class="row py-lg-5">
|
||||||
|
<div class="col-lg-6 col-md-8 mx-auto">
|
||||||
|
<h1 class="display-4 fw-bold">User Management</h1>
|
||||||
|
<p class="lead text-muted">Manage all registered users.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="container">
|
||||||
|
<?php if (isset($_GET['success'])) : ?>
|
||||||
|
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
||||||
|
<?php echo htmlspecialchars($_GET['success']); ?>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if (isset($_GET['error'])) : ?>
|
||||||
|
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
||||||
|
<?php echo htmlspecialchars($_GET['error']); ?>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<div class="card shadow-sm">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped table-hover align-middle">
|
||||||
|
<thead class="table-dark">
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Email</th>
|
||||||
|
<th>Role</th>
|
||||||
|
<th>Registered</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php if (empty($users)) : ?>
|
||||||
|
<tr>
|
||||||
|
<td colspan="6" class="text-center">No users found.</td>
|
||||||
|
</tr>
|
||||||
|
<?php else : ?>
|
||||||
|
<?php foreach ($users as $user) : ?>
|
||||||
|
<tr>
|
||||||
|
<td><?php echo htmlspecialchars($user['id']); ?></td>
|
||||||
|
<td><?php echo htmlspecialchars($user['name']); ?></td>
|
||||||
|
<td><?php echo htmlspecialchars($user['email']); ?></td>
|
||||||
|
<td><span class="badge bg-secondary"><?php echo htmlspecialchars($user['role']); ?></span></td>
|
||||||
|
<td><?php echo date('M j, Y', strtotime($user['created_at'])); ?></td>
|
||||||
|
<td>
|
||||||
|
<a href="edit_user.php?id=<?php echo $user['id']; ?>" class="btn btn-sm btn-outline-primary">Edit</a>
|
||||||
|
<a href="delete_user.php?id=<?php echo $user['id']; ?>"
|
||||||
|
class="btn btn-sm btn-outline-danger <?php echo ($user['id'] == $_SESSION['user_id']) ? 'disabled' : '' ?>"
|
||||||
|
onclick="return confirm('Are you sure you want to delete this user?');">Delete</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<?php require_once __DIR__ . '/../partials/footer.php'; ?>
|
||||||
105
assets/css/custom.css
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
body {
|
||||||
|
font-family: var(--font-body);
|
||||||
|
transition: background-color 0.3s, color 0.3s;
|
||||||
|
background-color: var(--background-color);
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
font-family: var(--font-heading);
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
border: 1px solid var(--card-border-color);
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
background-color: var(--card-background-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card:hover {
|
||||||
|
transform: translateY(-5px);
|
||||||
|
box-shadow: 0 8px 15px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar {
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
||||||
|
background-color: rgba(255, 255, 255, 0.8);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme='dark'] .navbar {
|
||||||
|
background-color: rgba(33, 37, 41, 0.8);
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control, .form-select {
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
background-color: var(--background-color);
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control:focus, .form-select:focus {
|
||||||
|
box-shadow: 0 0 0 0.25rem rgba(0, 123, 255, 0.25);
|
||||||
|
border-color: var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 0.75rem 1.5rem;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
background-color: var(--primary-color);
|
||||||
|
border: none;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary:hover {
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary {
|
||||||
|
background-color: var(--secondary-color);
|
||||||
|
border-color: var(--secondary-color);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-muted {
|
||||||
|
color: var(--text-color) !important;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg-light {
|
||||||
|
background-color: var(--light-gray) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-group-item {
|
||||||
|
background-color: var(--list-group-bg);
|
||||||
|
border-color: var(--list-group-border);
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
background-color: var(--card-background-color);
|
||||||
|
border-top: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.favorite-icon.is-favorite {
|
||||||
|
color: var(--secondary-color) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-text-primary {
|
||||||
|
fill: var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.favorite-icon:not(.is-favorite) {
|
||||||
|
color: var(--text-color);
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
47
assets/css/theme.css
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/* assets/css/theme.css */
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap');
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--font-body: 'Inter', sans-serif;
|
||||||
|
--font-heading: 'Inter', sans-serif;
|
||||||
|
--primary-color: #007bff;
|
||||||
|
--secondary-color: #ffc107;
|
||||||
|
--text-color: #212529;
|
||||||
|
--background-color: #ffffff;
|
||||||
|
--border-color: #dee2e6;
|
||||||
|
--light-gray: #f8f9fa;
|
||||||
|
--card-background-color: #ffffff;
|
||||||
|
--card-border-color: rgba(0, 0, 0, 0.125);
|
||||||
|
--list-group-bg: #fff;
|
||||||
|
--list-group-border: rgba(0, 0, 0, 0.125);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme="dark"] {
|
||||||
|
--text-color: #f8f9fa;
|
||||||
|
--background-color: #212529; /* Darker background */
|
||||||
|
--border-color: #495057;
|
||||||
|
--light-gray: #343a40; /* Darker shade for light gray elements */
|
||||||
|
--card-background-color: #343a40;
|
||||||
|
--card-border-color: rgba(255, 255, 255, 0.125);
|
||||||
|
--list-group-bg: #343a40;
|
||||||
|
--list-group-border: rgba(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: var(--background-color);
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
background-color: var(--card-background-color);
|
||||||
|
border: 1px solid var(--card-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-group {
|
||||||
|
background-color: var(--list-group-bg);
|
||||||
|
border: 1px solid var(--list-group-border);
|
||||||
|
}
|
||||||
|
.list-group-item {
|
||||||
|
background-color: var(--list-group-bg);
|
||||||
|
border-color: var(--list-group-border);
|
||||||
|
}
|
||||||
BIN
assets/images/drills/6935a50baccaa8.71246771.jpg
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
assets/images/drills/6935a51ec5b065.03239693.jpg
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
assets/images/drills/6935a5ec4cda08.99722189.jpg
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
assets/images/drills/6935a5fcc674b5.14447569.jpg
Normal file
|
After Width: | Height: | Size: 463 KiB |
BIN
assets/images/drills/6935a60a6335d8.08108298.jpg
Normal file
|
After Width: | Height: | Size: 463 KiB |
4
assets/images/favicon.svg
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<svg width="32" height="32" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect width="32" height="32" rx="5" ry="5" fill="#007bff"/>
|
||||||
|
<text x="50%" y="50%" dominant-baseline="middle" text-anchor="middle" font-family="Arial, sans-serif" font-size="20" font-weight="bold" fill="white">D</text>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 317 B |
5
assets/images/logo.svg
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<svg width="250" height="60" viewBox="0 0 250 60" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<text x="10" y="45" font-family="Arial, sans-serif" font-size="40" font-weight="bold">
|
||||||
|
<tspan fill="#343a40">Drill</tspan><tspan fill="#007bff">ex</tspan>
|
||||||
|
</text>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 264 B |
20
assets/js/main.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
const themeSwitcher = document.getElementById('theme-switcher');
|
||||||
|
const body = document.body;
|
||||||
|
|
||||||
|
// Set the default theme to light if no preference is saved
|
||||||
|
const savedTheme = localStorage.getItem('theme') || 'light';
|
||||||
|
body.setAttribute('data-theme', savedTheme);
|
||||||
|
themeSwitcher.checked = savedTheme === 'dark';
|
||||||
|
|
||||||
|
themeSwitcher.addEventListener('change', function() {
|
||||||
|
if (this.checked) {
|
||||||
|
body.setAttribute('data-theme', 'dark');
|
||||||
|
localStorage.setItem('theme', 'dark');
|
||||||
|
} else {
|
||||||
|
body.setAttribute('data-theme', 'light');
|
||||||
|
localStorage.setItem('theme', 'light');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
35
auth.php
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
require_once __DIR__ . '/db/config.php';
|
||||||
|
|
||||||
|
function login($email, $password) {
|
||||||
|
$pdo = db();
|
||||||
|
$stmt = $pdo->prepare("SELECT * FROM users WHERE email = :email");
|
||||||
|
$stmt->execute(['email' => $email]);
|
||||||
|
$user = $stmt->fetch();
|
||||||
|
|
||||||
|
if ($user && password_verify($password, $user['password'])) {
|
||||||
|
return $user;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_logged_in() {
|
||||||
|
return isset($_SESSION['user_id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_admin() {
|
||||||
|
return is_logged_in() && $_SESSION['user_role'] === 'admin';
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_user_id() {
|
||||||
|
return $_SESSION['user_id'] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_youtube_id_from_url($url)
|
||||||
|
{
|
||||||
|
$pattern =
|
||||||
|
'/(?:youtube\.com\/(?:[^\/\n\s]+\/\S+\/|(?:v|e(?:mbed)?)\/|\S*?[?&]v=)|youtu\.be\/)([a-zA-Z0-9_-]{11})/';
|
||||||
|
preg_match($pattern, $url, $matches);
|
||||||
|
return $matches[1] ?? '';
|
||||||
|
}
|
||||||
1788
composer-setup.php
Normal file
13
composer.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"name": "ubuntu/workspace",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Flatlogic Bot",
|
||||||
|
"email": "support@flatlogic.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"require": {
|
||||||
|
"hybridauth/hybridauth": "^3.12",
|
||||||
|
"dompdf/dompdf": "^3.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
369
composer.lock
generated
Normal file
@ -0,0 +1,369 @@
|
|||||||
|
{
|
||||||
|
"_readme": [
|
||||||
|
"This file locks the dependencies of your project to a known state",
|
||||||
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
|
"This file is @generated automatically"
|
||||||
|
],
|
||||||
|
"content-hash": "c5cc786aec2b2d784c75a8bff73f343e",
|
||||||
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "dompdf/dompdf",
|
||||||
|
"version": "v3.1.4",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/dompdf/dompdf.git",
|
||||||
|
"reference": "db712c90c5b9868df3600e64e68da62e78a34623"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/dompdf/dompdf/zipball/db712c90c5b9868df3600e64e68da62e78a34623",
|
||||||
|
"reference": "db712c90c5b9868df3600e64e68da62e78a34623",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"dompdf/php-font-lib": "^1.0.0",
|
||||||
|
"dompdf/php-svg-lib": "^1.0.0",
|
||||||
|
"ext-dom": "*",
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"masterminds/html5": "^2.0",
|
||||||
|
"php": "^7.1 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"ext-gd": "*",
|
||||||
|
"ext-json": "*",
|
||||||
|
"ext-zip": "*",
|
||||||
|
"mockery/mockery": "^1.3",
|
||||||
|
"phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11",
|
||||||
|
"squizlabs/php_codesniffer": "^3.5",
|
||||||
|
"symfony/process": "^4.4 || ^5.4 || ^6.2 || ^7.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-gd": "Needed to process images",
|
||||||
|
"ext-gmagick": "Improves image processing performance",
|
||||||
|
"ext-imagick": "Improves image processing performance",
|
||||||
|
"ext-zlib": "Needed for pdf stream compression"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Dompdf\\": "src/"
|
||||||
|
},
|
||||||
|
"classmap": [
|
||||||
|
"lib/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"LGPL-2.1"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "The Dompdf Community",
|
||||||
|
"homepage": "https://github.com/dompdf/dompdf/blob/master/AUTHORS.md"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter",
|
||||||
|
"homepage": "https://github.com/dompdf/dompdf",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/dompdf/dompdf/issues",
|
||||||
|
"source": "https://github.com/dompdf/dompdf/tree/v3.1.4"
|
||||||
|
},
|
||||||
|
"time": "2025-10-29T12:43:30+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "dompdf/php-font-lib",
|
||||||
|
"version": "1.0.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/dompdf/php-font-lib.git",
|
||||||
|
"reference": "6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/dompdf/php-font-lib/zipball/6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d",
|
||||||
|
"reference": "6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"php": "^7.1 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"symfony/phpunit-bridge": "^3 || ^4 || ^5 || ^6"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"FontLib\\": "src/FontLib"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"LGPL-2.1-or-later"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "The FontLib Community",
|
||||||
|
"homepage": "https://github.com/dompdf/php-font-lib/blob/master/AUTHORS.md"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A library to read, parse, export and make subsets of different types of font files.",
|
||||||
|
"homepage": "https://github.com/dompdf/php-font-lib",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/dompdf/php-font-lib/issues",
|
||||||
|
"source": "https://github.com/dompdf/php-font-lib/tree/1.0.1"
|
||||||
|
},
|
||||||
|
"time": "2024-12-02T14:37:59+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "dompdf/php-svg-lib",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/dompdf/php-svg-lib.git",
|
||||||
|
"reference": "eb045e518185298eb6ff8d80d0d0c6b17aecd9af"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/eb045e518185298eb6ff8d80d0d0c6b17aecd9af",
|
||||||
|
"reference": "eb045e518185298eb6ff8d80d0d0c6b17aecd9af",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"php": "^7.1 || ^8.0",
|
||||||
|
"sabberworm/php-css-parser": "^8.4"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Svg\\": "src/Svg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"LGPL-3.0-or-later"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "The SvgLib Community",
|
||||||
|
"homepage": "https://github.com/dompdf/php-svg-lib/blob/master/AUTHORS.md"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A library to read, parse and export to PDF SVG files.",
|
||||||
|
"homepage": "https://github.com/dompdf/php-svg-lib",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/dompdf/php-svg-lib/issues",
|
||||||
|
"source": "https://github.com/dompdf/php-svg-lib/tree/1.0.0"
|
||||||
|
},
|
||||||
|
"time": "2024-04-29T13:26:35+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hybridauth/hybridauth",
|
||||||
|
"version": "v3.12.2",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/hybridauth/hybridauth.git",
|
||||||
|
"reference": "c6184bf92404394e918353a0ea0d35a97ac3b0fe"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/hybridauth/hybridauth/zipball/c6184bf92404394e918353a0ea0d35a97ac3b0fe",
|
||||||
|
"reference": "c6184bf92404394e918353a0ea0d35a97ac3b0fe",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^5.4 || ^7.0 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"ext-curl": "*",
|
||||||
|
"phpunit/phpunit": "^4.8.35 || ^6.5 || ^8.0 || ^12.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"firebase/php-jwt": "Needed to support Apple provider",
|
||||||
|
"phpseclib/phpseclib": "Needed to support Apple provider"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Hybridauth\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Miled",
|
||||||
|
"email": "hybridauth@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "PHP Social Authentication Library",
|
||||||
|
"homepage": "https://hybridauth.github.io",
|
||||||
|
"keywords": [
|
||||||
|
"Authentication",
|
||||||
|
"OpenId",
|
||||||
|
"api",
|
||||||
|
"apple",
|
||||||
|
"authorization",
|
||||||
|
"facebook",
|
||||||
|
"google",
|
||||||
|
"oauth",
|
||||||
|
"social",
|
||||||
|
"twitter"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"gitter": "https://gitter.im/hybridauth/hybridauth",
|
||||||
|
"issues": "https://github.com/hybridauth/hybridauth/issues",
|
||||||
|
"source": "https://github.com/hybridauth/hybridauth/tree/v3.12.2"
|
||||||
|
},
|
||||||
|
"time": "2025-06-18T11:58:48+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "masterminds/html5",
|
||||||
|
"version": "2.10.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/Masterminds/html5-php.git",
|
||||||
|
"reference": "fcf91eb64359852f00d921887b219479b4f21251"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/Masterminds/html5-php/zipball/fcf91eb64359852f00d921887b219479b4f21251",
|
||||||
|
"reference": "fcf91eb64359852f00d921887b219479b4f21251",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-dom": "*",
|
||||||
|
"php": ">=5.3.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "2.7-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Masterminds\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Matt Butcher",
|
||||||
|
"email": "technosophos@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Matt Farina",
|
||||||
|
"email": "matt@mattfarina.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Asmir Mustafic",
|
||||||
|
"email": "goetas@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "An HTML5 parser and serializer.",
|
||||||
|
"homepage": "http://masterminds.github.io/html5-php",
|
||||||
|
"keywords": [
|
||||||
|
"HTML5",
|
||||||
|
"dom",
|
||||||
|
"html",
|
||||||
|
"parser",
|
||||||
|
"querypath",
|
||||||
|
"serializer",
|
||||||
|
"xml"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/Masterminds/html5-php/issues",
|
||||||
|
"source": "https://github.com/Masterminds/html5-php/tree/2.10.0"
|
||||||
|
},
|
||||||
|
"time": "2025-07-25T09:04:22+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sabberworm/php-css-parser",
|
||||||
|
"version": "v8.9.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/MyIntervals/PHP-CSS-Parser.git",
|
||||||
|
"reference": "d8e916507b88e389e26d4ab03c904a082aa66bb9"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/d8e916507b88e389e26d4ab03c904a082aa66bb9",
|
||||||
|
"reference": "d8e916507b88e389e26d4ab03c904a082aa66bb9",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-iconv": "*",
|
||||||
|
"php": "^5.6.20 || ^7.0.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "5.7.27 || 6.5.14 || 7.5.20 || 8.5.41",
|
||||||
|
"rawr/cross-data-providers": "^2.0.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-mbstring": "for parsing UTF-8 CSS"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-main": "9.0.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Sabberworm\\CSS\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Raphael Schweikert"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Oliver Klee",
|
||||||
|
"email": "github@oliverklee.de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jake Hotson",
|
||||||
|
"email": "jake.github@qzdesign.co.uk"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Parser for CSS Files written in PHP",
|
||||||
|
"homepage": "https://www.sabberworm.com/blog/2010/6/10/php-css-parser",
|
||||||
|
"keywords": [
|
||||||
|
"css",
|
||||||
|
"parser",
|
||||||
|
"stylesheet"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/MyIntervals/PHP-CSS-Parser/issues",
|
||||||
|
"source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v8.9.0"
|
||||||
|
},
|
||||||
|
"time": "2025-07-11T13:20:48+00:00"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"packages-dev": [],
|
||||||
|
"aliases": [],
|
||||||
|
"minimum-stability": "stable",
|
||||||
|
"stability-flags": {},
|
||||||
|
"prefer-stable": false,
|
||||||
|
"prefer-lowest": false,
|
||||||
|
"platform": {},
|
||||||
|
"platform-dev": {},
|
||||||
|
"plugin-api-version": "2.9.0"
|
||||||
|
}
|
||||||
254
create_drill.php
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/partials/header.php';
|
||||||
|
|
||||||
|
// Require login
|
||||||
|
if (!is_logged_in()) {
|
||||||
|
header('Location: login.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$pageTitle = 'Create a New Drill';
|
||||||
|
$pageDescription = 'Add a new football/soccer drill to the library.';
|
||||||
|
|
||||||
|
$errors = [];
|
||||||
|
$successMessage = '';
|
||||||
|
|
||||||
|
// Define selectable options
|
||||||
|
$age_groups = ['U6-U8', 'U9-U12', 'U13-U16', 'U17+', 'Adults'];
|
||||||
|
$skill_focuses = ['Dribbling', 'Passing', 'Shooting', 'Defense', 'Goalkeeping', 'Crossing', 'Finishing', 'First Touch'];
|
||||||
|
$difficulties = ['Beginner', 'Intermediate', 'Advanced'];
|
||||||
|
|
||||||
|
// Fetch categories
|
||||||
|
$pdo = db();
|
||||||
|
$stmt = $pdo->query("SELECT * FROM categories ORDER BY name");
|
||||||
|
$categories = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
// Sanitize and validate inputs
|
||||||
|
$title = trim($_POST['title'] ?? '');
|
||||||
|
$description = trim($_POST['description'] ?? '');
|
||||||
|
$min_players = filter_input(INPUT_POST, 'min_players', FILTER_VALIDATE_INT);
|
||||||
|
$max_players = filter_input(INPUT_POST, 'max_players', FILTER_VALIDATE_INT);
|
||||||
|
$age_group = trim($_POST['age_group'] ?? '');
|
||||||
|
$skill_focus = trim($_POST['skill_focus'] ?? '');
|
||||||
|
$difficulty = trim($_POST['difficulty'] ?? '');
|
||||||
|
$duration_minutes = filter_input(INPUT_POST, 'duration_minutes', FILTER_VALIDATE_INT);
|
||||||
|
$equipment_required = trim($_POST['equipment_required'] ?? '');
|
||||||
|
$youtube_url = filter_input(INPUT_POST, 'youtube_url', FILTER_VALIDATE_URL);
|
||||||
|
$is_public = isset($_POST['is_public']) ? 1 : 0;
|
||||||
|
$selected_categories = $_POST['categories'] ?? [];
|
||||||
|
$image_path = null;
|
||||||
|
|
||||||
|
// Basic validation
|
||||||
|
if (empty($title)) $errors[] = 'Title is required.';
|
||||||
|
if (empty($description)) $errors[] = 'Description is required.';
|
||||||
|
if ($min_players === false || $min_players < 1) $errors[] = 'Minimum players must be a positive number.';
|
||||||
|
if ($max_players === false || $max_players < $min_players) $errors[] = 'Maximum players must be greater than or equal to minimum players.';
|
||||||
|
if (!in_array($age_group, $age_groups)) $errors[] = 'Invalid age group selected.';
|
||||||
|
if (!in_array($skill_focus, $skill_focuses)) $errors[] = 'Invalid skill focus selected.';
|
||||||
|
if (!in_array($difficulty, $difficulties)) $errors[] = 'Invalid difficulty selected.';
|
||||||
|
if ($duration_minutes === false || $duration_minutes < 1) $errors[] = 'Duration must be a positive number.';
|
||||||
|
if ($youtube_url === false && !empty($_POST['youtube_url'])) $errors[] = 'YouTube URL is not a valid URL.';
|
||||||
|
if (empty($selected_categories)) $errors[] = 'At least one category must be selected.';
|
||||||
|
|
||||||
|
// Image upload handling
|
||||||
|
if (isset($_FILES['drill_image']) && $_FILES['drill_image']['error'] === UPLOAD_ERR_OK) {
|
||||||
|
$upload_dir = __DIR__ . '/assets/images/drills/';
|
||||||
|
if (!is_dir($upload_dir)) {
|
||||||
|
mkdir($upload_dir, 0775, true);
|
||||||
|
}
|
||||||
|
$file = $_FILES['drill_image'];
|
||||||
|
$file_ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
|
||||||
|
$allowed_exts = ['jpg', 'jpeg', 'png', 'gif'];
|
||||||
|
|
||||||
|
if (in_array($file_ext, $allowed_exts)) {
|
||||||
|
if ($file['size'] <= 5 * 1024 * 1024) { // 5MB limit
|
||||||
|
$new_filename = uniqid('', true) . '.' . $file_ext;
|
||||||
|
$destination = $upload_dir . $new_filename;
|
||||||
|
if (move_uploaded_file($file['tmp_name'], $destination)) {
|
||||||
|
$image_path = '/assets/images/drills/' . $new_filename;
|
||||||
|
} else {
|
||||||
|
$errors[] = 'Failed to move uploaded file.';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$errors[] = 'File is too large. Maximum size is 5MB.';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$errors[] = 'Invalid file type. Only JPG, JPEG, PNG, and GIF are allowed.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($errors)) {
|
||||||
|
try {
|
||||||
|
$pdo->beginTransaction();
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare(
|
||||||
|
'INSERT INTO drills (title, description, min_players, max_players, age_group, skill_focus, difficulty, duration_minutes, equipment_required, youtube_url, is_public, coach_id, image_path)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'
|
||||||
|
);
|
||||||
|
|
||||||
|
$coach_id = get_user_id();
|
||||||
|
|
||||||
|
$stmt->execute([
|
||||||
|
$title,
|
||||||
|
$description,
|
||||||
|
$min_players,
|
||||||
|
$max_players,
|
||||||
|
$age_group,
|
||||||
|
$skill_focus,
|
||||||
|
$difficulty,
|
||||||
|
$duration_minutes,
|
||||||
|
$equipment_required,
|
||||||
|
$youtube_url ?: null,
|
||||||
|
$is_public,
|
||||||
|
$coach_id,
|
||||||
|
$image_path
|
||||||
|
]);
|
||||||
|
|
||||||
|
$newDrillId = $pdo->lastInsertId();
|
||||||
|
|
||||||
|
// Insert into drill_categories
|
||||||
|
$stmt = $pdo->prepare('INSERT INTO drill_categories (drill_id, category_id) VALUES (?, ?)');
|
||||||
|
foreach ($selected_categories as $category_id) {
|
||||||
|
$stmt->execute([$newDrillId, $category_id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$pdo->commit();
|
||||||
|
|
||||||
|
// Redirect to the new drill page
|
||||||
|
header("Location: drill.php?id=" . $newDrillId . "&created=true");
|
||||||
|
exit;
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$pdo->rollBack();
|
||||||
|
// In a real app, log this error instead of displaying it
|
||||||
|
$errors[] = "Database error: " . $e->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<main class="container my-5">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-lg-9 col-xl-8">
|
||||||
|
<div class="card shadow-lg border-0 rounded-4">
|
||||||
|
<div class="card-body p-4 p-sm-5">
|
||||||
|
<div class="text-center mb-4">
|
||||||
|
<h1 class="h2 fw-bold">Create a New Drill</h1>
|
||||||
|
<p class="text-muted">Contribute to the Drillex collection by adding your own drill.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if (!empty($errors)) : ?>
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<p class="mb-0"><strong>Please fix the following errors:</strong></p>
|
||||||
|
<ul class="mb-0">
|
||||||
|
<?php foreach ($errors as $error) : ?>
|
||||||
|
<li><?php echo htmlspecialchars($error); ?></li>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<form action="create_drill.php" method="POST" enctype="multipart/form-data" novalidate>
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<input type="text" class="form-control" id="title" name="title" placeholder="Drill Title" required value="<?php echo htmlspecialchars($_POST['title'] ?? ''); ?>">
|
||||||
|
<label for="title">Drill Title</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<textarea class="form-control" id="description" name="description" placeholder="Description & Instructions" style="height: 150px" required><?php echo htmlspecialchars($_POST['description'] ?? ''); ?></textarea>
|
||||||
|
<label for="description">Description & Instructions</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="drill_image" class="form-label">Drill Image</label>
|
||||||
|
<input class="form-control" type="file" id="drill_image" name="drill_image">
|
||||||
|
<div class="form-text">Upload an image for the drill (JPG, PNG, GIF - max 5MB).</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row g-3 mb-3">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="form-floating">
|
||||||
|
<input type="number" class="form-control" id="min_players" name="min_players" placeholder="Min. Players" min="1" required value="<?php echo htmlspecialchars($_POST['min_players'] ?? '2'); ?>">
|
||||||
|
<label for="min_players">Min. Players</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="form-floating">
|
||||||
|
<input type="number" class="form-control" id="max_players" name="max_players" placeholder="Max. Players" min="1" required value="<?php echo htmlspecialchars($_POST['max_players'] ?? '16'); ?>">
|
||||||
|
<label for="max_players">Max. Players</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row g-3 mb-3">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="form-floating">
|
||||||
|
<select class="form-select" id="age_group" name="age_group" required>
|
||||||
|
<?php foreach ($age_groups as $group) : ?>
|
||||||
|
<option value="<?php echo $group; ?>" <?php echo (($_POST['age_group'] ?? '') === $group) ? 'selected' : ''; ?>><?php echo $group; ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
<label for="age_group">Age Group</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="form-floating">
|
||||||
|
<select class="form-select" id="difficulty" name="difficulty" required>
|
||||||
|
<?php foreach ($difficulties as $level) : ?>
|
||||||
|
<option value="<?php echo $level; ?>" <?php echo (($_POST['difficulty'] ?? '') === $level) ? 'selected' : ''; ?>><?php echo $level; ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
<label for="difficulty">Difficulty</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<select class="form-select" id="skill_focus" name="skill_focus" required>
|
||||||
|
<?php foreach ($skill_focuses as $focus) : ?>
|
||||||
|
<option value="<?php echo $focus; ?>" <?php echo (($_POST['skill_focus'] ?? '') === $focus) ? 'selected' : ''; ?>><?php echo $focus; ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
<label for="skill_focus">Primary Skill Focus</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="categories" class="form-label">Categories</label>
|
||||||
|
<select class="form-select" id="categories" name="categories[]" multiple required size="5">
|
||||||
|
<?php foreach ($categories as $category) : ?>
|
||||||
|
<option value="<?php echo $category['id']; ?>" <?php echo in_array($category['id'], $_POST['categories'] ?? []) ? 'selected' : ''; ?>><?php echo htmlspecialchars($category['name']); ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
<div class="form-text">Select one or more categories (hold Ctrl or Cmd to select multiple).</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<input type="number" class="form-control" id="duration_minutes" name="duration_minutes" placeholder="Duration (minutes)" min="1" required value="<?php echo htmlspecialchars($_POST['duration_minutes'] ?? '15'); ?>">
|
||||||
|
<label for="duration_minutes">Duration (minutes)</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<input type="text" class="form-control" id="equipment_required" name="equipment_required" placeholder="e.g., Cones, balls, bibs" value="<?php echo htmlspecialchars($_POST['equipment_required'] ?? ''); ?>">
|
||||||
|
<label for="equipment_required">Equipment Required</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-floating mb-4">
|
||||||
|
<input type="url" class="form-control" id="youtube_url" name="youtube_url" placeholder="https://www.youtube.com/watch?v=..." value="<?php echo htmlspecialchars($_POST['youtube_url'] ?? ''); ?>">
|
||||||
|
<label for="youtube_url">YouTube Video URL (Optional)</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-check form-switch mb-4">
|
||||||
|
<input class="form-check-input" type="checkbox" role="switch" id="is_public" name="is_public" value="1" checked>
|
||||||
|
<label class="form-check-label" for="is_public">Make this drill public immediately</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-grid">
|
||||||
|
<button type="submit" class="btn btn-primary btn-lg rounded-pill">Create Drill</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<?php require_once __DIR__ . '/partials/footer.php'; ?>
|
||||||
113
create_training_session.php
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/partials/header.php';
|
||||||
|
|
||||||
|
// Require login
|
||||||
|
if (!is_logged_in()) {
|
||||||
|
header('Location: login.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$pageTitle = 'Create Training Session';
|
||||||
|
$pageDescription = 'Build a new training session from your drills.';
|
||||||
|
|
||||||
|
$coach_id = get_user_id();
|
||||||
|
$pdo = db();
|
||||||
|
$errors = [];
|
||||||
|
|
||||||
|
// Fetch the coach's drills
|
||||||
|
$stmt = $pdo->prepare("SELECT id, title FROM drills WHERE coach_id = ? ORDER BY title");
|
||||||
|
$stmt->execute([$coach_id]);
|
||||||
|
$drills = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
$name = trim($_POST['name'] ?? '');
|
||||||
|
$description = trim($_POST['description'] ?? '');
|
||||||
|
$selected_drills = $_POST['drills'] ?? [];
|
||||||
|
|
||||||
|
if (empty($name)) $errors[] = 'Session name is required.';
|
||||||
|
if (empty($selected_drills)) $errors[] = 'You must select at least one drill.';
|
||||||
|
|
||||||
|
if (empty($errors)) {
|
||||||
|
try {
|
||||||
|
$pdo->beginTransaction();
|
||||||
|
|
||||||
|
// Insert the new session
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO training_sessions (coach_id, name, description) VALUES (?, ?, ?)");
|
||||||
|
$stmt->execute([$coach_id, $name, $description]);
|
||||||
|
$session_id = $pdo->lastInsertId();
|
||||||
|
|
||||||
|
// Link drills to the session
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO training_session_drills (session_id, drill_id, sequence) VALUES (?, ?, ?)");
|
||||||
|
$sequence = 0;
|
||||||
|
foreach ($selected_drills as $drill_id) {
|
||||||
|
$stmt->execute([$session_id, $drill_id, ++$sequence]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$pdo->commit();
|
||||||
|
header('Location: training_sessions.php?status=created');
|
||||||
|
exit();
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$pdo->rollBack();
|
||||||
|
$errors[] = "Database error: " . $e->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<main class="container my-5">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<div class="card shadow-sm border-0 rounded-4">
|
||||||
|
<div class="card-body p-4">
|
||||||
|
<h1 class="h3 mb-4 text-center">Create a New Training Session</h1>
|
||||||
|
|
||||||
|
<?php if (!empty($errors)): ?>
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<ul class="mb-0">
|
||||||
|
<?php foreach ($errors as $error): ?>
|
||||||
|
<li><?php echo htmlspecialchars($error); ?></li>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<form action="create_training_session.php" method="POST">
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<input type="text" class="form-control" id="name" name="name" placeholder="Session Name" required value="<?php echo htmlspecialchars($_POST['name'] ?? ''); ?>">
|
||||||
|
<label for="name">Session Name</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<textarea class="form-control" id="description" name="description" placeholder="Session Description" style="height: 120px;"><?php echo htmlspecialchars($_POST['description'] ?? ''); ?></textarea>
|
||||||
|
<label for="description">Description (Optional)</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-4">
|
||||||
|
<label class="form-label">Select Drills</label>
|
||||||
|
<div class="list-group" style="max-height: 300px; overflow-y: auto;">
|
||||||
|
<?php if (empty($drills)): ?>
|
||||||
|
<div class="list-group-item">You have no drills to add. <a href="create_drill.php">Create one now</a>.</div>
|
||||||
|
<?php else: ?>
|
||||||
|
<?php foreach ($drills as $drill): ?>
|
||||||
|
<label class="list-group-item">
|
||||||
|
<input class="form-check-input me-2" type="checkbox" name="drills[]" value="<?php echo $drill['id']; ?>" <?php echo in_array($drill['id'], $_POST['drills'] ?? []) ? 'checked' : ''; ?>>
|
||||||
|
<?php echo htmlspecialchars($drill['title']); ?>
|
||||||
|
</label>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
<div class="form-text">Select one or more drills to include in this session.</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-grid">
|
||||||
|
<button type="submit" class="btn btn-primary btn-lg">Create Session</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<?php require_once __DIR__ . '/partials/footer.php'; ?>
|
||||||
28
db/category_seed.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/config.php';
|
||||||
|
|
||||||
|
$categories = [
|
||||||
|
'Fitness',
|
||||||
|
'Passing',
|
||||||
|
'Dribbling',
|
||||||
|
'Shooting',
|
||||||
|
'Defense',
|
||||||
|
'Goalkeeping',
|
||||||
|
'Set Pieces',
|
||||||
|
'Tactical'
|
||||||
|
];
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
$stmt = $pdo->prepare("INSERT IGNORE INTO categories (name) VALUES (?)");
|
||||||
|
|
||||||
|
foreach ($categories as $category) {
|
||||||
|
$stmt->execute([$category]);
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Categories seeded successfully.\n";
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
die("Error seeding categories: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
55
db/migrate.php
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/config.php';
|
||||||
|
|
||||||
|
function get_migrated_files($pdo) {
|
||||||
|
$stmt = $pdo->query("SHOW TABLES LIKE 'migrations'");
|
||||||
|
if ($stmt->rowCount() > 0) {
|
||||||
|
$stmt = $pdo->query('SELECT filename FROM migrations');
|
||||||
|
return $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function add_migrated_file($pdo, $filename) {
|
||||||
|
$stmt = $pdo->prepare('INSERT INTO migrations (filename) VALUES (?)');
|
||||||
|
$stmt->execute([$filename]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
// Create migrations table if it doesn't exist
|
||||||
|
$pdo->exec('CREATE TABLE IF NOT EXISTS migrations (filename VARCHAR(255) NOT NULL PRIMARY KEY)');
|
||||||
|
|
||||||
|
$migrated_files = get_migrated_files($pdo);
|
||||||
|
$migrations_dir = __DIR__ . '/migrations';
|
||||||
|
$files = glob($migrations_dir . '/*.sql');
|
||||||
|
|
||||||
|
$all_migrations_run = true;
|
||||||
|
|
||||||
|
foreach ($files as $file) {
|
||||||
|
$filename = basename($file);
|
||||||
|
if (!in_array($filename, $migrated_files)) {
|
||||||
|
$all_migrations_run = false;
|
||||||
|
$sql = file_get_contents($file);
|
||||||
|
try {
|
||||||
|
$pdo->exec($sql);
|
||||||
|
add_migrated_file($pdo, $filename);
|
||||||
|
echo "Migrated: $filename\n";
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
die("Migration failed on $filename: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if($all_migrations_run) {
|
||||||
|
echo "All migrations are up to date.\n";
|
||||||
|
} else {
|
||||||
|
echo "\nMigrations complete.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
die("Migration failed: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
12
db/migrations/001_create_categories_tables.sql
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS categories (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
name VARCHAR(255) NOT NULL UNIQUE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS drill_categories (
|
||||||
|
drill_id INT NOT NULL,
|
||||||
|
category_id INT NOT NULL,
|
||||||
|
PRIMARY KEY (drill_id, category_id),
|
||||||
|
FOREIGN KEY (drill_id) REFERENCES drills(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (category_id) REFERENCES categories(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
1
db/migrations/002_add_image_path_to_drills.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE drills ADD COLUMN image_path VARCHAR(255) DEFAULT NULL;
|
||||||
9
db/migrations/003_create_social_profiles_table.sql
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS `social_profiles` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`user_id` int(11) NOT NULL,
|
||||||
|
`provider` varchar(255) NOT NULL,
|
||||||
|
`provider_id` varchar(255) NOT NULL,
|
||||||
|
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
10
db/migrations/004_create_training_sessions_table.sql
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `training_sessions` (
|
||||||
|
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
`coach_id` INT NOT NULL,
|
||||||
|
`name` VARCHAR(255) NOT NULL,
|
||||||
|
`description` TEXT,
|
||||||
|
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (`coach_id`) REFERENCES `users`(`id`) ON DELETE CASCADE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `training_session_drills` (
|
||||||
|
`session_id` INT NOT NULL,
|
||||||
|
`drill_id` INT NOT NULL,
|
||||||
|
`sequence` INT NOT NULL DEFAULT 0,
|
||||||
|
PRIMARY KEY (`session_id`, `drill_id`),
|
||||||
|
FOREIGN KEY (`session_id`) REFERENCES `training_sessions`(`id`) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (`drill_id`) REFERENCES `drills`(`id`) ON DELETE CASCADE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
19
db/migrations/006_create_teams_tables.sql
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
-- Create the teams table
|
||||||
|
CREATE TABLE IF NOT EXISTS teams (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
owner_user_id INT NOT NULL,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (owner_user_id) REFERENCES users(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Create the team_members table
|
||||||
|
CREATE TABLE IF NOT EXISTS team_members (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
team_id INT NOT NULL,
|
||||||
|
user_id INT NOT NULL,
|
||||||
|
joined_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (team_id) REFERENCES teams(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
UNIQUE KEY (team_id, user_id)
|
||||||
|
);
|
||||||
11
db/migrations/007_add_visibility_to_tables.sql
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
-- Add visibility and team_id to the drills table
|
||||||
|
ALTER TABLE drills
|
||||||
|
ADD COLUMN visibility ENUM('private', 'team', 'public') NOT NULL DEFAULT 'private',
|
||||||
|
ADD COLUMN team_id INT NULL,
|
||||||
|
ADD FOREIGN KEY (team_id) REFERENCES teams(id) ON DELETE SET NULL;
|
||||||
|
|
||||||
|
-- Add visibility and team_id to the training_sessions table
|
||||||
|
ALTER TABLE training_sessions
|
||||||
|
ADD COLUMN visibility ENUM('private', 'team', 'public') NOT NULL DEFAULT 'private',
|
||||||
|
ADD COLUMN team_id INT NULL,
|
||||||
|
ADD FOREIGN KEY (team_id) REFERENCES teams(id) ON DELETE SET NULL;
|
||||||
1
db/migrations/008_add_role_to_team_members.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE `team_members` ADD `role` ENUM('owner', 'admin', 'member') NOT NULL DEFAULT 'member' AFTER `user_id`;
|
||||||
11
db/migrations/009_create_user_favorites_table.sql
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS user_favorites (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
user_id INT NOT NULL,
|
||||||
|
drill_id INT DEFAULT NULL,
|
||||||
|
training_session_id INT DEFAULT NULL,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (drill_id) REFERENCES drills(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (training_session_id) REFERENCES training_sessions(id) ON DELETE CASCADE,
|
||||||
|
UNIQUE KEY user_favorite_item (user_id, drill_id, training_session_id)
|
||||||
|
);
|
||||||
87
db/seed.php
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'config.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||||
|
|
||||||
|
// Create drills table
|
||||||
|
$pdo->exec("
|
||||||
|
CREATE TABLE IF NOT EXISTS drills (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
title VARCHAR(255) NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
min_players INT,
|
||||||
|
max_players INT,
|
||||||
|
age_group VARCHAR(50),
|
||||||
|
skill_focus VARCHAR(100),
|
||||||
|
difficulty VARCHAR(50),
|
||||||
|
duration_minutes INT,
|
||||||
|
equipment_required TEXT,
|
||||||
|
youtube_url VARCHAR(255),
|
||||||
|
is_public BOOLEAN DEFAULT TRUE,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
coach_id INT NULL
|
||||||
|
)
|
||||||
|
");
|
||||||
|
|
||||||
|
// Check if table is empty before seeding
|
||||||
|
$stmt = $pdo->query("SELECT COUNT(*) FROM drills");
|
||||||
|
if ($stmt->fetchColumn() == 0) {
|
||||||
|
// Seed data
|
||||||
|
$drills = [
|
||||||
|
[
|
||||||
|
'title' => '4-Cone Dribbling Drill',
|
||||||
|
'description' => 'A simple drill to improve close control and dribbling skills.',
|
||||||
|
'min_players' => 1,
|
||||||
|
'max_players' => 8,
|
||||||
|
'age_group' => 'U8-U12',
|
||||||
|
'skill_focus' => 'Dribbling, Ball Control',
|
||||||
|
'difficulty' => 'Beginner',
|
||||||
|
'duration_minutes' => 15,
|
||||||
|
'equipment_required' => '4 cones, 1 ball per player',
|
||||||
|
'youtube_url' => 'https://www.youtube.com/embed/example1'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'title' => 'Passing Triangle',
|
||||||
|
'description' => 'A drill to practice short, quick passes and movement off the ball.',
|
||||||
|
'min_players' => 3,
|
||||||
|
'max_players' => 6,
|
||||||
|
'age_group' => 'U10-U16',
|
||||||
|
'skill_focus' => 'Passing, Movement',
|
||||||
|
'difficulty' => 'Intermediate',
|
||||||
|
'duration_minutes' => 20,
|
||||||
|
'equipment_required' => '3 cones, 1 ball',
|
||||||
|
'youtube_url' => 'https://www.youtube.com/embed/example2'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'title' => 'Defensive Positioning Game',
|
||||||
|
'description' => 'A small-sided game focused on teaching defensive shape and communication.',
|
||||||
|
'min_players' => 8,
|
||||||
|
'max_players' => 12,
|
||||||
|
'age_group' => 'U12-U18',
|
||||||
|
'skill_focus' => 'Defending, Team Shape',
|
||||||
|
'difficulty' => 'Advanced',
|
||||||
|
'duration_minutes' => 30,
|
||||||
|
'equipment_required' => 'Bibs, 2 small goals',
|
||||||
|
'youtube_url' => null
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare(
|
||||||
|
"INSERT INTO drills (title, description, min_players, max_players, age_group, skill_focus, difficulty, duration_minutes, equipment_required, youtube_url, coach_id)
|
||||||
|
VALUES (:title, :description, :min_players, :max_players, :age_group, :skill_focus, :difficulty, :duration_minutes, :equipment_required, :youtube_url, :coach_id)"
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($drills as $drill) {
|
||||||
|
$drill['coach_id'] = 1; // Hardcode coach_id for seed data
|
||||||
|
$stmt->execute($drill);
|
||||||
|
}
|
||||||
|
echo "Database seeded successfully!\n";
|
||||||
|
} else {
|
||||||
|
echo "Database already seeded.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
die("Database error: " . $e->getMessage());
|
||||||
|
}
|
||||||
48
db/user_seed.php
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/config.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
// Create users table
|
||||||
|
$pdo->exec("CREATE TABLE IF NOT EXISTS users (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
email VARCHAR(255) NOT NULL UNIQUE,
|
||||||
|
password VARCHAR(255) NOT NULL,
|
||||||
|
role ENUM('admin', 'coach') NOT NULL DEFAULT 'coach',
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
)");
|
||||||
|
|
||||||
|
// Add sample users
|
||||||
|
$users = [
|
||||||
|
[
|
||||||
|
'name' => 'Admin User',
|
||||||
|
'email' => 'admin@example.com',
|
||||||
|
'password' => password_hash('password', PASSWORD_DEFAULT),
|
||||||
|
'role' => 'admin'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Coach User',
|
||||||
|
'email' => 'coach@example.com',
|
||||||
|
'password' => password_hash('password', PASSWORD_DEFAULT),
|
||||||
|
'role' => 'coach'
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO users (name, email, password, role) VALUES (:name, :email, :password, :role)");
|
||||||
|
|
||||||
|
foreach ($users as $user) {
|
||||||
|
// Check if user already exists
|
||||||
|
$check = $pdo->prepare("SELECT id FROM users WHERE email = :email");
|
||||||
|
$check->execute(['email' => $user['email']]);
|
||||||
|
if ($check->rowCount() == 0) {
|
||||||
|
$stmt->execute($user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Users table created and seeded successfully." . PHP_EOL;
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
die("DB ERROR: " . $e->getMessage());
|
||||||
|
}
|
||||||
44
delete_drill.php
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/partials/header.php';
|
||||||
|
|
||||||
|
// Require login
|
||||||
|
if (!is_logged_in()) {
|
||||||
|
header('Location: login.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$current_coach_id = get_user_id();
|
||||||
|
$drill_id = $_GET['id'] ?? null;
|
||||||
|
|
||||||
|
if (!$drill_id) {
|
||||||
|
header('Location: my_drills.php?error=No drill specified');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
// First, verify the drill belongs to the current user
|
||||||
|
$stmt = $pdo->prepare("SELECT coach_id FROM drills WHERE id = ?");
|
||||||
|
$stmt->execute([$drill_id]);
|
||||||
|
$drill = $stmt->fetch();
|
||||||
|
|
||||||
|
if ($drill && $drill['coach_id'] == $current_coach_id) {
|
||||||
|
// Delete the drill
|
||||||
|
$delete_stmt = $pdo->prepare("DELETE FROM drills WHERE id = ?");
|
||||||
|
$delete_stmt->execute([$drill_id]);
|
||||||
|
|
||||||
|
header('Location: my_drills.php?success=Drill deleted successfully');
|
||||||
|
exit();
|
||||||
|
} else {
|
||||||
|
// Either drill doesn't exist or user doesn't have permission
|
||||||
|
header('Location: my_drills.php?error=Drill not found or you do not have permission to delete it');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
error_log("Database error: " . $e->getMessage());
|
||||||
|
header('Location: my_drills.php?error=A database error occurred.');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
?>
|
||||||
34
delete_training_session.php
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/auth.php'; // Corrected path
|
||||||
|
|
||||||
|
// Require login
|
||||||
|
if (!is_logged_in()) {
|
||||||
|
header('Location: login.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$session_id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
|
||||||
|
if (!$session_id) {
|
||||||
|
header('Location: training_sessions.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$coach_id = get_user_id();
|
||||||
|
require_once __DIR__ . '/db/config.php'; // Ensure db() is available
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
// Verify the session belongs to the current coach before deleting
|
||||||
|
$stmt = $pdo->prepare("SELECT id FROM training_sessions WHERE id = ? AND coach_id = ?");
|
||||||
|
$stmt->execute([$session_id, $coach_id]);
|
||||||
|
$session = $stmt->fetch();
|
||||||
|
|
||||||
|
if ($session) {
|
||||||
|
// The ON DELETE CASCADE on the training_session_drills table will handle deleting the links.
|
||||||
|
$stmt = $pdo->prepare("DELETE FROM training_sessions WHERE id = ?");
|
||||||
|
$stmt->execute([$session_id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Redirect back to the list with a status message
|
||||||
|
header('Location: training_sessions.php?status=deleted');
|
||||||
|
exit();
|
||||||
|
?>
|
||||||
114
drill.php
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/partials/header.php';
|
||||||
|
require_once 'db/config.php';
|
||||||
|
require_once 'auth.php';
|
||||||
|
|
||||||
|
$drill = null;
|
||||||
|
if (isset($_GET['id'])) {
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
$stmt = $pdo->prepare("SELECT * FROM drills WHERE id = ?");
|
||||||
|
$stmt->execute([$_GET['id']]);
|
||||||
|
$drill = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
// For production, you would log this error and show a generic error page.
|
||||||
|
die("Error fetching drill details: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$drill) {
|
||||||
|
http_response_code(404);
|
||||||
|
// A simple 404 page, you can create a more styled one.
|
||||||
|
die('Drill not found.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$pageTitle = htmlspecialchars($drill['title']);
|
||||||
|
$pageDescription = htmlspecialchars(substr($drill['description'], 0, 160));
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<main class="container mt-5">
|
||||||
|
<?php if (isset($_GET['created']) && $_GET['created'] == 'true') : ?>
|
||||||
|
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
||||||
|
<strong>Success!</strong> Your drill has been created successfully.
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
|
<h1 class="fw-bold"><?php echo htmlspecialchars($drill['title']); ?></h1>
|
||||||
|
<?php if (isset($_SESSION['user_id']) && $_SESSION['user_id'] == $drill['user_id']) : ?>
|
||||||
|
<div>
|
||||||
|
<a href="edit_drill.php?id=<?php echo $drill['id']; ?>" class="btn btn-outline-primary btn-sm">Edit</a>
|
||||||
|
<a href="delete_drill.php?id=<?php echo $drill['id']; ?>" class="btn btn-outline-danger btn-sm" onclick="return confirm('Are you sure you want to delete this drill?');">Delete</a>
|
||||||
|
<a href="export_drill_pdf.php?id=<?php echo $drill['id']; ?>" class="btn btn-outline-secondary btn-sm">Export to PDF</a>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<!-- Left Column: Details & Instructions -->
|
||||||
|
<div class="col-lg-6">
|
||||||
|
<div class="card shadow-sm mb-4">
|
||||||
|
<div class="card-header">
|
||||||
|
<h5 class="mb-0">Drill Details</h5>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<ul class="list-group list-group-flush">
|
||||||
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
|
<strong>Players:</strong>
|
||||||
|
<span><?php echo htmlspecialchars($drill['min_players']) . ' - ' . htmlspecialchars($drill['max_players']); ?></span>
|
||||||
|
</li>
|
||||||
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
|
<strong>Age Group:</strong>
|
||||||
|
<span class="badge bg-primary rounded-pill"><?php echo htmlspecialchars($drill['age_group']); ?></span>
|
||||||
|
</li>
|
||||||
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
|
<strong>Skill Focus:</strong>
|
||||||
|
<span><?php echo htmlspecialchars($drill['skill_focus']); ?></span>
|
||||||
|
</li>
|
||||||
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
|
<strong>Difficulty:</strong>
|
||||||
|
<span class="badge bg-danger rounded-pill"><?php echo htmlspecialchars($drill['difficulty']); ?></span>
|
||||||
|
</li>
|
||||||
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
|
<strong>Duration:</strong>
|
||||||
|
<span><?php echo htmlspecialchars($drill['duration_minutes']); ?> minutes</span>
|
||||||
|
</li>
|
||||||
|
<li class="list-group-item">
|
||||||
|
<strong>Equipment:</strong>
|
||||||
|
<p class="mb-0"><?php echo htmlspecialchars($drill['equipment_required']); ?></p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card shadow-sm mb-4">
|
||||||
|
<div class="card-body">
|
||||||
|
<h3 class="card-title">Instructions</h3>
|
||||||
|
<p class="lead"><?php echo nl2br(htmlspecialchars($drill['description'])); ?></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Right Column: Media (Image/Video) -->
|
||||||
|
<div class="col-lg-6">
|
||||||
|
<?php if (!empty($drill['image_path'])) : ?>
|
||||||
|
<div class="mb-4 shadow-sm rounded">
|
||||||
|
<img src="<?php echo htmlspecialchars($drill['image_path']); ?>" class="img-fluid rounded" alt="Drill Image">
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if (!empty($drill['youtube_url']) && get_youtube_id_from_url($drill['youtube_url'])) : ?>
|
||||||
|
<div class="video-container mb-4 shadow-sm rounded overflow-hidden">
|
||||||
|
<iframe src="https://www.youtube.com/embed/<?php echo get_youtube_id_from_url($drill['youtube_url']); ?>?rel=0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<?php require_once __DIR__ . '/partials/footer.php'; ?>
|
||||||
306
edit_drill.php
Normal file
@ -0,0 +1,306 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/partials/header.php';
|
||||||
|
|
||||||
|
// Require login
|
||||||
|
if (!is_logged_in()) {
|
||||||
|
header('Location: login.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$drill_id = $_GET['id'] ?? null;
|
||||||
|
$current_coach_id = get_user_id();
|
||||||
|
|
||||||
|
if (!$drill_id) {
|
||||||
|
header('Location: my_drills.php?error=No drill specified');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->prepare("SELECT * FROM drills WHERE id = ? AND coach_id = ?");
|
||||||
|
$stmt->execute([$drill_id, $current_coach_id]);
|
||||||
|
$drill = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (!$drill) {
|
||||||
|
header('Location: my_drills.php?error=Drill not found or you do not have permission to edit it');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch current categories for the drill
|
||||||
|
$stmt = $pdo->prepare("SELECT category_id FROM drill_categories WHERE drill_id = ?");
|
||||||
|
$stmt->execute([$drill_id]);
|
||||||
|
$current_category_ids = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
error_log("Database error: " . $e->getMessage());
|
||||||
|
header('Location: my_drills.php?error=A database error occurred.');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$pageTitle = 'Edit Drill';
|
||||||
|
$pageDescription = 'Update the details of your football/soccer drill.';
|
||||||
|
|
||||||
|
$errors = [];
|
||||||
|
|
||||||
|
// Define selectable options
|
||||||
|
$age_groups = ['U6-U8', 'U9-U12', 'U13-U16', 'U17+', 'Adults'];
|
||||||
|
$skill_focuses = ['Dribbling', 'Passing', 'Shooting', 'Defense', 'Goalkeeping', 'Crossing', 'Finishing', 'First Touch'];
|
||||||
|
$difficulties = ['Beginner', 'Intermediate', 'Advanced'];
|
||||||
|
|
||||||
|
// Fetch all categories
|
||||||
|
$stmt = $pdo->query("SELECT * FROM categories ORDER BY name");
|
||||||
|
$categories = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
// Sanitize and validate inputs
|
||||||
|
$title = trim($_POST['title'] ?? '');
|
||||||
|
$description = trim($_POST['description'] ?? '');
|
||||||
|
$min_players = filter_input(INPUT_POST, 'min_players', FILTER_VALIDATE_INT);
|
||||||
|
$max_players = filter_input(INPUT_POST, 'max_players', FILTER_VALIDATE_INT);
|
||||||
|
$age_group = trim($_POST['age_group'] ?? '');
|
||||||
|
$skill_focus = trim($_POST['skill_focus'] ?? '');
|
||||||
|
$difficulty = trim($_POST['difficulty'] ?? '');
|
||||||
|
$duration_minutes = filter_input(INPUT_POST, 'duration_minutes', FILTER_VALIDATE_INT);
|
||||||
|
$equipment_required = trim($_POST['equipment_required'] ?? '');
|
||||||
|
$youtube_url = filter_input(INPUT_POST, 'youtube_url', FILTER_VALIDATE_URL);
|
||||||
|
$is_public = isset($_POST['is_public']) ? 1 : 0;
|
||||||
|
$selected_categories = $_POST['categories'] ?? [];
|
||||||
|
$image_path = $drill['image_path']; // Keep old image by default
|
||||||
|
|
||||||
|
// Basic validation
|
||||||
|
if (empty($title)) $errors[] = 'Title is required.';
|
||||||
|
if (empty($description)) $errors[] = 'Description is required.';
|
||||||
|
if ($min_players === false || $min_players < 1) $errors[] = 'Minimum players must be a positive number.';
|
||||||
|
if ($max_players === false || $max_players < $min_players) $errors[] = 'Maximum players must be greater than or equal to minimum players.';
|
||||||
|
if (!in_array($age_group, $age_groups)) $errors[] = 'Invalid age group selected.';
|
||||||
|
if (!in_array($skill_focus, $skill_focuses)) $errors[] = 'Invalid skill focus selected.';
|
||||||
|
if (!in_array($difficulty, $difficulties)) $errors[] = 'Invalid difficulty selected.';
|
||||||
|
if ($duration_minutes === false || $duration_minutes < 1) $errors[] = 'Duration must be a positive number.';
|
||||||
|
if ($youtube_url === false && !empty($_POST['youtube_url'])) $errors[] = 'YouTube URL is not a valid URL.';
|
||||||
|
if (empty($selected_categories)) $errors[] = 'At least one category must be selected.';
|
||||||
|
|
||||||
|
// New image upload handling
|
||||||
|
if (isset($_FILES['drill_image']) && $_FILES['drill_image']['error'] === UPLOAD_ERR_OK) {
|
||||||
|
$upload_dir = __DIR__ . '/assets/images/drills/';
|
||||||
|
if (!is_dir($upload_dir)) {
|
||||||
|
mkdir($upload_dir, 0775, true);
|
||||||
|
}
|
||||||
|
$file = $_FILES['drill_image'];
|
||||||
|
$file_ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
|
||||||
|
$allowed_exts = ['jpg', 'jpeg', 'png', 'gif'];
|
||||||
|
|
||||||
|
if (in_array($file_ext, $allowed_exts)) {
|
||||||
|
if ($file['size'] <= 5 * 1024 * 1024) { // 5MB limit
|
||||||
|
$new_filename = uniqid('', true) . '.' . $file_ext;
|
||||||
|
$destination = $upload_dir . $new_filename;
|
||||||
|
|
||||||
|
if (move_uploaded_file($file['tmp_name'], $destination)) {
|
||||||
|
// Delete old image if it exists
|
||||||
|
if ($drill['image_path'] && file_exists(__DIR__ . '/' . $drill['image_path'])) {
|
||||||
|
unlink(__DIR__ . '/' . $drill['image_path']);
|
||||||
|
}
|
||||||
|
$image_path = '/assets/images/drills/' . $new_filename;
|
||||||
|
} else {
|
||||||
|
$errors[] = 'Failed to move uploaded file.';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$errors[] = 'File is too large. Maximum size is 5MB.';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$errors[] = 'Invalid file type. Only JPG, JPEG, PNG, and GIF are allowed.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($errors)) {
|
||||||
|
try {
|
||||||
|
$pdo->beginTransaction();
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare(
|
||||||
|
'UPDATE drills SET
|
||||||
|
title = ?,
|
||||||
|
description = ?,
|
||||||
|
min_players = ?,
|
||||||
|
max_players = ?,
|
||||||
|
age_group = ?,
|
||||||
|
skill_focus = ?,
|
||||||
|
difficulty = ?,
|
||||||
|
duration_minutes = ?,
|
||||||
|
equipment_required = ?,
|
||||||
|
youtube_url = ?,
|
||||||
|
is_public = ?,
|
||||||
|
image_path = ?
|
||||||
|
WHERE id = ? AND coach_id = ?'
|
||||||
|
);
|
||||||
|
|
||||||
|
$stmt->execute([
|
||||||
|
$title,
|
||||||
|
$description,
|
||||||
|
$min_players,
|
||||||
|
$max_players,
|
||||||
|
$age_group,
|
||||||
|
$skill_focus,
|
||||||
|
$difficulty,
|
||||||
|
$duration_minutes,
|
||||||
|
$equipment_required,
|
||||||
|
$youtube_url ?: null,
|
||||||
|
$is_public,
|
||||||
|
$image_path,
|
||||||
|
$drill_id,
|
||||||
|
$current_coach_id
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Update categories
|
||||||
|
// 1. Delete existing categories for this drill
|
||||||
|
$stmt = $pdo->prepare("DELETE FROM drill_categories WHERE drill_id = ?");
|
||||||
|
$stmt->execute([$drill_id]);
|
||||||
|
|
||||||
|
// 2. Insert new categories
|
||||||
|
$stmt = $pdo->prepare('INSERT INTO drill_categories (drill_id, category_id) VALUES (?, ?)');
|
||||||
|
foreach ($selected_categories as $category_id) {
|
||||||
|
$stmt->execute([$drill_id, $category_id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$pdo->commit();
|
||||||
|
|
||||||
|
header("Location: my_drills.php?success=Drill updated successfully");
|
||||||
|
exit;
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$pdo->rollBack();
|
||||||
|
// In a real app, log this error instead of displaying it
|
||||||
|
$errors[] = "Database error: " . $e->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<main class="container my-5">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-lg-9 col-xl-8">
|
||||||
|
<div class="card shadow-lg border-0 rounded-4">
|
||||||
|
<div class="card-body p-4 p-sm-5">
|
||||||
|
<div class="text-center mb-4">
|
||||||
|
<h1 class="h2 fw-bold">Edit Drill</h1>
|
||||||
|
<p class="text-muted">Update the details of your drill.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if (!empty($errors)) : ?>
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<p class="mb-0"><strong>Please fix the following errors:</strong></p>
|
||||||
|
<ul class="mb-0">
|
||||||
|
<?php foreach ($errors as $error) : ?>
|
||||||
|
<li><?php echo htmlspecialchars($error); ?></li>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<form action="edit_drill.php?id=<?php echo $drill_id; ?>" method="POST" enctype="multipart/form-data" novalidate>
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<input type="text" class="form-control" id="title" name="title" placeholder="Drill Title" required value="<?php echo htmlspecialchars($drill['title']); ?>">
|
||||||
|
<label for="title">Drill Title</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<textarea class="form-control" id="description" name="description" placeholder="Description & Instructions" style="height: 150px" required><?php echo htmlspecialchars($drill['description']); ?></textarea>
|
||||||
|
<label for="description">Description & Instructions</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="drill_image" class="form-label">Drill Image</label>
|
||||||
|
<?php if ($drill['image_path']) : ?>
|
||||||
|
<div class="mb-2">
|
||||||
|
<img src="<?php echo htmlspecialchars($drill['image_path']); ?>" alt="Current Drill Image" style="max-width: 200px; height: auto; border-radius: 0.25rem;">
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<input class="form-control" type="file" id="drill_image" name="drill_image">
|
||||||
|
<div class="form-text">Upload a new image to replace the current one (JPG, PNG, GIF - max 5MB).</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row g-3 mb-3">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="form-floating">
|
||||||
|
<input type="number" class="form-control" id="min_players" name="min_players" placeholder="Min. Players" min="1" required value="<?php echo htmlspecialchars($drill['min_players']); ?>">
|
||||||
|
<label for="min_players">Min. Players</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="form-floating">
|
||||||
|
<input type="number" class="form-control" id="max_players" name="max_players" placeholder="Max. Players" min="1" required value="<?php echo htmlspecialchars($drill['max_players']); ?>">
|
||||||
|
<label for="max_players">Max. Players</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row g-3 mb-3">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="form-floating">
|
||||||
|
<select class="form-select" id="age_group" name="age_group" required>
|
||||||
|
<?php foreach ($age_groups as $group) : ?>
|
||||||
|
<option value="<?php echo $group; ?>" <?php echo ($drill['age_group'] === $group) ? 'selected' : ''; ?>><?php echo $group; ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
<label for="age_group">Age Group</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="form-floating">
|
||||||
|
<select class="form-select" id="difficulty" name="difficulty" required>
|
||||||
|
<?php foreach ($difficulties as $level) : ?>
|
||||||
|
<option value="<?php echo $level; ?>" <?php echo ($drill['difficulty'] === $level) ? 'selected' : ''; ?>><?php echo $level; ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
<label for="difficulty">Difficulty</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<select class="form-select" id="skill_focus" name="skill_focus" required>
|
||||||
|
<?php foreach ($skill_focuses as $focus) : ?>
|
||||||
|
<option value="<?php echo $focus; ?>" <?php echo (($drill['skill_focus'] ?? '') === $focus) ? 'selected' : ''; ?>><?php echo $focus; ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
<label for="skill_focus">Primary Skill Focus</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="categories" class="form-label">Categories</label>
|
||||||
|
<select class="form-select" id="categories" name="categories[]" multiple required size="5">
|
||||||
|
<?php foreach ($categories as $category) : ?>
|
||||||
|
<option value="<?php echo $category['id']; ?>" <?php echo in_array($category['id'], $current_category_ids) ? 'selected' : ''; ?>><?php echo htmlspecialchars($category['name']); ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
<div class="form-text">Select one or more categories (hold Ctrl or Cmd to select multiple).</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<input type="number" class="form-control" id="duration_minutes" name="duration_minutes" placeholder="Duration (minutes)" min="1" required value="<?php echo htmlspecialchars($drill['duration_minutes']); ?>">
|
||||||
|
<label for="duration_minutes">Duration (minutes)</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<input type="text" class="form-control" id="equipment_required" name="equipment_required" placeholder="e.g., Cones, balls, bibs" value="<?php echo htmlspecialchars($drill['equipment_required']); ?>">
|
||||||
|
<label for="equipment_required">Equipment Required</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-floating mb-4">
|
||||||
|
<input type="url" class="form-control" id="youtube_url" name="youtube_url" placeholder="https://www.youtube.com/watch?v=..." value="<?php echo htmlspecialchars($drill['youtube_url']); ?>">
|
||||||
|
<label for="youtube_url">YouTube Video URL (Optional)</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-check form-switch mb-4">
|
||||||
|
<input class="form-check-input" type="checkbox" role="switch" id="is_public" name="is_public" value="1" <?php echo $drill['is_public'] ? 'checked' : ''; ?>>
|
||||||
|
<label class="form-check-label" for="is_public">Make this drill public</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-grid">
|
||||||
|
<button type="submit" class="btn btn-primary btn-lg rounded-pill">Save Changes</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<?php require_once __DIR__ . '/partials/footer.php'; ?>
|
||||||
131
edit_training_session.php
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/partials/header.php';
|
||||||
|
|
||||||
|
// Require login
|
||||||
|
if (!is_logged_in()) {
|
||||||
|
header('Location: login.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$session_id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
|
||||||
|
if (!$session_id) {
|
||||||
|
header('Location: training_sessions.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$coach_id = get_user_id();
|
||||||
|
$pdo = db();
|
||||||
|
$errors = [];
|
||||||
|
|
||||||
|
// Fetch the training session
|
||||||
|
$stmt = $pdo->prepare("SELECT * FROM training_sessions WHERE id = ? AND coach_id = ?");
|
||||||
|
$stmt->execute([$session_id, $coach_id]);
|
||||||
|
$session = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (!$session) {
|
||||||
|
header('Location: training_sessions.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch the coach's drills
|
||||||
|
$stmt = $pdo->prepare("SELECT id, title FROM drills WHERE coach_id = ? ORDER BY title");
|
||||||
|
$stmt->execute([$coach_id]);
|
||||||
|
$all_drills = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// Fetch the drills currently in the session
|
||||||
|
$stmt = $pdo->prepare("SELECT drill_id FROM training_session_drills WHERE session_id = ?");
|
||||||
|
$stmt->execute([$session_id]);
|
||||||
|
$session_drill_ids = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
$name = trim($_POST['name'] ?? '');
|
||||||
|
$description = trim($_POST['description'] ?? '');
|
||||||
|
$selected_drills = $_POST['drills'] ?? [];
|
||||||
|
|
||||||
|
if (empty($name)) $errors[] = 'Session name is required.';
|
||||||
|
if (empty($selected_drills)) $errors[] = 'You must select at least one drill.';
|
||||||
|
|
||||||
|
if (empty($errors)) {
|
||||||
|
try {
|
||||||
|
$pdo->beginTransaction();
|
||||||
|
|
||||||
|
// Update the session details
|
||||||
|
$stmt = $pdo->prepare("UPDATE training_sessions SET name = ?, description = ? WHERE id = ?");
|
||||||
|
$stmt->execute([$name, $description, $session_id]);
|
||||||
|
|
||||||
|
// Delete existing drill associations
|
||||||
|
$stmt = $pdo->prepare("DELETE FROM training_session_drills WHERE session_id = ?");
|
||||||
|
$stmt->execute([$session_id]);
|
||||||
|
|
||||||
|
// Insert new drill associations
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO training_session_drills (session_id, drill_id, sequence) VALUES (?, ?, ?)");
|
||||||
|
$sequence = 0;
|
||||||
|
foreach ($selected_drills as $drill_id) {
|
||||||
|
$stmt->execute([$session_id, $drill_id, ++$sequence]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$pdo->commit();
|
||||||
|
header('Location: training_session.php?id=' . $session_id . '&status=updated');
|
||||||
|
exit();
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$pdo->rollBack();
|
||||||
|
$errors[] = "Database error: " . $e->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$pageTitle = 'Edit Training Session';
|
||||||
|
?>
|
||||||
|
|
||||||
|
<main class="container my-5">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-lg-8">
|
||||||
|
<div class="card shadow-sm border-0 rounded-4">
|
||||||
|
<div class="card-body p-4">
|
||||||
|
<h1 class="h3 mb-4 text-center">Edit Training Session</h1>
|
||||||
|
|
||||||
|
<?php if (!empty($errors)): ?>
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<ul class="mb-0">
|
||||||
|
<?php foreach ($errors as $error): ?>
|
||||||
|
<li><?php echo htmlspecialchars($error); ?></li>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<form action="edit_training_session.php?id=<?php echo $session_id; ?>" method="POST">
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<input type="text" class="form-control" id="name" name="name" placeholder="Session Name" required value="<?php echo htmlspecialchars($session['name']); ?>">
|
||||||
|
<label for="name">Session Name</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<textarea class="form-control" id="description" name="description" placeholder="Session Description" style="height: 120px;"><?php echo htmlspecialchars($session['description']); ?></textarea>
|
||||||
|
<label for="description">Description (Optional)</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-4">
|
||||||
|
<label class="form-label">Select Drills</label>
|
||||||
|
<div class="list-group" style="max-height: 300px; overflow-y: auto;">
|
||||||
|
<?php foreach ($all_drills as $drill): ?>
|
||||||
|
<label class="list-group-item">
|
||||||
|
<input class="form-check-input me-2" type="checkbox" name="drills[]" value="<?php echo $drill['id']; ?>" <?php echo in_array($drill['id'], $session_drill_ids) ? 'checked' : ''; ?>>
|
||||||
|
<?php echo htmlspecialchars($drill['title']); ?>
|
||||||
|
</label>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-grid">
|
||||||
|
<button type="submit" class="btn btn-primary btn-lg">Save Changes</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<?php require_once __DIR__ . '/partials/footer.php'; ?>
|
||||||
134
export_drill_pdf.php
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'vendor/autoload.php';
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
use Dompdf\Dompdf;
|
||||||
|
use Dompdf\Options;
|
||||||
|
|
||||||
|
if (!isset($_GET['id']) || !is_numeric($_GET['id'])) {
|
||||||
|
die('Invalid drill ID');
|
||||||
|
}
|
||||||
|
|
||||||
|
$drill_id = $_GET['id'];
|
||||||
|
|
||||||
|
// Fetch drill data from the database
|
||||||
|
$stmt = db()->prepare("SELECT d.title, d.description, d.image_path, d.created_at, c.name as category_name FROM drills d LEFT JOIN categories c ON d.category_id = c.id WHERE d.id = ?");
|
||||||
|
$stmt->execute([$drill_id]);
|
||||||
|
$drill = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (!$drill) {
|
||||||
|
die('Drill not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTML content for the PDF
|
||||||
|
$html = '
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Drill Report</title>
|
||||||
|
<style>
|
||||||
|
@page {
|
||||||
|
margin: 30px;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-family: 'Helvetica', sans-serif;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.header img {
|
||||||
|
max-width: 150px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
padding: 20px;
|
||||||
|
border: 1px solid #eee;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
color: #007bff;
|
||||||
|
margin-top: 0;
|
||||||
|
border-bottom: 2px solid #007bff;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
line-height: 1.6;
|
||||||
|
margin: 0 0 15px;
|
||||||
|
}
|
||||||
|
strong {
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
.footer {
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 30px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: #777;
|
||||||
|
}
|
||||||
|
.drill-image {
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
.drill-image img {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="header">
|
||||||
|
<?php
|
||||||
|
$logo_path = __DIR__ . '/assets/images/logo.svg';
|
||||||
|
if (file_exists($logo_path)) {
|
||||||
|
$logo_data = base64_encode(file_get_contents($logo_path));
|
||||||
|
$logo_mime = mime_content_type($logo_path);
|
||||||
|
$logo_src = 'data:' . $logo_mime . ';base64,' . $logo_data;
|
||||||
|
} else {
|
||||||
|
$logo_src = '';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<?php if ($logo_src): ?>
|
||||||
|
<img src="<?php echo $logo_src; ?>" alt="Logo">
|
||||||
|
<?php endif; ?>
|
||||||
|
<h2>Drill Report</h2>
|
||||||
|
</div>
|
||||||
|
<div class="container">
|
||||||
|
<h1><?php echo htmlspecialchars($drill['title']); ?></h1>
|
||||||
|
<p><strong>Category:</strong> <?php echo htmlspecialchars($drill['category_name']); ?></p>
|
||||||
|
<p><strong>Description:</strong></p>
|
||||||
|
<div><?php echo nl2br(htmlspecialchars($drill['description'])); ?></div>
|
||||||
|
<?php if (!empty($drill['image_path'])):
|
||||||
|
$image_path = __DIR__ . '/' . $drill['image_path'];
|
||||||
|
if (file_exists($image_path)) {
|
||||||
|
$image_data = base64_encode(file_get_contents($image_path));
|
||||||
|
$image_mime = mime_content_type($image_path);
|
||||||
|
$image_src = 'data:' . $image_mime . ';base64,' . $image_data;
|
||||||
|
} else {
|
||||||
|
$image_src = '';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<?php if ($image_src): ?>
|
||||||
|
<div class="drill-image">
|
||||||
|
<img src="<?php echo $image_src; ?>" alt="Drill Image">
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<p><strong>Created at:</strong> <?php echo htmlspecialchars($drill['created_at']); ?></p>
|
||||||
|
</div>
|
||||||
|
<div class="footer">
|
||||||
|
<p>Generated by Drillex on <?php echo date('Y-m-d H:i:s'); ?></p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
';
|
||||||
|
|
||||||
|
$options = new Options();
|
||||||
|
$options->set('isHtml5ParserEnabled', true);
|
||||||
|
$dompdf = new Dompdf($options);
|
||||||
|
$dompdf->loadHtml($html);
|
||||||
|
$dompdf->setPaper('A4', 'portrait');
|
||||||
|
$dompdf->render();
|
||||||
|
$dompdf->stream("drill_" . $drill['id'] . ".pdf", ["Attachment" => false]);
|
||||||
161
export_training_session_pdf.php
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'vendor/autoload.php';
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
use Dompdf\Dompdf;
|
||||||
|
use Dompdf\Options;
|
||||||
|
|
||||||
|
if (!isset($_GET['id']) || !is_numeric($_GET['id'])) {
|
||||||
|
die('Invalid training session ID');
|
||||||
|
}
|
||||||
|
|
||||||
|
$session_id = $_GET['id'];
|
||||||
|
|
||||||
|
// Fetch session data from the database
|
||||||
|
$stmt = db()->prepare("SELECT * FROM training_sessions WHERE id = ?");
|
||||||
|
$stmt->execute([$session_id]);
|
||||||
|
$session = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (!$session) {
|
||||||
|
die('Training session not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch associated drills
|
||||||
|
$stmt = db()->prepare("SELECT d.title, d.description, d.image_path, c.name as category_name FROM drills d JOIN training_session_drills tsd ON d.id = tsd.drill_id LEFT JOIN categories c ON d.category_id = c.id WHERE tsd.training_session_id = ?");
|
||||||
|
$stmt->execute([$session_id]);
|
||||||
|
$drills = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// HTML content for the PDF
|
||||||
|
$html = '
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Training Session Report</title>
|
||||||
|
<style>
|
||||||
|
@page {
|
||||||
|
margin: 30px;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-family: 'Helvetica', sans-serif;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.header img {
|
||||||
|
max-width: 150px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
padding: 20px;
|
||||||
|
border: 1px solid #eee;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
h1, h2 {
|
||||||
|
color: #007bff;
|
||||||
|
border-bottom: 2px solid #007bff;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
margin-top: 30px;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
line-height: 1.6;
|
||||||
|
margin: 0 0 15px;
|
||||||
|
}
|
||||||
|
strong {
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
.drill {
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
.drill:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
.footer {
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 30px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: #777;
|
||||||
|
}
|
||||||
|
.drill-image {
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
.drill-image img {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="header">
|
||||||
|
<?php
|
||||||
|
$logo_path = __DIR__ . '/assets/images/logo.svg';
|
||||||
|
if (file_exists($logo_path)) {
|
||||||
|
$logo_data = base64_encode(file_get_contents($logo_path));
|
||||||
|
$logo_mime = mime_content_type($logo_path);
|
||||||
|
$logo_src = 'data:' . $logo_mime . ';base64,' . $logo_data;
|
||||||
|
} else {
|
||||||
|
$logo_src = '';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<?php if ($logo_src): ?>
|
||||||
|
<img src="<?php echo $logo_src; ?>" alt="Logo">
|
||||||
|
<?php endif; ?>
|
||||||
|
<h2>Training Session Report</h2>
|
||||||
|
</div>
|
||||||
|
<div class="container">
|
||||||
|
<h1><?php echo htmlspecialchars($session['title']); ?></h1>
|
||||||
|
<p><strong>Date:</strong> <?php echo htmlspecialchars($session['date']); ?></p>
|
||||||
|
<p><strong>Notes:</strong></p>
|
||||||
|
<div><?php echo nl2br(htmlspecialchars($session['notes'])); ?></div>
|
||||||
|
|
||||||
|
<h2>Drills</h2>
|
||||||
|
<?php foreach ($drills as $drill): ?>
|
||||||
|
<div class="drill">
|
||||||
|
<h3><?php echo htmlspecialchars($drill['title']); ?></h3>
|
||||||
|
<p><strong>Category:</strong> <?php echo htmlspecialchars($drill['category_name']); ?></p>
|
||||||
|
<p><strong>Description:</strong></p>
|
||||||
|
<div><?php echo nl2br(htmlspecialchars($drill['description'])); ?></div>
|
||||||
|
<?php if (!empty($drill['image_path'])):
|
||||||
|
$image_path = __DIR__ . '/' . $drill['image_path'];
|
||||||
|
if (file_exists($image_path)) {
|
||||||
|
$image_data = base64_encode(file_get_contents($image_path));
|
||||||
|
$image_mime = mime_content_type($image_path);
|
||||||
|
$image_src = 'data:' . $image_mime . ';base64,' . $image_data;
|
||||||
|
} else {
|
||||||
|
$image_src = '';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<?php if ($image_src): ?>
|
||||||
|
<div class="drill-image">
|
||||||
|
<img src="<?php echo $image_src; ?>" alt="Drill Image">
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
<div class="footer">
|
||||||
|
<p>Generated by Drillex on <?php echo date('Y-m-d H:i:s'); ?></p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
';
|
||||||
|
|
||||||
|
$options = new Options();
|
||||||
|
$options->set('isHtml5ParserEnabled', true);
|
||||||
|
$dompdf = new Dompdf($options);
|
||||||
|
$dompdf->loadHtml($html);
|
||||||
|
$dompdf->setPaper('A4', 'portrait');
|
||||||
|
$dompdf->render();
|
||||||
|
$dompdf->stream("training_session_" . $session['id'] . ".pdf", ["Attachment" => false]);
|
||||||
47
hybridauth_callback.php
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'vendor/autoload.php';
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
session_start();
|
||||||
|
|
||||||
|
$config = require_once 'hybridauth_config.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$hybridauth = new Hybridauth\Hybridauth($config);
|
||||||
|
$adapter = $hybridauth->authenticate('Google');
|
||||||
|
$userProfile = $adapter->getUserProfile();
|
||||||
|
|
||||||
|
// Log user profile data for debugging
|
||||||
|
$profile_data = date('Y-m-d H:i:s') . ' - User Profile: ' . print_r($userProfile, true) . "\n";
|
||||||
|
file_put_contents('logs/hybridauth_debug.log', $profile_data, FILE_APPEND);
|
||||||
|
|
||||||
|
|
||||||
|
// Check if user exists in our database
|
||||||
|
$stmt = db()->prepare("SELECT * FROM users WHERE email = ?");
|
||||||
|
$stmt->execute([$userProfile->email]);
|
||||||
|
$user = $stmt->fetch();
|
||||||
|
|
||||||
|
if ($user) {
|
||||||
|
// User exists, log them in
|
||||||
|
$_SESSION['user_id'] = $user['id'];
|
||||||
|
$_SESSION['user_name'] = $user['name'];
|
||||||
|
header('Location: my_drills.php');
|
||||||
|
exit();
|
||||||
|
} else {
|
||||||
|
// User does not exist, create a new account
|
||||||
|
$password = password_hash(bin2hex(random_bytes(8)), PASSWORD_DEFAULT);
|
||||||
|
$stmt = db()->prepare("INSERT INTO users (name, email, password) VALUES (?, ?, ?)");
|
||||||
|
$stmt->execute([$userProfile->displayName, $userProfile->email, $password]);
|
||||||
|
$userId = db()->lastInsertId();
|
||||||
|
|
||||||
|
$_SESSION['user_id'] = $userId;
|
||||||
|
$_SESSION['user_name'] = $userProfile->displayName;
|
||||||
|
header('Location: my_drills.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$error_message = date('Y-m-d H:i:s') . ' - Hybridauth Error: ' . $e->getMessage() . "\n";
|
||||||
|
file_put_contents('logs/hybridauth_errors.log', $error_message, FILE_APPEND);
|
||||||
|
header('Location: login.php?error=social_login_failed');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
20
hybridauth_login.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
|
||||||
|
require_once __DIR__ . '/vendor/autoload.php';
|
||||||
|
|
||||||
|
$config = require_once __DIR__ . '/hybridauth_config.php';
|
||||||
|
|
||||||
|
if (isset($_GET['provider'])) {
|
||||||
|
$provider = $_GET['provider'];
|
||||||
|
|
||||||
|
try {
|
||||||
|
$hybridauth = new Hybridauth\Hybridauth($config);
|
||||||
|
$adapter = $hybridauth->authenticate($provider);
|
||||||
|
header('Location: hybridauth_callback.php?provider=' . $provider);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo 'Oops, we ran into an issue: ' . $e->getMessage();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
echo 'Provider not specified.';
|
||||||
|
}
|
||||||
393
index.php
@ -1,150 +1,255 @@
|
|||||||
<?php
|
<?php
|
||||||
declare(strict_types=1);
|
require_once __DIR__ . '/partials/header.php';
|
||||||
@ini_set('display_errors', '1');
|
require_once 'db/config.php';
|
||||||
@error_reporting(E_ALL);
|
require_once 'auth.php';
|
||||||
@date_default_timezone_set('UTC');
|
|
||||||
|
|
||||||
$phpVersion = PHP_VERSION;
|
// Pagination settings
|
||||||
$now = date('Y-m-d H:i:s');
|
$drillsPerPage = 9;
|
||||||
|
$currentPage = isset($_GET['page']) ? (int)$_GET['page'] : 1;
|
||||||
|
if ($currentPage < 1) {
|
||||||
|
$currentPage = 1;
|
||||||
|
}
|
||||||
|
$offset = ($currentPage - 1) * $drillsPerPage;
|
||||||
|
|
||||||
|
// Fetch drills from the database
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
// Base query for counting total matching drills
|
||||||
|
$userId = $_SESSION['user_id'] ?? 0;
|
||||||
|
|
||||||
|
// Base query for counting total matching drills
|
||||||
|
$countSql = "SELECT COUNT(d.id) FROM drills d WHERE d.is_public = TRUE";
|
||||||
|
|
||||||
|
// Base query for fetching drills with favorite status
|
||||||
|
$sql = "SELECT d.*, CASE WHEN uf.user_id IS NOT NULL THEN 1 ELSE 0 END AS is_favorite
|
||||||
|
FROM drills d
|
||||||
|
LEFT JOIN user_favorites uf ON d.id = uf.drill_id AND uf.user_id = :userId
|
||||||
|
WHERE d.is_public = TRUE";
|
||||||
|
|
||||||
|
|
||||||
|
$params = [];
|
||||||
|
|
||||||
|
// Search functionality
|
||||||
|
$searchTerm = $_GET['search'] ?? '';
|
||||||
|
if (!empty($searchTerm)) {
|
||||||
|
$filterCondition = " AND (title LIKE ? OR description LIKE ?)";
|
||||||
|
$countSql .= $filterCondition;
|
||||||
|
$sql .= $filterCondition;
|
||||||
|
$params[] = "%" . $searchTerm . "%";
|
||||||
|
$params[] = "%" . $searchTerm . "%";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter functionality
|
||||||
|
$ageGroup = $_GET['age_group'] ?? '';
|
||||||
|
if (!empty($ageGroup)) {
|
||||||
|
$filterCondition = " AND age_group = ?";
|
||||||
|
$countSql .= $filterCondition;
|
||||||
|
$sql .= $filterCondition;
|
||||||
|
$params[] = $ageGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
$difficulty = $_GET['difficulty'] ?? '';
|
||||||
|
if (!empty($difficulty)) {
|
||||||
|
$filterCondition = " AND difficulty = ?";
|
||||||
|
$countSql .= $filterCondition;
|
||||||
|
$sql .= $filterCondition;
|
||||||
|
$params[] = $difficulty;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get total number of drills that match filters
|
||||||
|
$countStmt = $pdo->prepare($countSql);
|
||||||
|
$countStmt->execute($params);
|
||||||
|
$totalDrills = $countStmt->fetchColumn();
|
||||||
|
$totalPages = ceil($totalDrills / $drillsPerPage);
|
||||||
|
|
||||||
|
// Add ordering and pagination to the main query
|
||||||
|
$sql .= " ORDER BY created_at DESC LIMIT :limit OFFSET :offset";
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare($sql);
|
||||||
|
|
||||||
|
$stmt->bindValue(':userId', $userId, PDO::PARAM_INT);
|
||||||
|
|
||||||
|
// Bind filter parameters
|
||||||
|
foreach ($params as $key => $value) {
|
||||||
|
$stmt->bindValue($key + 1, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind pagination parameters
|
||||||
|
$stmt->bindValue(':limit', $drillsPerPage, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
|
||||||
|
|
||||||
|
$stmt->execute();
|
||||||
|
$drills = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// Fetch distinct filter values for dropdowns
|
||||||
|
$ageGroups = $pdo->query("SELECT DISTINCT age_group FROM drills WHERE is_public = TRUE ORDER BY age_group")->fetchAll(PDO::FETCH_COLUMN);
|
||||||
|
$difficulties = $pdo->query("SELECT DISTINCT difficulty FROM drills WHERE is_public = TRUE ORDER BY difficulty")->fetchAll(PDO::FETCH_COLUMN);
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
// For production, you would log this error and show a generic error page.
|
||||||
|
die("Error fetching drills: " . $e->getMessage());
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
<header class="py-5 text-center container-fluid">
|
||||||
<head>
|
<div class="row py-lg-5">
|
||||||
<meta charset="utf-8" />
|
<div class="col-lg-6 col-md-8 mx-auto">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<h1 class="display-4 fw-bold">Find Your Perfect Drill</h1>
|
||||||
<title>New Style</title>
|
<p class="lead text-muted"><?php echo htmlspecialchars($pageDescription); ?></p>
|
||||||
<?php
|
<p>
|
||||||
// Read project preview data from environment
|
<a href="create_drill.php" class="btn btn-primary my-2">Create a Drill</a>
|
||||||
$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? '';
|
<a href="#" class="btn btn-secondary my-2">Browse All</a>
|
||||||
$projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
|
</p>
|
||||||
?>
|
|
||||||
<?php if ($projectDescription): ?>
|
|
||||||
<!-- Meta description -->
|
|
||||||
<meta name="description" content='<?= htmlspecialchars($projectDescription) ?>' />
|
|
||||||
<!-- Open Graph meta tags -->
|
|
||||||
<meta property="og:description" content="<?= htmlspecialchars($projectDescription) ?>" />
|
|
||||||
<!-- Twitter meta tags -->
|
|
||||||
<meta property="twitter:description" content="<?= htmlspecialchars($projectDescription) ?>" />
|
|
||||||
<?php endif; ?>
|
|
||||||
<?php if ($projectImageUrl): ?>
|
|
||||||
<!-- Open Graph image -->
|
|
||||||
<meta property="og:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
|
|
||||||
<!-- Twitter image -->
|
|
||||||
<meta property="twitter:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
|
|
||||||
<?php endif; ?>
|
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
|
|
||||||
<style>
|
|
||||||
:root {
|
|
||||||
--bg-color-start: #6a11cb;
|
|
||||||
--bg-color-end: #2575fc;
|
|
||||||
--text-color: #ffffff;
|
|
||||||
--card-bg-color: rgba(255, 255, 255, 0.01);
|
|
||||||
--card-border-color: rgba(255, 255, 255, 0.1);
|
|
||||||
}
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
font-family: 'Inter', sans-serif;
|
|
||||||
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
|
|
||||||
color: var(--text-color);
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
min-height: 100vh;
|
|
||||||
text-align: center;
|
|
||||||
overflow: hidden;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
body::before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><path d="M-10 10L110 10M10 -10L10 110" stroke-width="1" stroke="rgba(255,255,255,0.05)"/></svg>');
|
|
||||||
animation: bg-pan 20s linear infinite;
|
|
||||||
z-index: -1;
|
|
||||||
}
|
|
||||||
@keyframes bg-pan {
|
|
||||||
0% { background-position: 0% 0%; }
|
|
||||||
100% { background-position: 100% 100%; }
|
|
||||||
}
|
|
||||||
main {
|
|
||||||
padding: 2rem;
|
|
||||||
}
|
|
||||||
.card {
|
|
||||||
background: var(--card-bg-color);
|
|
||||||
border: 1px solid var(--card-border-color);
|
|
||||||
border-radius: 16px;
|
|
||||||
padding: 2rem;
|
|
||||||
backdrop-filter: blur(20px);
|
|
||||||
-webkit-backdrop-filter: blur(20px);
|
|
||||||
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
.loader {
|
|
||||||
margin: 1.25rem auto 1.25rem;
|
|
||||||
width: 48px;
|
|
||||||
height: 48px;
|
|
||||||
border: 3px solid rgba(255, 255, 255, 0.25);
|
|
||||||
border-top-color: #fff;
|
|
||||||
border-radius: 50%;
|
|
||||||
animation: spin 1s linear infinite;
|
|
||||||
}
|
|
||||||
@keyframes spin {
|
|
||||||
from { transform: rotate(0deg); }
|
|
||||||
to { transform: rotate(360deg); }
|
|
||||||
}
|
|
||||||
.hint {
|
|
||||||
opacity: 0.9;
|
|
||||||
}
|
|
||||||
.sr-only {
|
|
||||||
position: absolute;
|
|
||||||
width: 1px; height: 1px;
|
|
||||||
padding: 0; margin: -1px;
|
|
||||||
overflow: hidden;
|
|
||||||
clip: rect(0, 0, 0, 0);
|
|
||||||
white-space: nowrap; border: 0;
|
|
||||||
}
|
|
||||||
h1 {
|
|
||||||
font-size: 3rem;
|
|
||||||
font-weight: 700;
|
|
||||||
margin: 0 0 1rem;
|
|
||||||
letter-spacing: -1px;
|
|
||||||
}
|
|
||||||
p {
|
|
||||||
margin: 0.5rem 0;
|
|
||||||
font-size: 1.1rem;
|
|
||||||
}
|
|
||||||
code {
|
|
||||||
background: rgba(0,0,0,0.2);
|
|
||||||
padding: 2px 6px;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
||||||
}
|
|
||||||
footer {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 1rem;
|
|
||||||
font-size: 0.8rem;
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<main>
|
|
||||||
<div class="card">
|
|
||||||
<h1>Analyzing your requirements and generating your website…</h1>
|
|
||||||
<div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes">
|
|
||||||
<span class="sr-only">Loading…</span>
|
|
||||||
</div>
|
</div>
|
||||||
<p class="hint"><?= ($_SERVER['HTTP_HOST'] ?? '') === 'appwizzy.com' ? 'AppWizzy' : 'Flatlogic' ?> AI is collecting your requirements and applying the first changes.</p>
|
|
||||||
<p class="hint">This page will update automatically as the plan is implemented.</p>
|
|
||||||
<p>Runtime: PHP <code><?= htmlspecialchars($phpVersion) ?></code> — UTC <code><?= htmlspecialchars($now) ?></code></p>
|
|
||||||
</div>
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="container">
|
||||||
|
<!-- Search and Filter Form -->
|
||||||
|
<div class="mb-5 p-4 rounded-3 shadow-sm bg-light">
|
||||||
|
<form action="index.php" method="GET" class="row g-3 align-items-end">
|
||||||
|
<div class="col-md-5">
|
||||||
|
<label for="search" class="form-label">Search</label>
|
||||||
|
<input type="text" class="form-control" id="search" name="search" placeholder="e.g., Passing, Dribbling..." value="<?php echo htmlspecialchars($searchTerm); ?>">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<label for="age_group" class="form-label">Age Group</label>
|
||||||
|
<select id="age_group" name="age_group" class="form-select">
|
||||||
|
<option value="">All Ages</option>
|
||||||
|
<?php foreach ($ageGroups as $ag): ?>
|
||||||
|
<option value="<?php echo htmlspecialchars($ag); ?>" <?php echo ($ageGroup === $ag) ? 'selected' : ''; ?>><?php echo htmlspecialchars($ag); ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2">
|
||||||
|
<label for="difficulty" class="form-label">Difficulty</label>
|
||||||
|
<select id="difficulty" name="difficulty" class="form-select">
|
||||||
|
<option value="">All</option>
|
||||||
|
<?php foreach ($difficulties as $d): ?>
|
||||||
|
<option value="<?php echo htmlspecialchars($d); ?>" <?php echo ($difficulty === $d) ? 'selected' : ''; ?>><?php echo htmlspecialchars($d); ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2">
|
||||||
|
<button type="submit" class="btn btn-primary w-100">Filter</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h2 class="mb-4">All Drills</h2>
|
||||||
|
|
||||||
|
<!-- Drills Grid -->
|
||||||
|
<div class="row row-cols-1 row-cols-sm-2 row-cols-md-3 g-4">
|
||||||
|
<?php if (empty($drills)): ?>
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="alert alert-info text-center">No drills found matching your criteria.</div>
|
||||||
|
</div>
|
||||||
|
<?php else: ?>
|
||||||
|
<?php foreach ($drills as $drill): ?>
|
||||||
|
<div class="col">
|
||||||
|
<div class="card h-100 card-drill shadow-sm">
|
||||||
|
<?php if (!empty($drill['image_path'])) : ?>
|
||||||
|
<img src="<?php echo htmlspecialchars($drill['image_path']); ?>" class="card-img-top" alt="<?php echo htmlspecialchars($drill['title']); ?>" style="height: 200px; object-fit: cover;">
|
||||||
|
<?php elseif (!empty($drill['youtube_url']) && get_youtube_id_from_url($drill['youtube_url'])) : ?>
|
||||||
|
<div class="card-img-top ratio ratio-16x9">
|
||||||
|
<iframe style="min-height: 200px;" src="https://www.youtube.com/embed/<?php echo get_youtube_id_from_url($drill['youtube_url']); ?>?rel=0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
|
||||||
|
</div>
|
||||||
|
<?php else : ?>
|
||||||
|
<svg class="card-img-top bg-light" width="100%" height="200" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Placeholder: Image" preserveAspectRatio="xMidYMid slice" focusable="false"><title>Placeholder</title><rect width="100%" height="100%" fill="var(--light-gray)"></rect><text x="50%" y="50%" fill="var(--text-color)" dy=".3em">No Image</text></svg>
|
||||||
|
<?php endif; ?>
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title fw-bold"><?php echo htmlspecialchars($drill['title']); ?></h5>
|
||||||
|
<p class="card-text text-muted"><?php echo htmlspecialchars(substr($drill['description'], 0, 80)); ?>...</p>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer bg-transparent border-top-0 d-flex justify-content-between align-items-center">
|
||||||
|
<a href="drill.php?id=<?php echo $drill['id']; ?>" class="btn btn-sm btn-outline-primary">View Details</a>
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<?php if (is_logged_in()): ?>
|
||||||
|
<span class="favorite-icon material-icons-outlined me-2 <?php echo $drill['is_favorite'] ? 'is-favorite' : ''; ?>" data-drill-id="<?php echo $drill['id']; ?>">
|
||||||
|
<?php echo $drill['is_favorite'] ? 'favorite' : 'favorite_border'; ?>
|
||||||
|
</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
<span class="badge bg-light text-dark me-1"><?php echo htmlspecialchars($drill['age_group']); ?></span>
|
||||||
|
<span class="badge
|
||||||
|
<?php
|
||||||
|
switch (strtolower($drill['difficulty'])) {
|
||||||
|
case 'easy': echo 'bg-success'; break;
|
||||||
|
case 'medium': echo 'bg-warning text-dark'; break;
|
||||||
|
case 'hard': echo 'bg-danger'; break;
|
||||||
|
default: echo 'bg-secondary';
|
||||||
|
}
|
||||||
|
?>">
|
||||||
|
<?php echo htmlspecialchars($drill['difficulty']); ?>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Pagination -->
|
||||||
|
<?php if ($totalPages > 1) : ?>
|
||||||
|
<nav aria-label="Page navigation">
|
||||||
|
<ul class="pagination justify-content-center">
|
||||||
|
<?php
|
||||||
|
// Build the query string for pagination links
|
||||||
|
$queryParams = $_GET;
|
||||||
|
unset($queryParams['page']);
|
||||||
|
$queryString = http_build_query($queryParams);
|
||||||
|
?>
|
||||||
|
|
||||||
|
<!-- Previous Page -->
|
||||||
|
<li class="page-item <?php echo ($currentPage <= 1) ? 'disabled' : ''; ?>">
|
||||||
|
<a class="page-link" href="?page=<?php echo $currentPage - 1; ?>&<?php echo $queryString; ?>" tabindex="-1" aria-disabled="true">Previous</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<!-- Page Numbers -->
|
||||||
|
<?php for ($i = 1; $i <= $totalPages; $i++) : ?>
|
||||||
|
<li class="page-item <?php echo ($i === $currentPage) ? 'active' : ''; ?>">
|
||||||
|
<a class="page-link" href="?page=<?php echo $i; ?>&<?php echo $queryString; ?>"><?php echo $i; ?></a>
|
||||||
|
</li>
|
||||||
|
<?php endfor; ?>
|
||||||
|
|
||||||
|
<!-- Next Page -->
|
||||||
|
<li class="page-item <?php echo ($currentPage >= $totalPages) ? 'disabled' : ''; ?>">
|
||||||
|
<a class="page-link" href="?page=<?php echo $currentPage + 1; ?>&<?php echo $queryString; ?>">Next</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
<?php endif; ?>
|
||||||
</main>
|
</main>
|
||||||
<footer>
|
|
||||||
Page updated: <?= htmlspecialchars($now) ?> (UTC)
|
<script>
|
||||||
</footer>
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
</body>
|
const favoriteIcons = document.querySelectorAll('.favorite-icon');
|
||||||
</html>
|
|
||||||
|
favoriteIcons.forEach(icon => {
|
||||||
|
icon.addEventListener('click', function () {
|
||||||
|
const drillId = this.dataset.drillId;
|
||||||
|
const isFavorited = this.textContent.trim() === 'favorite';
|
||||||
|
|
||||||
|
fetch('toggle_favorite.php', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded',
|
||||||
|
},
|
||||||
|
body: `drill_id=${drillId}`
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.success) {
|
||||||
|
this.textContent = isFavorited ? 'favorite_border' : 'favorite';
|
||||||
|
} else {
|
||||||
|
console.error('Failed to toggle favorite');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => console.error('Error:', error));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<?php require_once __DIR__ . '/partials/footer.php'; ?>
|
||||||
|
|||||||
73
login.php
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once __DIR__ . '/partials/header.php';
|
||||||
|
|
||||||
|
if (is_logged_in()) {
|
||||||
|
header('Location: index.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$error = null;
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
require_once __DIR__ . '/auth.php';
|
||||||
|
$email = $_POST['email'] ?? '';
|
||||||
|
$password = $_POST['password'] ?? '';
|
||||||
|
|
||||||
|
$user = login($email, $password);
|
||||||
|
|
||||||
|
if ($user) {
|
||||||
|
$_SESSION['user_id'] = $user['id'];
|
||||||
|
$_SESSION['user_name'] = $user['name'];
|
||||||
|
$_SESSION['user_role'] = $user['role'];
|
||||||
|
header('Location: index.php');
|
||||||
|
exit();
|
||||||
|
} else {
|
||||||
|
$error = 'Invalid email or password.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="container-fluid vh-100 d-flex justify-content-center align-items-center bg-light-gradient">
|
||||||
|
<div class="col-11 col-sm-8 col-md-6 col-lg-5 col-xl-4">
|
||||||
|
<div class="card shadow-lg border-0 rounded-4">
|
||||||
|
<div class="card-body p-4 p-sm-5">
|
||||||
|
<div class="text-center mb-4">
|
||||||
|
<h1 class="h2 fw-bold">Welcome Back</h1>
|
||||||
|
<p class="text-muted">Login to access your Drillex account.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if ($error) : ?>
|
||||||
|
<div class="alert alert-danger"><?php echo $error; ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<form action="login.php" method="POST">
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<input type="email" class="form-control" id="email" name="email" placeholder="name@example.com" required>
|
||||||
|
<label for="email">Email address</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-floating mb-4">
|
||||||
|
<input type="password" class="form-control" id="password" name="password" placeholder="Password" required>
|
||||||
|
<label for="password">Password</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-grid">
|
||||||
|
<button type="submit" class="btn btn-primary btn-lg rounded-pill">Login</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div class="text-center mt-4">
|
||||||
|
<p class="text-muted mb-2">or</p>
|
||||||
|
<a href="hybridauth_login.php?provider=Google" class="btn btn-outline-dark btn-lg rounded-pill w-100">
|
||||||
|
<i class="bi bi-google me-2"></i> Sign in with Google
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="text-center mt-4">
|
||||||
|
<p class="mb-0">Don't have an account? <a href="register.php" class="fw-bold text-decoration-none">Sign up</a></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php require_once __DIR__ . '/partials/footer.php'; ?>
|
||||||
6
logout.php
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
session_unset();
|
||||||
|
session_destroy();
|
||||||
|
header('Location: index.php');
|
||||||
|
exit();
|
||||||
202
my_drills.php
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/partials/header.php';
|
||||||
|
|
||||||
|
// Require login
|
||||||
|
if (!is_logged_in()) {
|
||||||
|
header('Location: login.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$current_user_id = get_user_id();
|
||||||
|
|
||||||
|
$pageTitle = 'My Drills';
|
||||||
|
$pageDescription = 'Manage your created drills.';
|
||||||
|
|
||||||
|
// Fetch drills for the current coach
|
||||||
|
$drills = [];
|
||||||
|
try {
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
// Fetch categories for the filter
|
||||||
|
$category_stmt = $pdo->query("SELECT * FROM categories ORDER BY name");
|
||||||
|
$categories = $category_stmt->fetchAll();
|
||||||
|
|
||||||
|
// Filtering logic
|
||||||
|
$selected_categories = isset($_GET['categories']) && is_array($_GET['categories']) ? $_GET['categories'] : [];
|
||||||
|
$show_favorites = isset($_GET['favorites']) && $_GET['favorites'] == '1';
|
||||||
|
|
||||||
|
$sql = "SELECT d.*, (uf.id IS NOT NULL) as is_favorite FROM drills d LEFT JOIN user_favorites uf ON d.id = uf.drill_id AND uf.user_id = ?";
|
||||||
|
$params = [$current_user_id];
|
||||||
|
|
||||||
|
$where_clauses = ["d.coach_id = ?"];
|
||||||
|
$params[] = $current_user_id;
|
||||||
|
|
||||||
|
if (!empty($selected_categories)) {
|
||||||
|
$sql .= " JOIN drill_categories dc ON d.id = dc.drill_id";
|
||||||
|
$where_clauses[] = "dc.category_id IN (" . str_repeat('?,', count($selected_categories) - 1) . "?)";
|
||||||
|
$params = array_merge($params, $selected_categories);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($show_favorites) {
|
||||||
|
$where_clauses[] = "uf.id IS NOT NULL";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($where_clauses)) {
|
||||||
|
$sql .= " WHERE " . implode(' AND ', $where_clauses);
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql .= " GROUP BY d.id ORDER BY d.created_at DESC";
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare($sql);
|
||||||
|
$stmt->execute($params);
|
||||||
|
$drills = $stmt->fetchAll();
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
// In a real app, log this error.
|
||||||
|
error_log("Database error: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<header class="py-5 text-center container-fluid">
|
||||||
|
<div class="row py-lg-5">
|
||||||
|
<div class="col-lg-6 col-md-8 mx-auto">
|
||||||
|
<h1 class="display-4 fw-bold">My Drills</h1>
|
||||||
|
<p class="lead text-muted">Here you can manage all the drills you have created.</p>
|
||||||
|
<a href="create_drill.php" class="btn btn-primary">Create New Drill</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main class="container">
|
||||||
|
<div class="mb-4 p-3 border rounded bg-light">
|
||||||
|
<form method="GET" action="my_drills.php">
|
||||||
|
<h5 class="mb-3">Filter</h5>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<h6>By Category</h6>
|
||||||
|
<div class="row">
|
||||||
|
<?php foreach ($categories as $category) : ?>
|
||||||
|
<div class="col-md-3 col-sm-6">
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" name="categories[]" value="<?php echo $category['id']; ?>" id="cat_<?php echo $category['id']; ?>" <?php echo in_array($category['id'], $selected_categories) ? 'checked' : ''; ?>>
|
||||||
|
<label class="form-check-label" for="cat_<?php echo $category['id']; ?>">
|
||||||
|
<?php echo htmlspecialchars($category['name']); ?>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 mt-3">
|
||||||
|
<h6>By Favorites</h6>
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" name="favorites" value="1" id="favorites_filter" <?php echo $show_favorites ? 'checked' : ''; ?>>
|
||||||
|
<label class="form-check-label" for="favorites_filter">
|
||||||
|
Show only favorites
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3">
|
||||||
|
<button type="submit" class="btn btn-primary">Filter</button>
|
||||||
|
<a href="my_drills.php" class="btn btn-secondary">Clear</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if (isset($_GET['success'])) : ?>
|
||||||
|
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
||||||
|
<?php echo htmlspecialchars($_GET['success']); ?>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if (isset($_GET['error'])) : ?>
|
||||||
|
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
||||||
|
<?php echo htmlspecialchars($_GET['error']); ?>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if (empty($drills)) : ?>
|
||||||
|
<div class="text-center p-5 border rounded-3 bg-light shadow-sm">
|
||||||
|
<p class="lead">You haven't created any drills yet.</p>
|
||||||
|
<p>Why not start now?</p>
|
||||||
|
<a href="create_drill.php" class="btn btn-lg btn-success">Create Your First Drill</a>
|
||||||
|
</div>
|
||||||
|
<?php else : ?>
|
||||||
|
<div class="row row-cols-1 row-cols-sm-2 row-cols-md-3 g-4">
|
||||||
|
<?php foreach ($drills as $drill) : ?>
|
||||||
|
<div class="col">
|
||||||
|
<div class="card h-100 card-drill">
|
||||||
|
<a href="drill.php?id=<?php echo $drill['id']; ?>">
|
||||||
|
<img src="<?php echo $drill['image_path'] ? htmlspecialchars($drill['image_path']) : 'https://via.placeholder.com/400x250.png?text=No+Image'; ?>" class="card-img-top" alt="Drill Image">
|
||||||
|
</a>
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title fw-bold"><?php echo htmlspecialchars($drill['title']); ?></h5>
|
||||||
|
<p class="card-text text-muted"><?php echo htmlspecialchars(substr($drill['description'], 0, 80)); ?>...</p>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer bg-transparent border-top-0">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||||
|
<a href="drill.php?id=<?php echo $drill['id']; ?>" class="btn btn-sm btn-outline-primary">View</a>
|
||||||
|
<i class="material-icons favorite-icon" data-drill-id="<?php echo $drill['id']; ?>" style="cursor: pointer;">
|
||||||
|
<?php echo $drill['is_favorite'] ? 'favorite' : 'favorite_border'; ?>
|
||||||
|
</i>
|
||||||
|
<div>
|
||||||
|
<span class="badge bg-light text-dark me-1"><?php echo htmlspecialchars($drill['age_group']); ?></span>
|
||||||
|
<span class="badge
|
||||||
|
<?php
|
||||||
|
switch (strtolower($drill['difficulty'])) {
|
||||||
|
case 'easy': echo 'bg-success'; break;
|
||||||
|
case 'medium': echo 'bg-warning text-dark'; break;
|
||||||
|
case 'hard': echo 'bg-danger'; break;
|
||||||
|
default: echo 'bg-secondary';
|
||||||
|
}
|
||||||
|
?>">
|
||||||
|
<?php echo htmlspecialchars($drill['difficulty']); ?>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex justify-content-end gap-2">
|
||||||
|
<a href="edit_drill.php?id=<?php echo $drill['id']; ?>" class="btn btn-sm btn-outline-secondary">Edit</a>
|
||||||
|
<a href="delete_drill.php?id=<?php echo $drill['id']; ?>" class="btn btn-sm btn-outline-danger" onclick="return confirm('Are you sure you want to delete this drill?');">Delete</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.querySelectorAll('.favorite-icon').forEach(icon => {
|
||||||
|
icon.addEventListener('click', function() {
|
||||||
|
const drillId = this.dataset.drillId;
|
||||||
|
const isFavorited = this.textContent.trim() === 'favorite';
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('drill_id', drillId);
|
||||||
|
|
||||||
|
fetch('toggle_favorite.php', {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.success) {
|
||||||
|
if (data.status === 'added') {
|
||||||
|
this.textContent = 'favorite';
|
||||||
|
} else {
|
||||||
|
this.textContent = 'favorite_border';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alert(data.message || 'An error occurred.');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error:', error);
|
||||||
|
alert('An error occurred while favoriting this drill.');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<?php require_once __DIR__ . '/partials/footer.php'; ?>
|
||||||
10
partials/footer.php
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<footer class="py-4 mt-5 footer">
|
||||||
|
<div class="container text-center">
|
||||||
|
<p class="mb-0">© <?php echo date("Y"); ?> <?php echo htmlspecialchars($pageTitle); ?>. All rights reserved.</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
97
partials/header.php
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/../auth.php';
|
||||||
|
|
||||||
|
$pageTitle = getenv('PROJECT_NAME') ?: 'Drillex';
|
||||||
|
$pageDescription = getenv('PROJECT_DESCRIPTION') ?: 'Create, share, and discover training drills.';
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title><?php echo htmlspecialchars($pageTitle); ?></title>
|
||||||
|
<meta name="description" content="<?php echo htmlspecialchars($pageDescription); ?>">
|
||||||
|
|
||||||
|
<!-- Open Graph / Facebook -->
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<meta property="og:title" content="<?php echo htmlspecialchars($pageTitle); ?>">
|
||||||
|
<meta property="og:description" content="<?php echo htmlspecialchars($pageDescription); ?>">
|
||||||
|
<meta property="og:image" content="<?php echo htmlspecialchars($_SERVER['PROJECT_IMAGE_URL'] ?? ''); ?>">
|
||||||
|
|
||||||
|
<!-- Twitter -->
|
||||||
|
<meta property="twitter:card" content="summary_large_image">
|
||||||
|
<meta property="twitter:title" content="<?php echo htmlspecialchars($pageTitle); ?>">
|
||||||
|
<meta property="twitter:description" content="<?php echo htmlspecialchars($pageDescription); ?>">
|
||||||
|
<meta property="twitter:image" content="<?php echo htmlspecialchars($_SERVER['PROJECT_IMAGE_URL'] ?? ''); ?>">
|
||||||
|
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&family=Inter:wght@400;500&display=swap" rel="stylesheet">
|
||||||
|
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="assets/css/theme.css?v=<?php echo time(); ?>">
|
||||||
|
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||||
|
<link rel="icon" href="assets/images/favicon.svg" type="image/svg+xml">
|
||||||
|
</head>
|
||||||
|
<body >
|
||||||
|
|
||||||
|
<nav class="navbar navbar-expand-lg navbar-light sticky-top">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<a class="navbar-brand" href="index.php">
|
||||||
|
<svg width="150" height="36" viewBox="0 0 250 60" xmlns="http://www.w3.org/2000/svg" class="logo">
|
||||||
|
<text x="10" y="45" font-family="Arial, sans-serif" font-size="40" font-weight="bold">
|
||||||
|
<tspan fill="var(--text-color)">Drill</tspan><tspan class="logo-text-primary">ex</tspan>
|
||||||
|
</text>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<div class="form-check form-switch me-3">
|
||||||
|
<input class="form-check-input" type="checkbox" id="theme-switcher">
|
||||||
|
<label class="form-check-label" for="theme-switcher">
|
||||||
|
<span class="d-none d-sm-inline">Dark Mode</span>
|
||||||
|
<i class="material-icons vm">brightness_4</i>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
<div class="collapse navbar-collapse" id="navbarNav">
|
||||||
|
<ul class="navbar-nav ms-auto">
|
||||||
|
<?php if (is_logged_in()): ?>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href="create_drill.php" class="btn btn-primary me-2">Create Drill</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href="my_drills.php" class="nav-link">My Drills</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href="training_sessions.php" class="nav-link">Training Sessions</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href="teams.php" class="nav-link">Teams</a>
|
||||||
|
</li>
|
||||||
|
<?php if (is_admin()): ?>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href="admin/users.php" class="nav-link">Manage Users</a>
|
||||||
|
</li>
|
||||||
|
<?php endif; ?>
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
|
<?php echo htmlspecialchars($_SESSION['user_name']); ?>
|
||||||
|
</a>
|
||||||
|
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown">
|
||||||
|
<li><a class="dropdown-item" href="logout.php">Logout</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<?php else: ?>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href="login.php" class="btn btn-outline-primary me-2">Login</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href="register.php" class="btn btn-primary">Register</a>
|
||||||
|
</li>
|
||||||
|
<?php endif; ?>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
95
register.php
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once __DIR__ . '/partials/header.php';
|
||||||
|
|
||||||
|
if (is_logged_in()) {
|
||||||
|
header('Location: index.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$error = null;
|
||||||
|
$success = null;
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
$name = $_POST['name'] ?? '';
|
||||||
|
$email = $_POST['email'] ?? '';
|
||||||
|
$password = $_POST['password'] ?? '';
|
||||||
|
$password_confirm = $_POST['password_confirm'] ?? '';
|
||||||
|
|
||||||
|
if (empty($name) || empty($email) || empty($password)) {
|
||||||
|
$error = 'All fields are required.';
|
||||||
|
} elseif ($password !== $password_confirm) {
|
||||||
|
$error = 'Passwords do not match.';
|
||||||
|
} else {
|
||||||
|
$pdo = db();
|
||||||
|
$stmt = $pdo->prepare("SELECT id FROM users WHERE email = :email");
|
||||||
|
$stmt->execute(['email' => $email]);
|
||||||
|
if ($stmt->fetch()) {
|
||||||
|
$error = 'Email already in use.';
|
||||||
|
} else {
|
||||||
|
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO users (name, email, password, role) VALUES (:name, :email, :password, 'coach')");
|
||||||
|
if ($stmt->execute(['name' => $name, 'email' => $email, 'password' => $hashed_password])) {
|
||||||
|
$success = 'Registration successful! You can now <a href="login.php" class="fw-bold text-decoration-none">login</a>.';
|
||||||
|
} else {
|
||||||
|
$error = 'An error occurred. Please try again.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="container-fluid vh-100 d-flex justify-content-center align-items-center bg-light-gradient">
|
||||||
|
<div class="col-11 col-sm-8 col-md-6 col-lg-5 col-xl-4">
|
||||||
|
<div class="card shadow-lg border-0 rounded-4">
|
||||||
|
<div class="card-body p-4 p-sm-5">
|
||||||
|
<div class="text-center mb-4">
|
||||||
|
<h1 class="h2 fw-bold">Create Your Account</h1>
|
||||||
|
<p class="text-muted">Join Drillex to start creating and sharing drills.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if ($error) : ?>
|
||||||
|
<div class="alert alert-danger"><?php echo $error; ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if ($success) : ?>
|
||||||
|
<div class="alert alert-success"><?php echo $success; ?></div>
|
||||||
|
<?php else : ?>
|
||||||
|
<form action="register.php" method="POST">
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<input type="text" class="form-control" id="name" name="name" placeholder="Your Name" required>
|
||||||
|
<label for="name">Name</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<input type="email" class="form-control" id="email" name="email" placeholder="name@example.com" required>
|
||||||
|
<label for="email">Email address</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-floating mb-3">
|
||||||
|
<input type="password" class="form-control" id="password" name="password" placeholder="Password" required>
|
||||||
|
<label for="password">Password</label>
|
||||||
|
</div>
|
||||||
|
<div class="form-floating mb-4">
|
||||||
|
<input type="password" class="form-control" id="password_confirm" name="password_confirm" placeholder="Confirm Password" required>
|
||||||
|
<label for="password_confirm">Confirm Password</label>
|
||||||
|
</div>
|
||||||
|
<div class="d-grid">
|
||||||
|
<button type="submit" class="btn btn-primary btn-lg rounded-pill">Create Account</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<div class="text-center mt-4">
|
||||||
|
<p class="text-muted mb-2">or</p>
|
||||||
|
<a href="hybridauth_login.php?provider=Google" class="btn btn-outline-dark btn-lg rounded-pill w-100">
|
||||||
|
<i class="bi bi-google me-2"></i> Sign in with Google
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="text-center mt-4">
|
||||||
|
<p class="mb-0">Already have an account? <a href="login.php" class="fw-bold text-decoration-none">Login</a></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php require_once __DIR__ . '/partials/footer.php'; ?>
|
||||||
217
team.php
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'auth.php';
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
if (!is_logged_in()) {
|
||||||
|
header('Location: login.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($_GET['id']) || !is_numeric($_GET['id'])) {
|
||||||
|
header('Location: teams.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$team_id = $_GET['id'];
|
||||||
|
$user_id = $_SESSION['user_id'];
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
// Get the current user's role in the team
|
||||||
|
$stmt = $pdo->prepare("SELECT role FROM team_members WHERE team_id = ? AND user_id = ?");
|
||||||
|
$stmt->execute([$team_id, $user_id]);
|
||||||
|
$current_user_role = $stmt->fetchColumn();
|
||||||
|
|
||||||
|
// Fetch team details
|
||||||
|
$stmt = $pdo->prepare("SELECT name, owner_user_id FROM teams WHERE id = ?");
|
||||||
|
$stmt->execute([$team_id]);
|
||||||
|
$team = $stmt->fetch();
|
||||||
|
|
||||||
|
if (!$team) {
|
||||||
|
header('Location: teams.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$is_owner = ($current_user_role == 'owner');
|
||||||
|
$is_admin = ($current_user_role == 'admin');
|
||||||
|
$is_member = $current_user_role;
|
||||||
|
|
||||||
|
// Handle POST requests for team management
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
// Must be a member to perform any action
|
||||||
|
if (!$is_member) {
|
||||||
|
header("Location: team.php?id=$team_id");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a new member
|
||||||
|
if (isset($_POST['add_member']) && ($is_owner || $is_admin)) {
|
||||||
|
$email = trim($_POST['email']);
|
||||||
|
$stmt = $pdo->prepare("SELECT id FROM users WHERE email = ?");
|
||||||
|
$stmt->execute([$email]);
|
||||||
|
$new_member_id = $stmt->fetchColumn();
|
||||||
|
|
||||||
|
if ($new_member_id) {
|
||||||
|
// Add as a 'member' by default
|
||||||
|
$stmt = $pdo->prepare("INSERT IGNORE INTO team_members (team_id, user_id, role) VALUES (?, ?, 'member')");
|
||||||
|
$stmt->execute([$team_id, $new_member_id]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove a member
|
||||||
|
if (isset($_POST['remove_member']) && isset($_POST['member_id'])) {
|
||||||
|
$member_id_to_remove = $_POST['member_id'];
|
||||||
|
|
||||||
|
// Get the role of the member to be removed
|
||||||
|
$stmt = $pdo->prepare("SELECT role FROM team_members WHERE team_id = ? AND user_id = ?");
|
||||||
|
$stmt->execute([$team_id, $member_id_to_remove]);
|
||||||
|
$member_to_remove_role = $stmt->fetchColumn();
|
||||||
|
|
||||||
|
// Owners can remove anyone except themselves
|
||||||
|
// Admins can only remove members
|
||||||
|
if ($is_owner && $member_id_to_remove != $user_id) {
|
||||||
|
$stmt = $pdo->prepare("DELETE FROM team_members WHERE team_id = ? AND user_id = ?");
|
||||||
|
$stmt->execute([$team_id, $member_id_to_remove]);
|
||||||
|
} elseif ($is_admin && $member_to_remove_role == 'member') {
|
||||||
|
$stmt = $pdo->prepare("DELETE FROM team_members WHERE team_id = ? AND user_id = ?");
|
||||||
|
$stmt->execute([$team_id, $member_id_to_remove]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Promote to Admin
|
||||||
|
if (isset($_POST['promote_admin']) && isset($_POST['member_id']) && $is_owner) {
|
||||||
|
$member_id_to_promote = $_POST['member_id'];
|
||||||
|
$stmt = $pdo->prepare("UPDATE team_members SET role = 'admin' WHERE team_id = ? AND user_id = ? AND role = 'member'");
|
||||||
|
$stmt->execute([$team_id, $member_id_to_promote]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Demote to Member
|
||||||
|
if (isset($_POST['demote_admin']) && isset($_POST['member_id']) && $is_owner) {
|
||||||
|
$member_id_to_demote = $_POST['member_id'];
|
||||||
|
$stmt = $pdo->prepare("UPDATE team_members SET role = 'member' WHERE team_id = ? AND user_id = ? AND role = 'admin'");
|
||||||
|
$stmt->execute([$team_id, $member_id_to_demote]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transfer Ownership
|
||||||
|
if (isset($_POST['make_owner']) && isset($_POST['member_id']) && $is_owner) {
|
||||||
|
$new_owner_id = $_POST['member_id'];
|
||||||
|
// Start transaction
|
||||||
|
$pdo->beginTransaction();
|
||||||
|
try {
|
||||||
|
// New owner becomes 'owner'
|
||||||
|
$stmt = $pdo->prepare("UPDATE team_members SET role = 'owner' WHERE team_id = ? AND user_id = ?");
|
||||||
|
$stmt->execute([$team_id, $new_owner_id]);
|
||||||
|
|
||||||
|
// Old owner becomes 'admin'
|
||||||
|
$stmt = $pdo->prepare("UPDATE team_members SET role = 'admin' WHERE team_id = ? AND user_id = ?");
|
||||||
|
$stmt->execute([$team_id, $user_id]);
|
||||||
|
|
||||||
|
// Update owner_user_id in teams table
|
||||||
|
$stmt = $pdo->prepare("UPDATE teams SET owner_user_id = ? WHERE id = ?");
|
||||||
|
$stmt->execute([$new_owner_id, $team_id]);
|
||||||
|
|
||||||
|
$pdo->commit();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$pdo->rollBack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Leave team
|
||||||
|
if (isset($_POST['leave_team']) && !$is_owner) {
|
||||||
|
$stmt = $pdo->prepare("DELETE FROM team_members WHERE team_id = ? AND user_id = ?");
|
||||||
|
$stmt->execute([$team_id, $user_id]);
|
||||||
|
header("Location: teams.php"); // Redirect to teams list after leaving
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
header("Location: team.php?id=$team_id");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once 'partials/header.php';
|
||||||
|
|
||||||
|
// Fetch all team members with their roles and user details
|
||||||
|
$stmt = $pdo->prepare(
|
||||||
|
"SELECT u.id, u.name, u.email, tm.role FROM users u " .
|
||||||
|
"JOIN team_members tm ON u.id = tm.user_id " .
|
||||||
|
"WHERE tm.team_id = ? ORDER BY tm.role, u.name"
|
||||||
|
);
|
||||||
|
$stmt->execute([$team_id]);
|
||||||
|
$members = $stmt->fetchAll();
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="container mt-5">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
|
<h2>Team: <?php echo htmlspecialchars($team['name']); ?></h2>
|
||||||
|
<?php if ($is_member && !$is_owner): ?>
|
||||||
|
<form method="POST" onsubmit="return confirm('Are you sure you want to leave this team?');">
|
||||||
|
<button type="submit" name="leave_team" class="btn btn-danger">Leave Team</button>
|
||||||
|
</form>
|
||||||
|
<?php elseif ($is_owner): ?>
|
||||||
|
<span class="text-muted">You are the owner. Transfer ownership to leave.</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if (!$is_member): ?>
|
||||||
|
<div class="alert alert-warning">You are not a member of this team.</div>
|
||||||
|
<?php // In a future step, we could show a public/private status and a join button here ?>
|
||||||
|
<?php else: ?>
|
||||||
|
<?php if ($is_owner || $is_admin): ?>
|
||||||
|
<div class="card mb-4">
|
||||||
|
<div class="card-header">Add New Member</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form method="POST" class="row g-3">
|
||||||
|
<div class="col-auto">
|
||||||
|
<input type="email" class="form-control" name="email" placeholder="Enter user's email" required>
|
||||||
|
</div>
|
||||||
|
<div class="col-auto">
|
||||||
|
<button type="submit" name="add_member" class="btn btn-primary">Add Member</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<h4>Members (<?php echo count($members); ?>)</h4>
|
||||||
|
<div class="list-group">
|
||||||
|
<?php foreach ($members as $member): ?>
|
||||||
|
<div class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
|
<div>
|
||||||
|
<strong><?php echo htmlspecialchars($member['name']); ?></strong> (<?php echo htmlspecialchars($member['email']); ?>)
|
||||||
|
<span class="badge bg-secondary ms-2"><?php echo ucfirst($member['role']); ?></span>
|
||||||
|
</div>
|
||||||
|
<div class="btn-group">
|
||||||
|
<?php if ($is_owner && $member['id'] !== $user_id): ?>
|
||||||
|
<form method="POST" class="d-inline" onsubmit="return confirm('Promote this member to Admin?');">
|
||||||
|
<input type="hidden" name="member_id" value="<?php echo $member['id']; ?>">
|
||||||
|
<?php if ($member['role'] == 'member'): ?>
|
||||||
|
<button type="submit" name="promote_admin" class="btn btn-sm btn-outline-secondary">Promote to Admin</button>
|
||||||
|
<?php elseif ($member['role'] == 'admin'): ?>
|
||||||
|
<form method="POST" class="d-inline" onsubmit="return confirm('Demote this member to Member?');">
|
||||||
|
<input type="hidden" name="member_id" value="<?php echo $member['id']; ?>">
|
||||||
|
<button type="submit" name="demote_admin" class="btn btn-sm btn-outline-warning">Demote to Member</button>
|
||||||
|
</form>
|
||||||
|
<?php endif; ?>
|
||||||
|
</form>
|
||||||
|
<form method="POST" class="d-inline ms-1" onsubmit="return confirm('Make this member the new owner? You will become an Admin.');">
|
||||||
|
<input type="hidden" name="member_id" value="<?php echo $member['id']; ?>">
|
||||||
|
<button type="submit" name="make_owner" class="btn btn-sm btn-outline-primary">Make Owner</button>
|
||||||
|
</form>
|
||||||
|
<form method="POST" class="d-inline ms-1" onsubmit="return confirm('Are you sure you want to remove this member?');">
|
||||||
|
<input type="hidden" name="member_id" value="<?php echo $member['id']; ?>">
|
||||||
|
<button type="submit" name="remove_member" class="btn btn-sm btn-danger">Remove</button>
|
||||||
|
</form>
|
||||||
|
<?php elseif ($is_admin && $member['role'] === 'member'): ?>
|
||||||
|
<form method="POST" class="d-inline" onsubmit="return confirm('Are you sure you want to remove this member?');">
|
||||||
|
<input type="hidden" name="member_id" value="<?php echo $member['id']; ?>">
|
||||||
|
<button type="submit" name="remove_member" class="btn btn-sm btn-danger">Remove</button>
|
||||||
|
</form>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php require_once 'partials/footer.php'; ?>
|
||||||
99
teams.php
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'auth.php';
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
if (!is_logged_in()) {
|
||||||
|
header('Location: login.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$user_id = $_SESSION['user_id'];
|
||||||
|
$pdo = db();
|
||||||
|
$teams = [];
|
||||||
|
$error_message = '';
|
||||||
|
|
||||||
|
// Handle team creation
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['create_team'])) {
|
||||||
|
$team_name = trim($_POST['team_name']);
|
||||||
|
if (!empty($team_name)) {
|
||||||
|
try {
|
||||||
|
// Create the team
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO teams (name, owner_user_id) VALUES (?, ?)");
|
||||||
|
$stmt->execute([$team_name, $user_id]);
|
||||||
|
$team_id = $pdo->lastInsertId();
|
||||||
|
|
||||||
|
// Automatically add the creator as a member with the 'owner' role
|
||||||
|
$stmt = $pdo->prepare("INSERT INTO team_members (team_id, user_id, role) VALUES (?, ?, 'owner')");
|
||||||
|
$stmt->execute([$team_id, $user_id]);
|
||||||
|
|
||||||
|
header('Location: teams.php'); // Redirect to avoid form resubmission
|
||||||
|
exit();
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
error_log("Database error in teams.php (create team): " . $e->getMessage());
|
||||||
|
$error_message = "Failed to create team. Please try again.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch teams for the current user
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->prepare(
|
||||||
|
"SELECT t.id, t.name, t.owner_user_id FROM teams t " .
|
||||||
|
"JOIN team_members tm ON t.id = tm.team_id " .
|
||||||
|
"WHERE tm.user_id = ?"
|
||||||
|
);
|
||||||
|
$stmt->execute([$user_id]);
|
||||||
|
$teams = $stmt->fetchAll();
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
error_log("Database error in teams.php (fetch teams): " . $e->getMessage());
|
||||||
|
$error_message = "Failed to load teams. Please contact support.";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
require_once 'partials/header.php';
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="container mt-5">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<h2>My Teams</h2>
|
||||||
|
<?php if (!empty($error_message)): ?>
|
||||||
|
<div class="alert alert-danger"><?php echo htmlspecialchars($error_message); ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if (empty($teams)): ?>
|
||||||
|
<p>You are not a member of any teams yet.</p>
|
||||||
|
<?php else: ?>
|
||||||
|
<ul class="list-group">
|
||||||
|
<?php foreach ($teams as $team): ?>
|
||||||
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
|
<a href="team.php?id=<?php echo $team['id']; ?>"><?php echo htmlspecialchars($team['name']); ?></a>
|
||||||
|
<?php if ($team['owner_user_id'] == $user_id): ?>
|
||||||
|
<span class="badge bg-primary rounded-pill">Owner</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</li>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</ul>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<h5 class="card-title">Create a New Team</h5>
|
||||||
|
<form method="POST">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="team_name" class="form-label">Team Name</label>
|
||||||
|
<input type="text" class="form-control" id="team_name" name="team_name" required>
|
||||||
|
</div>
|
||||||
|
<button type="submit" name="create_team" class="btn btn-primary">Create Team</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
require_once 'partials/footer.php';
|
||||||
|
?>
|
||||||
58
toggle_favorite.php
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/auth.php';
|
||||||
|
require_once __DIR__ . '/db/config.php';
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
if (!is_logged_in()) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'User not logged in']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$user_id = $_SESSION['user_id'];
|
||||||
|
$drill_id = isset($_POST['drill_id']) ? (int)$_POST['drill_id'] : null;
|
||||||
|
$session_id = isset($_POST['session_id']) ? (int)$_POST['session_id'] : null;
|
||||||
|
|
||||||
|
if (!$drill_id && !$session_id) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Drill or session ID required']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
// Check if it's already a favorite
|
||||||
|
if ($drill_id) {
|
||||||
|
$stmt = $pdo->prepare('SELECT id FROM user_favorites WHERE user_id = ? AND drill_id = ?');
|
||||||
|
$stmt->execute([$user_id, $drill_id]);
|
||||||
|
} else {
|
||||||
|
$stmt = $pdo->prepare('SELECT id FROM user_favorites WHERE user_id = ? AND training_session_id = ?');
|
||||||
|
$stmt->execute([$user_id, $session_id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$is_favorite = $stmt->fetch();
|
||||||
|
|
||||||
|
try {
|
||||||
|
if ($is_favorite) {
|
||||||
|
// Remove from favorites
|
||||||
|
if ($drill_id) {
|
||||||
|
$stmt = $pdo->prepare('DELETE FROM user_favorites WHERE user_id = ? AND drill_id = ?');
|
||||||
|
$stmt->execute([$user_id, $drill_id]);
|
||||||
|
} else {
|
||||||
|
$stmt = $pdo->prepare('DELETE FROM user_favorites WHERE user_id = ? AND training_session_id = ?');
|
||||||
|
$stmt->execute([$user_id, $session_id]);
|
||||||
|
}
|
||||||
|
echo json_encode(['success' => true, 'status' => 'removed']);
|
||||||
|
} else {
|
||||||
|
// Add to favorites
|
||||||
|
if ($drill_id) {
|
||||||
|
$stmt = $pdo->prepare('INSERT INTO user_favorites (user_id, drill_id) VALUES (?, ?)');
|
||||||
|
$stmt->execute([$user_id, $drill_id]);
|
||||||
|
} else {
|
||||||
|
$stmt = $pdo->prepare('INSERT INTO user_favorites (user_id, training_session_id) VALUES (?, ?)');
|
||||||
|
$stmt->execute([$user_id, $session_id]);
|
||||||
|
}
|
||||||
|
echo json_encode(['success' => true, 'status' => 'added']);
|
||||||
|
}
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Database error: ' . $e->getMessage()]);
|
||||||
|
}
|
||||||
92
training_session.php
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/partials/header.php';
|
||||||
|
|
||||||
|
// Require login
|
||||||
|
if (!is_logged_in()) {
|
||||||
|
header('Location: login.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$session_id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
|
||||||
|
if (!$session_id) {
|
||||||
|
header('Location: training_sessions.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$coach_id = get_user_id();
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
// Fetch the training session
|
||||||
|
$stmt = $pdo->prepare("SELECT * FROM training_sessions WHERE id = ? AND coach_id = ?");
|
||||||
|
$stmt->execute([$session_id, $coach_id]);
|
||||||
|
$session = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (!$session) {
|
||||||
|
// Or show a 404 not found page
|
||||||
|
header('Location: training_sessions.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch the drills for this session, in order
|
||||||
|
$stmt = $pdo->prepare(
|
||||||
|
"SELECT d.*
|
||||||
|
FROM drills d
|
||||||
|
JOIN training_session_drills tsd ON d.id = tsd.drill_id
|
||||||
|
WHERE tsd.session_id = ? "
|
||||||
|
);
|
||||||
|
$stmt->execute([$session_id]);
|
||||||
|
$drills = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
$pageTitle = htmlspecialchars($session['name']);
|
||||||
|
$pageDescription = htmlspecialchars(substr($session['description'], 0, 150));
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<main class="container my-5">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-10 mx-auto">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
|
<div>
|
||||||
|
<h1 class="h2"><?php echo $pageTitle; ?></h1>
|
||||||
|
<p class="text-muted"><?php echo $pageDescription; ?></p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a href="edit_training_session.php?id=<?php echo $session['id']; ?>" class="btn btn-outline-secondary me-2">Edit</a>
|
||||||
|
<a href="delete_training_session.php?id=<?php echo $session['id']; ?>" class="btn btn-danger" onclick="return confirm('Are you sure you want to delete this session?');">Delete</a>
|
||||||
|
<a href="export_training_session_pdf.php?id=<?php echo $session['id']; ?>" class="btn btn-outline-primary">Export to PDF</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card shadow-sm border-0 rounded-4">
|
||||||
|
<div class="card-header bg-light p-3">
|
||||||
|
<h5 class="mb-0">Drills in this Session</h5>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<?php if (empty($drills)): ?>
|
||||||
|
<p class="text-center text-muted m-3">This training session has no drills.</p>
|
||||||
|
<?php else: ?>
|
||||||
|
<div class="accordion" id="drills-accordion">
|
||||||
|
<?php foreach ($drills as $index => $drill): ?>
|
||||||
|
<div class="accordion-item">
|
||||||
|
<h2 class="accordion-header" id="heading-<?php echo $drill['id']; ?>">
|
||||||
|
<button class="accordion-button <?php echo $index > 0 ? 'collapsed' : ''; ?>" type="button" data-bs-toggle="collapse" data-bs-target="#collapse-<?php echo $drill['id']; ?>" aria-expanded="<?php echo $index === 0 ? 'true' : 'false'; ?>" aria-controls="collapse-<?php echo $drill['id']; ?>">
|
||||||
|
<strong><?php echo htmlspecialchars($drill['title']); ?></strong> (<?php echo $drill['duration_minutes'] ?> mins)
|
||||||
|
</button>
|
||||||
|
</h2>
|
||||||
|
<div id="collapse-<?php echo $drill['id']; ?>" class="accordion-collapse collapse <?php echo $index === 0 ? 'show' : ''; ?>" aria-labelledby="heading-<?php echo $drill['id']; ?>" data-bs-parent="#drills-accordion">
|
||||||
|
<div class="accordion-body">
|
||||||
|
<p><?php echo nl2br(htmlspecialchars($drill['description'])); ?></p>
|
||||||
|
<a href="drill.php?id=<?php echo $drill['id']; ?>" class="btn btn-sm btn-outline-primary">View Full Drill Details</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<?php require_once __DIR__ . '/partials/footer.php'; ?>
|
||||||
128
training_sessions.php
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/partials/header.php';
|
||||||
|
|
||||||
|
// Require login
|
||||||
|
if (!is_logged_in()) {
|
||||||
|
header('Location: login.php');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$pageTitle = 'Training Sessions';
|
||||||
|
$pageDescription = 'Manage your training sessions.';
|
||||||
|
|
||||||
|
$coach_id = get_user_id();
|
||||||
|
$pdo = db();
|
||||||
|
|
||||||
|
// Filtering logic
|
||||||
|
$show_favorites = isset($_GET['favorites']) && $_GET['favorites'] == '1';
|
||||||
|
|
||||||
|
$sql = "SELECT ts.*, (uf.id IS NOT NULL) as is_favorite
|
||||||
|
FROM training_sessions ts
|
||||||
|
LEFT JOIN user_favorites uf ON ts.id = uf.training_session_id AND uf.user_id = ?
|
||||||
|
WHERE ts.coach_id = ?";
|
||||||
|
$params = [$coach_id, $coach_id];
|
||||||
|
|
||||||
|
if ($show_favorites) {
|
||||||
|
$sql .= " AND uf.id IS NOT NULL";
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql .= " ORDER BY ts.created_at DESC";
|
||||||
|
|
||||||
|
// Fetch training sessions for the current coach
|
||||||
|
$stmt = $pdo->prepare($sql);
|
||||||
|
$stmt->execute($params);
|
||||||
|
$sessions = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<main class="container my-5">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
|
<h1 class="h2">My Training Sessions</h1>
|
||||||
|
<a href="create_training_session.php" class="btn btn-primary">Create New Session</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-4 p-3 border rounded bg-light">
|
||||||
|
<form method="GET" action="training_sessions.php">
|
||||||
|
<h5 class="mb-3">Filter</h5>
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" name="favorites" value="1" id="favorites_filter" <?php echo $show_favorites ? 'checked' : ''; ?>>
|
||||||
|
<label class="form-check-label" for="favorites_filter">
|
||||||
|
Show only favorites
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3">
|
||||||
|
<button type="submit" class="btn btn-primary">Filter</button>
|
||||||
|
<a href="training_sessions.php" class="btn btn-secondary">Clear</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if (isset($_GET['status']) && $_GET['status'] === 'created'): ?>
|
||||||
|
<div class="alert alert-success">Training session created successfully!</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<div class="card shadow-sm border-0 rounded-4">
|
||||||
|
<div class="card-body">
|
||||||
|
<?php if (empty($sessions)): ?>
|
||||||
|
<div class="text-center p-4">
|
||||||
|
<p class="mb-0 text-muted">You haven't created any training sessions yet.</p>
|
||||||
|
</div>
|
||||||
|
<?php else: ?>
|
||||||
|
<div class="list-group list-group-flush">
|
||||||
|
<?php foreach ($sessions as $session): ?>
|
||||||
|
<div class="list-group-item list-group-item-action d-flex justify-content-between align-items-center">
|
||||||
|
<a href="training_session.php?id=<?php echo $session['id']; ?>" class="text-decoration-none text-dark flex-grow-1">
|
||||||
|
<h5 class="mb-1"><?php echo htmlspecialchars($session['name']); ?></h5>
|
||||||
|
<p class="mb-1 text-muted small"><?php echo htmlspecialchars(substr($session['description'], 0, 100)); ?>...</p>
|
||||||
|
</a>
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<i class="material-icons favorite-icon me-3 <?php echo $session['is_favorite'] ? 'is-favorite' : ''; ?>" data-session-id="<?php echo $session['id']; ?>">
|
||||||
|
<?php echo $session['is_favorite'] ? 'favorite' : 'favorite_border'; ?>
|
||||||
|
</i>
|
||||||
|
<span class="badge bg-light text-dark rounded-pill"><?php echo date("M d, Y", strtotime($session['created_at'])); ?></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.querySelectorAll('.favorite-icon').forEach(icon => {
|
||||||
|
icon.addEventListener('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
const sessionId = this.dataset.sessionId;
|
||||||
|
const isFavorited = this.textContent.trim() === 'favorite';
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('session_id', sessionId);
|
||||||
|
|
||||||
|
fetch('toggle_favorite.php', {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.success) {
|
||||||
|
if (data.status === 'added') {
|
||||||
|
this.textContent = 'favorite';
|
||||||
|
this.classList.add('is-favorite');
|
||||||
|
} else {
|
||||||
|
this.textContent = 'favorite_border';
|
||||||
|
this.classList.remove('is-favorite');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alert(data.message || 'An error occurred.');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error:', error);
|
||||||
|
alert('An error occurred while favoriting this session.');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<?php require_once __DIR__ . '/partials/footer.php'; ?>
|
||||||
22
vendor/autoload.php
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload.php @generated by Composer
|
||||||
|
|
||||||
|
if (PHP_VERSION_ID < 50600) {
|
||||||
|
if (!headers_sent()) {
|
||||||
|
header('HTTP/1.1 500 Internal Server Error');
|
||||||
|
}
|
||||||
|
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
|
||||||
|
if (!ini_get('display_errors')) {
|
||||||
|
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||||
|
fwrite(STDERR, $err);
|
||||||
|
} elseif (!headers_sent()) {
|
||||||
|
echo $err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new RuntimeException($err);
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once __DIR__ . '/composer/autoload_real.php';
|
||||||
|
|
||||||
|
return ComposerAutoloaderInit753ddc06a8b4769fbc63db74f09ba6ca::getLoader();
|
||||||
579
vendor/composer/ClassLoader.php
vendored
Normal file
@ -0,0 +1,579 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Composer.
|
||||||
|
*
|
||||||
|
* (c) Nils Adermann <naderman@naderman.de>
|
||||||
|
* Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Composer\Autoload;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
|
||||||
|
*
|
||||||
|
* $loader = new \Composer\Autoload\ClassLoader();
|
||||||
|
*
|
||||||
|
* // register classes with namespaces
|
||||||
|
* $loader->add('Symfony\Component', __DIR__.'/component');
|
||||||
|
* $loader->add('Symfony', __DIR__.'/framework');
|
||||||
|
*
|
||||||
|
* // activate the autoloader
|
||||||
|
* $loader->register();
|
||||||
|
*
|
||||||
|
* // to enable searching the include path (eg. for PEAR packages)
|
||||||
|
* $loader->setUseIncludePath(true);
|
||||||
|
*
|
||||||
|
* In this example, if you try to use a class in the Symfony\Component
|
||||||
|
* namespace or one of its children (Symfony\Component\Console for instance),
|
||||||
|
* the autoloader will first look for the class under the component/
|
||||||
|
* directory, and it will then fallback to the framework/ directory if not
|
||||||
|
* found before giving up.
|
||||||
|
*
|
||||||
|
* This class is loosely based on the Symfony UniversalClassLoader.
|
||||||
|
*
|
||||||
|
* @author Fabien Potencier <fabien@symfony.com>
|
||||||
|
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
* @see https://www.php-fig.org/psr/psr-0/
|
||||||
|
* @see https://www.php-fig.org/psr/psr-4/
|
||||||
|
*/
|
||||||
|
class ClassLoader
|
||||||
|
{
|
||||||
|
/** @var \Closure(string):void */
|
||||||
|
private static $includeFile;
|
||||||
|
|
||||||
|
/** @var string|null */
|
||||||
|
private $vendorDir;
|
||||||
|
|
||||||
|
// PSR-4
|
||||||
|
/**
|
||||||
|
* @var array<string, array<string, int>>
|
||||||
|
*/
|
||||||
|
private $prefixLengthsPsr4 = array();
|
||||||
|
/**
|
||||||
|
* @var array<string, list<string>>
|
||||||
|
*/
|
||||||
|
private $prefixDirsPsr4 = array();
|
||||||
|
/**
|
||||||
|
* @var list<string>
|
||||||
|
*/
|
||||||
|
private $fallbackDirsPsr4 = array();
|
||||||
|
|
||||||
|
// PSR-0
|
||||||
|
/**
|
||||||
|
* List of PSR-0 prefixes
|
||||||
|
*
|
||||||
|
* Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
|
||||||
|
*
|
||||||
|
* @var array<string, array<string, list<string>>>
|
||||||
|
*/
|
||||||
|
private $prefixesPsr0 = array();
|
||||||
|
/**
|
||||||
|
* @var list<string>
|
||||||
|
*/
|
||||||
|
private $fallbackDirsPsr0 = array();
|
||||||
|
|
||||||
|
/** @var bool */
|
||||||
|
private $useIncludePath = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array<string, string>
|
||||||
|
*/
|
||||||
|
private $classMap = array();
|
||||||
|
|
||||||
|
/** @var bool */
|
||||||
|
private $classMapAuthoritative = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array<string, bool>
|
||||||
|
*/
|
||||||
|
private $missingClasses = array();
|
||||||
|
|
||||||
|
/** @var string|null */
|
||||||
|
private $apcuPrefix;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array<string, self>
|
||||||
|
*/
|
||||||
|
private static $registeredLoaders = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string|null $vendorDir
|
||||||
|
*/
|
||||||
|
public function __construct($vendorDir = null)
|
||||||
|
{
|
||||||
|
$this->vendorDir = $vendorDir;
|
||||||
|
self::initializeIncludeClosure();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, list<string>>
|
||||||
|
*/
|
||||||
|
public function getPrefixes()
|
||||||
|
{
|
||||||
|
if (!empty($this->prefixesPsr0)) {
|
||||||
|
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
|
||||||
|
}
|
||||||
|
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, list<string>>
|
||||||
|
*/
|
||||||
|
public function getPrefixesPsr4()
|
||||||
|
{
|
||||||
|
return $this->prefixDirsPsr4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return list<string>
|
||||||
|
*/
|
||||||
|
public function getFallbackDirs()
|
||||||
|
{
|
||||||
|
return $this->fallbackDirsPsr0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return list<string>
|
||||||
|
*/
|
||||||
|
public function getFallbackDirsPsr4()
|
||||||
|
{
|
||||||
|
return $this->fallbackDirsPsr4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, string> Array of classname => path
|
||||||
|
*/
|
||||||
|
public function getClassMap()
|
||||||
|
{
|
||||||
|
return $this->classMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string, string> $classMap Class to filename map
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function addClassMap(array $classMap)
|
||||||
|
{
|
||||||
|
if ($this->classMap) {
|
||||||
|
$this->classMap = array_merge($this->classMap, $classMap);
|
||||||
|
} else {
|
||||||
|
$this->classMap = $classMap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-0 directories for a given prefix, either
|
||||||
|
* appending or prepending to the ones previously set for this prefix.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix
|
||||||
|
* @param list<string>|string $paths The PSR-0 root directories
|
||||||
|
* @param bool $prepend Whether to prepend the directories
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function add($prefix, $paths, $prepend = false)
|
||||||
|
{
|
||||||
|
$paths = (array) $paths;
|
||||||
|
if (!$prefix) {
|
||||||
|
if ($prepend) {
|
||||||
|
$this->fallbackDirsPsr0 = array_merge(
|
||||||
|
$paths,
|
||||||
|
$this->fallbackDirsPsr0
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->fallbackDirsPsr0 = array_merge(
|
||||||
|
$this->fallbackDirsPsr0,
|
||||||
|
$paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$first = $prefix[0];
|
||||||
|
if (!isset($this->prefixesPsr0[$first][$prefix])) {
|
||||||
|
$this->prefixesPsr0[$first][$prefix] = $paths;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ($prepend) {
|
||||||
|
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||||
|
$paths,
|
||||||
|
$this->prefixesPsr0[$first][$prefix]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||||
|
$this->prefixesPsr0[$first][$prefix],
|
||||||
|
$paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-4 directories for a given namespace, either
|
||||||
|
* appending or prepending to the ones previously set for this namespace.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||||
|
* @param list<string>|string $paths The PSR-4 base directories
|
||||||
|
* @param bool $prepend Whether to prepend the directories
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function addPsr4($prefix, $paths, $prepend = false)
|
||||||
|
{
|
||||||
|
$paths = (array) $paths;
|
||||||
|
if (!$prefix) {
|
||||||
|
// Register directories for the root namespace.
|
||||||
|
if ($prepend) {
|
||||||
|
$this->fallbackDirsPsr4 = array_merge(
|
||||||
|
$paths,
|
||||||
|
$this->fallbackDirsPsr4
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$this->fallbackDirsPsr4 = array_merge(
|
||||||
|
$this->fallbackDirsPsr4,
|
||||||
|
$paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
|
||||||
|
// Register directories for a new namespace.
|
||||||
|
$length = strlen($prefix);
|
||||||
|
if ('\\' !== $prefix[$length - 1]) {
|
||||||
|
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||||
|
}
|
||||||
|
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||||
|
$this->prefixDirsPsr4[$prefix] = $paths;
|
||||||
|
} elseif ($prepend) {
|
||||||
|
// Prepend directories for an already registered namespace.
|
||||||
|
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||||
|
$paths,
|
||||||
|
$this->prefixDirsPsr4[$prefix]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Append directories for an already registered namespace.
|
||||||
|
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||||
|
$this->prefixDirsPsr4[$prefix],
|
||||||
|
$paths
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-0 directories for a given prefix,
|
||||||
|
* replacing any others previously set for this prefix.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix
|
||||||
|
* @param list<string>|string $paths The PSR-0 base directories
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function set($prefix, $paths)
|
||||||
|
{
|
||||||
|
if (!$prefix) {
|
||||||
|
$this->fallbackDirsPsr0 = (array) $paths;
|
||||||
|
} else {
|
||||||
|
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a set of PSR-4 directories for a given namespace,
|
||||||
|
* replacing any others previously set for this namespace.
|
||||||
|
*
|
||||||
|
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||||
|
* @param list<string>|string $paths The PSR-4 base directories
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setPsr4($prefix, $paths)
|
||||||
|
{
|
||||||
|
if (!$prefix) {
|
||||||
|
$this->fallbackDirsPsr4 = (array) $paths;
|
||||||
|
} else {
|
||||||
|
$length = strlen($prefix);
|
||||||
|
if ('\\' !== $prefix[$length - 1]) {
|
||||||
|
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||||
|
}
|
||||||
|
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||||
|
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turns on searching the include path for class files.
|
||||||
|
*
|
||||||
|
* @param bool $useIncludePath
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setUseIncludePath($useIncludePath)
|
||||||
|
{
|
||||||
|
$this->useIncludePath = $useIncludePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can be used to check if the autoloader uses the include path to check
|
||||||
|
* for classes.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function getUseIncludePath()
|
||||||
|
{
|
||||||
|
return $this->useIncludePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turns off searching the prefix and fallback directories for classes
|
||||||
|
* that have not been registered with the class map.
|
||||||
|
*
|
||||||
|
* @param bool $classMapAuthoritative
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setClassMapAuthoritative($classMapAuthoritative)
|
||||||
|
{
|
||||||
|
$this->classMapAuthoritative = $classMapAuthoritative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should class lookup fail if not found in the current class map?
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isClassMapAuthoritative()
|
||||||
|
{
|
||||||
|
return $this->classMapAuthoritative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
|
||||||
|
*
|
||||||
|
* @param string|null $apcuPrefix
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setApcuPrefix($apcuPrefix)
|
||||||
|
{
|
||||||
|
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The APCu prefix in use, or null if APCu caching is not enabled.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getApcuPrefix()
|
||||||
|
{
|
||||||
|
return $this->apcuPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers this instance as an autoloader.
|
||||||
|
*
|
||||||
|
* @param bool $prepend Whether to prepend the autoloader or not
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function register($prepend = false)
|
||||||
|
{
|
||||||
|
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
|
||||||
|
|
||||||
|
if (null === $this->vendorDir) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($prepend) {
|
||||||
|
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
|
||||||
|
} else {
|
||||||
|
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||||
|
self::$registeredLoaders[$this->vendorDir] = $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregisters this instance as an autoloader.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function unregister()
|
||||||
|
{
|
||||||
|
spl_autoload_unregister(array($this, 'loadClass'));
|
||||||
|
|
||||||
|
if (null !== $this->vendorDir) {
|
||||||
|
unset(self::$registeredLoaders[$this->vendorDir]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the given class or interface.
|
||||||
|
*
|
||||||
|
* @param string $class The name of the class
|
||||||
|
* @return true|null True if loaded, null otherwise
|
||||||
|
*/
|
||||||
|
public function loadClass($class)
|
||||||
|
{
|
||||||
|
if ($file = $this->findFile($class)) {
|
||||||
|
$includeFile = self::$includeFile;
|
||||||
|
$includeFile($file);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the path to the file where the class is defined.
|
||||||
|
*
|
||||||
|
* @param string $class The name of the class
|
||||||
|
*
|
||||||
|
* @return string|false The path if found, false otherwise
|
||||||
|
*/
|
||||||
|
public function findFile($class)
|
||||||
|
{
|
||||||
|
// class map lookup
|
||||||
|
if (isset($this->classMap[$class])) {
|
||||||
|
return $this->classMap[$class];
|
||||||
|
}
|
||||||
|
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (null !== $this->apcuPrefix) {
|
||||||
|
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
|
||||||
|
if ($hit) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$file = $this->findFileWithExtension($class, '.php');
|
||||||
|
|
||||||
|
// Search for Hack files if we are running on HHVM
|
||||||
|
if (false === $file && defined('HHVM_VERSION')) {
|
||||||
|
$file = $this->findFileWithExtension($class, '.hh');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $this->apcuPrefix) {
|
||||||
|
apcu_add($this->apcuPrefix.$class, $file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false === $file) {
|
||||||
|
// Remember that this class does not exist.
|
||||||
|
$this->missingClasses[$class] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the currently registered loaders keyed by their corresponding vendor directories.
|
||||||
|
*
|
||||||
|
* @return array<string, self>
|
||||||
|
*/
|
||||||
|
public static function getRegisteredLoaders()
|
||||||
|
{
|
||||||
|
return self::$registeredLoaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $class
|
||||||
|
* @param string $ext
|
||||||
|
* @return string|false
|
||||||
|
*/
|
||||||
|
private function findFileWithExtension($class, $ext)
|
||||||
|
{
|
||||||
|
// PSR-4 lookup
|
||||||
|
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
|
||||||
|
|
||||||
|
$first = $class[0];
|
||||||
|
if (isset($this->prefixLengthsPsr4[$first])) {
|
||||||
|
$subPath = $class;
|
||||||
|
while (false !== $lastPos = strrpos($subPath, '\\')) {
|
||||||
|
$subPath = substr($subPath, 0, $lastPos);
|
||||||
|
$search = $subPath . '\\';
|
||||||
|
if (isset($this->prefixDirsPsr4[$search])) {
|
||||||
|
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
|
||||||
|
foreach ($this->prefixDirsPsr4[$search] as $dir) {
|
||||||
|
if (file_exists($file = $dir . $pathEnd)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-4 fallback dirs
|
||||||
|
foreach ($this->fallbackDirsPsr4 as $dir) {
|
||||||
|
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-0 lookup
|
||||||
|
if (false !== $pos = strrpos($class, '\\')) {
|
||||||
|
// namespaced class name
|
||||||
|
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
|
||||||
|
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
|
||||||
|
} else {
|
||||||
|
// PEAR-like class name
|
||||||
|
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($this->prefixesPsr0[$first])) {
|
||||||
|
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
|
||||||
|
if (0 === strpos($class, $prefix)) {
|
||||||
|
foreach ($dirs as $dir) {
|
||||||
|
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-0 fallback dirs
|
||||||
|
foreach ($this->fallbackDirsPsr0 as $dir) {
|
||||||
|
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PSR-0 include paths.
|
||||||
|
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
|
||||||
|
return $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private static function initializeIncludeClosure()
|
||||||
|
{
|
||||||
|
if (self::$includeFile !== null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scope isolated include.
|
||||||
|
*
|
||||||
|
* Prevents access to $this/self from included files.
|
||||||
|
*
|
||||||
|
* @param string $file
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
self::$includeFile = \Closure::bind(static function($file) {
|
||||||
|
include $file;
|
||||||
|
}, null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
396
vendor/composer/InstalledVersions.php
vendored
Normal file
@ -0,0 +1,396 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Composer.
|
||||||
|
*
|
||||||
|
* (c) Nils Adermann <naderman@naderman.de>
|
||||||
|
* Jordi Boggiano <j.boggiano@seld.be>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Composer;
|
||||||
|
|
||||||
|
use Composer\Autoload\ClassLoader;
|
||||||
|
use Composer\Semver\VersionParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is copied in every Composer installed project and available to all
|
||||||
|
*
|
||||||
|
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
|
||||||
|
*
|
||||||
|
* To require its presence, you can require `composer-runtime-api ^2.0`
|
||||||
|
*
|
||||||
|
* @final
|
||||||
|
*/
|
||||||
|
class InstalledVersions
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
private static $selfDir = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var mixed[]|null
|
||||||
|
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
|
||||||
|
*/
|
||||||
|
private static $installed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private static $installedIsLocalDir;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool|null
|
||||||
|
*/
|
||||||
|
private static $canGetVendors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array[]
|
||||||
|
* @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||||
|
*/
|
||||||
|
private static $installedByVendor = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all package names which are present, either by being installed, replaced or provided
|
||||||
|
*
|
||||||
|
* @return string[]
|
||||||
|
* @psalm-return list<string>
|
||||||
|
*/
|
||||||
|
public static function getInstalledPackages()
|
||||||
|
{
|
||||||
|
$packages = array();
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
$packages[] = array_keys($installed['versions']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (1 === \count($packages)) {
|
||||||
|
return $packages[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all package names with a specific type e.g. 'library'
|
||||||
|
*
|
||||||
|
* @param string $type
|
||||||
|
* @return string[]
|
||||||
|
* @psalm-return list<string>
|
||||||
|
*/
|
||||||
|
public static function getInstalledPackagesByType($type)
|
||||||
|
{
|
||||||
|
$packagesByType = array();
|
||||||
|
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
foreach ($installed['versions'] as $name => $package) {
|
||||||
|
if (isset($package['type']) && $package['type'] === $type) {
|
||||||
|
$packagesByType[] = $name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $packagesByType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the given package is installed
|
||||||
|
*
|
||||||
|
* This also returns true if the package name is provided or replaced by another package
|
||||||
|
*
|
||||||
|
* @param string $packageName
|
||||||
|
* @param bool $includeDevRequirements
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function isInstalled($packageName, $includeDevRequirements = true)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (isset($installed['versions'][$packageName])) {
|
||||||
|
return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the given package satisfies a version constraint
|
||||||
|
*
|
||||||
|
* e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
|
||||||
|
*
|
||||||
|
* Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
|
||||||
|
*
|
||||||
|
* @param VersionParser $parser Install composer/semver to have access to this class and functionality
|
||||||
|
* @param string $packageName
|
||||||
|
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function satisfies(VersionParser $parser, $packageName, $constraint)
|
||||||
|
{
|
||||||
|
$constraint = $parser->parseConstraints((string) $constraint);
|
||||||
|
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
|
||||||
|
|
||||||
|
return $provided->matches($constraint);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a version constraint representing all the range(s) which are installed for a given package
|
||||||
|
*
|
||||||
|
* It is easier to use this via isInstalled() with the $constraint argument if you need to check
|
||||||
|
* whether a given version of a package is installed, and not just whether it exists
|
||||||
|
*
|
||||||
|
* @param string $packageName
|
||||||
|
* @return string Version constraint usable with composer/semver
|
||||||
|
*/
|
||||||
|
public static function getVersionRanges($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ranges = array();
|
||||||
|
if (isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||||
|
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
|
||||||
|
}
|
||||||
|
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
|
||||||
|
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
|
||||||
|
}
|
||||||
|
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
|
||||||
|
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
|
||||||
|
}
|
||||||
|
if (array_key_exists('provided', $installed['versions'][$packageName])) {
|
||||||
|
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode(' || ', $ranges);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $packageName
|
||||||
|
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
||||||
|
*/
|
||||||
|
public static function getVersion($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($installed['versions'][$packageName]['version'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $installed['versions'][$packageName]['version'];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $packageName
|
||||||
|
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
|
||||||
|
*/
|
||||||
|
public static function getPrettyVersion($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $installed['versions'][$packageName]['pretty_version'];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $packageName
|
||||||
|
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
|
||||||
|
*/
|
||||||
|
public static function getReference($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($installed['versions'][$packageName]['reference'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $installed['versions'][$packageName]['reference'];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $packageName
|
||||||
|
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
|
||||||
|
*/
|
||||||
|
public static function getInstallPath($packageName)
|
||||||
|
{
|
||||||
|
foreach (self::getInstalled() as $installed) {
|
||||||
|
if (!isset($installed['versions'][$packageName])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
* @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
|
||||||
|
*/
|
||||||
|
public static function getRootPackage()
|
||||||
|
{
|
||||||
|
$installed = self::getInstalled();
|
||||||
|
|
||||||
|
return $installed[0]['root'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the raw installed.php data for custom implementations
|
||||||
|
*
|
||||||
|
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
|
||||||
|
* @return array[]
|
||||||
|
* @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
|
||||||
|
*/
|
||||||
|
public static function getRawData()
|
||||||
|
{
|
||||||
|
@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
|
||||||
|
|
||||||
|
if (null === self::$installed) {
|
||||||
|
// only require the installed.php file if this file is loaded from its dumped location,
|
||||||
|
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||||
|
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||||
|
self::$installed = include __DIR__ . '/installed.php';
|
||||||
|
} else {
|
||||||
|
self::$installed = array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$installed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the raw data of all installed.php which are currently loaded for custom implementations
|
||||||
|
*
|
||||||
|
* @return array[]
|
||||||
|
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||||
|
*/
|
||||||
|
public static function getAllRawData()
|
||||||
|
{
|
||||||
|
return self::getInstalled();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lets you reload the static array from another file
|
||||||
|
*
|
||||||
|
* This is only useful for complex integrations in which a project needs to use
|
||||||
|
* this class but then also needs to execute another project's autoloader in process,
|
||||||
|
* and wants to ensure both projects have access to their version of installed.php.
|
||||||
|
*
|
||||||
|
* A typical case would be PHPUnit, where it would need to make sure it reads all
|
||||||
|
* the data it needs from this class, then call reload() with
|
||||||
|
* `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
|
||||||
|
* the project in which it runs can then also use this class safely, without
|
||||||
|
* interference between PHPUnit's dependencies and the project's dependencies.
|
||||||
|
*
|
||||||
|
* @param array[] $data A vendor/composer/installed.php data set
|
||||||
|
* @return void
|
||||||
|
*
|
||||||
|
* @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
|
||||||
|
*/
|
||||||
|
public static function reload($data)
|
||||||
|
{
|
||||||
|
self::$installed = $data;
|
||||||
|
self::$installedByVendor = array();
|
||||||
|
|
||||||
|
// when using reload, we disable the duplicate protection to ensure that self::$installed data is
|
||||||
|
// always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
|
||||||
|
// so we have to assume it does not, and that may result in duplicate data being returned when listing
|
||||||
|
// all installed packages for example
|
||||||
|
self::$installedIsLocalDir = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private static function getSelfDir()
|
||||||
|
{
|
||||||
|
if (self::$selfDir === null) {
|
||||||
|
self::$selfDir = strtr(__DIR__, '\\', '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$selfDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array[]
|
||||||
|
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
|
||||||
|
*/
|
||||||
|
private static function getInstalled()
|
||||||
|
{
|
||||||
|
if (null === self::$canGetVendors) {
|
||||||
|
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
|
||||||
|
}
|
||||||
|
|
||||||
|
$installed = array();
|
||||||
|
$copiedLocalDir = false;
|
||||||
|
|
||||||
|
if (self::$canGetVendors) {
|
||||||
|
$selfDir = self::getSelfDir();
|
||||||
|
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
|
||||||
|
$vendorDir = strtr($vendorDir, '\\', '/');
|
||||||
|
if (isset(self::$installedByVendor[$vendorDir])) {
|
||||||
|
$installed[] = self::$installedByVendor[$vendorDir];
|
||||||
|
} elseif (is_file($vendorDir.'/composer/installed.php')) {
|
||||||
|
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
|
||||||
|
$required = require $vendorDir.'/composer/installed.php';
|
||||||
|
self::$installedByVendor[$vendorDir] = $required;
|
||||||
|
$installed[] = $required;
|
||||||
|
if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
|
||||||
|
self::$installed = $required;
|
||||||
|
self::$installedIsLocalDir = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
|
||||||
|
$copiedLocalDir = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === self::$installed) {
|
||||||
|
// only require the installed.php file if this file is loaded from its dumped location,
|
||||||
|
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
|
||||||
|
if (substr(__DIR__, -8, 1) !== 'C') {
|
||||||
|
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
|
||||||
|
$required = require __DIR__ . '/installed.php';
|
||||||
|
self::$installed = $required;
|
||||||
|
} else {
|
||||||
|
self::$installed = array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self::$installed !== array() && !$copiedLocalDir) {
|
||||||
|
$installed[] = self::$installed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $installed;
|
||||||
|
}
|
||||||
|
}
|
||||||
21
vendor/composer/LICENSE
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
|
||||||
|
Copyright (c) Nils Adermann, Jordi Boggiano
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is furnished
|
||||||
|
to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
11
vendor/composer/autoload_classmap.php
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_classmap.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(__DIR__);
|
||||||
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
|
||||||
|
'Dompdf\\Cpdf' => $vendorDir . '/dompdf/dompdf/lib/Cpdf.php',
|
||||||
|
);
|
||||||
9
vendor/composer/autoload_namespaces.php
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_namespaces.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(__DIR__);
|
||||||
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
);
|
||||||
15
vendor/composer/autoload_psr4.php
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_psr4.php @generated by Composer
|
||||||
|
|
||||||
|
$vendorDir = dirname(__DIR__);
|
||||||
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'Svg\\' => array($vendorDir . '/dompdf/php-svg-lib/src/Svg'),
|
||||||
|
'Sabberworm\\CSS\\' => array($vendorDir . '/sabberworm/php-css-parser/src'),
|
||||||
|
'Masterminds\\' => array($vendorDir . '/masterminds/html5/src'),
|
||||||
|
'Hybridauth\\' => array($vendorDir . '/hybridauth/hybridauth/src'),
|
||||||
|
'FontLib\\' => array($vendorDir . '/dompdf/php-font-lib/src/FontLib'),
|
||||||
|
'Dompdf\\' => array($vendorDir . '/dompdf/dompdf/src'),
|
||||||
|
);
|
||||||
38
vendor/composer/autoload_real.php
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_real.php @generated by Composer
|
||||||
|
|
||||||
|
class ComposerAutoloaderInit753ddc06a8b4769fbc63db74f09ba6ca
|
||||||
|
{
|
||||||
|
private static $loader;
|
||||||
|
|
||||||
|
public static function loadClassLoader($class)
|
||||||
|
{
|
||||||
|
if ('Composer\Autoload\ClassLoader' === $class) {
|
||||||
|
require __DIR__ . '/ClassLoader.php';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Composer\Autoload\ClassLoader
|
||||||
|
*/
|
||||||
|
public static function getLoader()
|
||||||
|
{
|
||||||
|
if (null !== self::$loader) {
|
||||||
|
return self::$loader;
|
||||||
|
}
|
||||||
|
|
||||||
|
require __DIR__ . '/platform_check.php';
|
||||||
|
|
||||||
|
spl_autoload_register(array('ComposerAutoloaderInit753ddc06a8b4769fbc63db74f09ba6ca', 'loadClassLoader'), true, true);
|
||||||
|
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
|
||||||
|
spl_autoload_unregister(array('ComposerAutoloaderInit753ddc06a8b4769fbc63db74f09ba6ca', 'loadClassLoader'));
|
||||||
|
|
||||||
|
require __DIR__ . '/autoload_static.php';
|
||||||
|
call_user_func(\Composer\Autoload\ComposerStaticInit753ddc06a8b4769fbc63db74f09ba6ca::getInitializer($loader));
|
||||||
|
|
||||||
|
$loader->register(true);
|
||||||
|
|
||||||
|
return $loader;
|
||||||
|
}
|
||||||
|
}
|
||||||
74
vendor/composer/autoload_static.php
vendored
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// autoload_static.php @generated by Composer
|
||||||
|
|
||||||
|
namespace Composer\Autoload;
|
||||||
|
|
||||||
|
class ComposerStaticInit753ddc06a8b4769fbc63db74f09ba6ca
|
||||||
|
{
|
||||||
|
public static $prefixLengthsPsr4 = array (
|
||||||
|
'S' =>
|
||||||
|
array (
|
||||||
|
'Svg\\' => 4,
|
||||||
|
'Sabberworm\\CSS\\' => 15,
|
||||||
|
),
|
||||||
|
'M' =>
|
||||||
|
array (
|
||||||
|
'Masterminds\\' => 12,
|
||||||
|
),
|
||||||
|
'H' =>
|
||||||
|
array (
|
||||||
|
'Hybridauth\\' => 11,
|
||||||
|
),
|
||||||
|
'F' =>
|
||||||
|
array (
|
||||||
|
'FontLib\\' => 8,
|
||||||
|
),
|
||||||
|
'D' =>
|
||||||
|
array (
|
||||||
|
'Dompdf\\' => 7,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
public static $prefixDirsPsr4 = array (
|
||||||
|
'Svg\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/dompdf/php-svg-lib/src/Svg',
|
||||||
|
),
|
||||||
|
'Sabberworm\\CSS\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/sabberworm/php-css-parser/src',
|
||||||
|
),
|
||||||
|
'Masterminds\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/masterminds/html5/src',
|
||||||
|
),
|
||||||
|
'Hybridauth\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/hybridauth/hybridauth/src',
|
||||||
|
),
|
||||||
|
'FontLib\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/dompdf/php-font-lib/src/FontLib',
|
||||||
|
),
|
||||||
|
'Dompdf\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/dompdf/dompdf/src',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
public static $classMap = array (
|
||||||
|
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
|
||||||
|
'Dompdf\\Cpdf' => __DIR__ . '/..' . '/dompdf/dompdf/lib/Cpdf.php',
|
||||||
|
);
|
||||||
|
|
||||||
|
public static function getInitializer(ClassLoader $loader)
|
||||||
|
{
|
||||||
|
return \Closure::bind(function () use ($loader) {
|
||||||
|
$loader->prefixLengthsPsr4 = ComposerStaticInit753ddc06a8b4769fbc63db74f09ba6ca::$prefixLengthsPsr4;
|
||||||
|
$loader->prefixDirsPsr4 = ComposerStaticInit753ddc06a8b4769fbc63db74f09ba6ca::$prefixDirsPsr4;
|
||||||
|
$loader->classMap = ComposerStaticInit753ddc06a8b4769fbc63db74f09ba6ca::$classMap;
|
||||||
|
|
||||||
|
}, null, ClassLoader::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
374
vendor/composer/installed.json
vendored
Normal file
@ -0,0 +1,374 @@
|
|||||||
|
{
|
||||||
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "dompdf/dompdf",
|
||||||
|
"version": "v3.1.4",
|
||||||
|
"version_normalized": "3.1.4.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/dompdf/dompdf.git",
|
||||||
|
"reference": "db712c90c5b9868df3600e64e68da62e78a34623"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/dompdf/dompdf/zipball/db712c90c5b9868df3600e64e68da62e78a34623",
|
||||||
|
"reference": "db712c90c5b9868df3600e64e68da62e78a34623",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"dompdf/php-font-lib": "^1.0.0",
|
||||||
|
"dompdf/php-svg-lib": "^1.0.0",
|
||||||
|
"ext-dom": "*",
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"masterminds/html5": "^2.0",
|
||||||
|
"php": "^7.1 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"ext-gd": "*",
|
||||||
|
"ext-json": "*",
|
||||||
|
"ext-zip": "*",
|
||||||
|
"mockery/mockery": "^1.3",
|
||||||
|
"phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11",
|
||||||
|
"squizlabs/php_codesniffer": "^3.5",
|
||||||
|
"symfony/process": "^4.4 || ^5.4 || ^6.2 || ^7.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-gd": "Needed to process images",
|
||||||
|
"ext-gmagick": "Improves image processing performance",
|
||||||
|
"ext-imagick": "Improves image processing performance",
|
||||||
|
"ext-zlib": "Needed for pdf stream compression"
|
||||||
|
},
|
||||||
|
"time": "2025-10-29T12:43:30+00:00",
|
||||||
|
"type": "library",
|
||||||
|
"installation-source": "dist",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Dompdf\\": "src/"
|
||||||
|
},
|
||||||
|
"classmap": [
|
||||||
|
"lib/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"LGPL-2.1"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "The Dompdf Community",
|
||||||
|
"homepage": "https://github.com/dompdf/dompdf/blob/master/AUTHORS.md"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter",
|
||||||
|
"homepage": "https://github.com/dompdf/dompdf",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/dompdf/dompdf/issues",
|
||||||
|
"source": "https://github.com/dompdf/dompdf/tree/v3.1.4"
|
||||||
|
},
|
||||||
|
"install-path": "../dompdf/dompdf"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "dompdf/php-font-lib",
|
||||||
|
"version": "1.0.1",
|
||||||
|
"version_normalized": "1.0.1.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/dompdf/php-font-lib.git",
|
||||||
|
"reference": "6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/dompdf/php-font-lib/zipball/6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d",
|
||||||
|
"reference": "6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"php": "^7.1 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"symfony/phpunit-bridge": "^3 || ^4 || ^5 || ^6"
|
||||||
|
},
|
||||||
|
"time": "2024-12-02T14:37:59+00:00",
|
||||||
|
"type": "library",
|
||||||
|
"installation-source": "dist",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"FontLib\\": "src/FontLib"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"LGPL-2.1-or-later"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "The FontLib Community",
|
||||||
|
"homepage": "https://github.com/dompdf/php-font-lib/blob/master/AUTHORS.md"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A library to read, parse, export and make subsets of different types of font files.",
|
||||||
|
"homepage": "https://github.com/dompdf/php-font-lib",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/dompdf/php-font-lib/issues",
|
||||||
|
"source": "https://github.com/dompdf/php-font-lib/tree/1.0.1"
|
||||||
|
},
|
||||||
|
"install-path": "../dompdf/php-font-lib"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "dompdf/php-svg-lib",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"version_normalized": "1.0.0.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/dompdf/php-svg-lib.git",
|
||||||
|
"reference": "eb045e518185298eb6ff8d80d0d0c6b17aecd9af"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/eb045e518185298eb6ff8d80d0d0c6b17aecd9af",
|
||||||
|
"reference": "eb045e518185298eb6ff8d80d0d0c6b17aecd9af",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"php": "^7.1 || ^8.0",
|
||||||
|
"sabberworm/php-css-parser": "^8.4"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5"
|
||||||
|
},
|
||||||
|
"time": "2024-04-29T13:26:35+00:00",
|
||||||
|
"type": "library",
|
||||||
|
"installation-source": "dist",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Svg\\": "src/Svg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"LGPL-3.0-or-later"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "The SvgLib Community",
|
||||||
|
"homepage": "https://github.com/dompdf/php-svg-lib/blob/master/AUTHORS.md"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "A library to read, parse and export to PDF SVG files.",
|
||||||
|
"homepage": "https://github.com/dompdf/php-svg-lib",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/dompdf/php-svg-lib/issues",
|
||||||
|
"source": "https://github.com/dompdf/php-svg-lib/tree/1.0.0"
|
||||||
|
},
|
||||||
|
"install-path": "../dompdf/php-svg-lib"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hybridauth/hybridauth",
|
||||||
|
"version": "v3.12.2",
|
||||||
|
"version_normalized": "3.12.2.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/hybridauth/hybridauth.git",
|
||||||
|
"reference": "c6184bf92404394e918353a0ea0d35a97ac3b0fe"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/hybridauth/hybridauth/zipball/c6184bf92404394e918353a0ea0d35a97ac3b0fe",
|
||||||
|
"reference": "c6184bf92404394e918353a0ea0d35a97ac3b0fe",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^5.4 || ^7.0 || ^8.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"ext-curl": "*",
|
||||||
|
"phpunit/phpunit": "^4.8.35 || ^6.5 || ^8.0 || ^12.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"firebase/php-jwt": "Needed to support Apple provider",
|
||||||
|
"phpseclib/phpseclib": "Needed to support Apple provider"
|
||||||
|
},
|
||||||
|
"time": "2025-06-18T11:58:48+00:00",
|
||||||
|
"type": "library",
|
||||||
|
"installation-source": "dist",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Hybridauth\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Miled",
|
||||||
|
"email": "hybridauth@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "PHP Social Authentication Library",
|
||||||
|
"homepage": "https://hybridauth.github.io",
|
||||||
|
"keywords": [
|
||||||
|
"Authentication",
|
||||||
|
"OpenId",
|
||||||
|
"api",
|
||||||
|
"apple",
|
||||||
|
"authorization",
|
||||||
|
"facebook",
|
||||||
|
"google",
|
||||||
|
"oauth",
|
||||||
|
"social",
|
||||||
|
"twitter"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"gitter": "https://gitter.im/hybridauth/hybridauth",
|
||||||
|
"issues": "https://github.com/hybridauth/hybridauth/issues",
|
||||||
|
"source": "https://github.com/hybridauth/hybridauth/tree/v3.12.2"
|
||||||
|
},
|
||||||
|
"install-path": "../hybridauth/hybridauth"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "masterminds/html5",
|
||||||
|
"version": "2.10.0",
|
||||||
|
"version_normalized": "2.10.0.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/Masterminds/html5-php.git",
|
||||||
|
"reference": "fcf91eb64359852f00d921887b219479b4f21251"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/Masterminds/html5-php/zipball/fcf91eb64359852f00d921887b219479b4f21251",
|
||||||
|
"reference": "fcf91eb64359852f00d921887b219479b4f21251",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-dom": "*",
|
||||||
|
"php": ">=5.3.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9"
|
||||||
|
},
|
||||||
|
"time": "2025-07-25T09:04:22+00:00",
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "2.7-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"installation-source": "dist",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Masterminds\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Matt Butcher",
|
||||||
|
"email": "technosophos@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Matt Farina",
|
||||||
|
"email": "matt@mattfarina.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Asmir Mustafic",
|
||||||
|
"email": "goetas@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "An HTML5 parser and serializer.",
|
||||||
|
"homepage": "http://masterminds.github.io/html5-php",
|
||||||
|
"keywords": [
|
||||||
|
"HTML5",
|
||||||
|
"dom",
|
||||||
|
"html",
|
||||||
|
"parser",
|
||||||
|
"querypath",
|
||||||
|
"serializer",
|
||||||
|
"xml"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/Masterminds/html5-php/issues",
|
||||||
|
"source": "https://github.com/Masterminds/html5-php/tree/2.10.0"
|
||||||
|
},
|
||||||
|
"install-path": "../masterminds/html5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sabberworm/php-css-parser",
|
||||||
|
"version": "v8.9.0",
|
||||||
|
"version_normalized": "8.9.0.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/MyIntervals/PHP-CSS-Parser.git",
|
||||||
|
"reference": "d8e916507b88e389e26d4ab03c904a082aa66bb9"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/d8e916507b88e389e26d4ab03c904a082aa66bb9",
|
||||||
|
"reference": "d8e916507b88e389e26d4ab03c904a082aa66bb9",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-iconv": "*",
|
||||||
|
"php": "^5.6.20 || ^7.0.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "5.7.27 || 6.5.14 || 7.5.20 || 8.5.41",
|
||||||
|
"rawr/cross-data-providers": "^2.0.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-mbstring": "for parsing UTF-8 CSS"
|
||||||
|
},
|
||||||
|
"time": "2025-07-11T13:20:48+00:00",
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-main": "9.0.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"installation-source": "dist",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Sabberworm\\CSS\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Raphael Schweikert"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Oliver Klee",
|
||||||
|
"email": "github@oliverklee.de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jake Hotson",
|
||||||
|
"email": "jake.github@qzdesign.co.uk"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Parser for CSS Files written in PHP",
|
||||||
|
"homepage": "https://www.sabberworm.com/blog/2010/6/10/php-css-parser",
|
||||||
|
"keywords": [
|
||||||
|
"css",
|
||||||
|
"parser",
|
||||||
|
"stylesheet"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/MyIntervals/PHP-CSS-Parser/issues",
|
||||||
|
"source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v8.9.0"
|
||||||
|
},
|
||||||
|
"install-path": "../sabberworm/php-css-parser"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"dev-package-names": []
|
||||||
|
}
|
||||||
77
vendor/composer/installed.php
vendored
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
<?php return array(
|
||||||
|
'root' => array(
|
||||||
|
'name' => 'ubuntu/workspace',
|
||||||
|
'pretty_version' => 'dev-master',
|
||||||
|
'version' => 'dev-master',
|
||||||
|
'reference' => '5a5ac43d6049d681ac1a8b3177bfa180460de6dc',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../../',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev' => true,
|
||||||
|
),
|
||||||
|
'versions' => array(
|
||||||
|
'dompdf/dompdf' => array(
|
||||||
|
'pretty_version' => 'v3.1.4',
|
||||||
|
'version' => '3.1.4.0',
|
||||||
|
'reference' => 'db712c90c5b9868df3600e64e68da62e78a34623',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../dompdf/dompdf',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'dompdf/php-font-lib' => array(
|
||||||
|
'pretty_version' => '1.0.1',
|
||||||
|
'version' => '1.0.1.0',
|
||||||
|
'reference' => '6137b7d4232b7f16c882c75e4ca3991dbcf6fe2d',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../dompdf/php-font-lib',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'dompdf/php-svg-lib' => array(
|
||||||
|
'pretty_version' => '1.0.0',
|
||||||
|
'version' => '1.0.0.0',
|
||||||
|
'reference' => 'eb045e518185298eb6ff8d80d0d0c6b17aecd9af',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../dompdf/php-svg-lib',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'hybridauth/hybridauth' => array(
|
||||||
|
'pretty_version' => 'v3.12.2',
|
||||||
|
'version' => '3.12.2.0',
|
||||||
|
'reference' => 'c6184bf92404394e918353a0ea0d35a97ac3b0fe',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../hybridauth/hybridauth',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'masterminds/html5' => array(
|
||||||
|
'pretty_version' => '2.10.0',
|
||||||
|
'version' => '2.10.0.0',
|
||||||
|
'reference' => 'fcf91eb64359852f00d921887b219479b4f21251',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../masterminds/html5',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'sabberworm/php-css-parser' => array(
|
||||||
|
'pretty_version' => 'v8.9.0',
|
||||||
|
'version' => '8.9.0.0',
|
||||||
|
'reference' => 'd8e916507b88e389e26d4ab03c904a082aa66bb9',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../sabberworm/php-css-parser',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
'ubuntu/workspace' => array(
|
||||||
|
'pretty_version' => 'dev-master',
|
||||||
|
'version' => 'dev-master',
|
||||||
|
'reference' => '5a5ac43d6049d681ac1a8b3177bfa180460de6dc',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../../',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
25
vendor/composer/platform_check.php
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// platform_check.php @generated by Composer
|
||||||
|
|
||||||
|
$issues = array();
|
||||||
|
|
||||||
|
if (!(PHP_VERSION_ID >= 70100)) {
|
||||||
|
$issues[] = 'Your Composer dependencies require a PHP version ">= 7.1.0". You are running ' . PHP_VERSION . '.';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($issues) {
|
||||||
|
if (!headers_sent()) {
|
||||||
|
header('HTTP/1.1 500 Internal Server Error');
|
||||||
|
}
|
||||||
|
if (!ini_get('display_errors')) {
|
||||||
|
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
|
||||||
|
fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
|
||||||
|
} elseif (!headers_sent()) {
|
||||||
|
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new \RuntimeException(
|
||||||
|
'Composer detected issues in your platform: ' . implode(' ', $issues)
|
||||||
|
);
|
||||||
|
}
|
||||||
24
vendor/dompdf/dompdf/AUTHORS.md
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
Dompdf was designed and developed by Benj Carson.
|
||||||
|
|
||||||
|
### Current Team
|
||||||
|
|
||||||
|
* **Brian Sweeney** (maintainer)
|
||||||
|
* **Till Berger**
|
||||||
|
|
||||||
|
### Alumni
|
||||||
|
|
||||||
|
* **Benj Carson** (creator)
|
||||||
|
* **Fabien Ménager**
|
||||||
|
* **Simon Berger**
|
||||||
|
* **Orion Richardson**
|
||||||
|
|
||||||
|
### Contributors
|
||||||
|
* **Gabriel Bull**
|
||||||
|
* **Barry vd. Heuvel**
|
||||||
|
* **Ryan H. Masten**
|
||||||
|
* **Helmut Tischer**
|
||||||
|
* [and many more...](https://github.com/dompdf/dompdf/graphs/contributors)
|
||||||
|
|
||||||
|
### Thanks
|
||||||
|
|
||||||
|
Dompdf would not have been possible without strong community support.
|
||||||
456
vendor/dompdf/dompdf/LICENSE.LGPL
vendored
Normal file
@ -0,0 +1,456 @@
|
|||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
Version 2.1, February 1999
|
||||||
|
|
||||||
|
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||||
|
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
[This is the first released version of the Lesser GPL. It also counts
|
||||||
|
as the successor of the GNU Library Public License, version 2, hence
|
||||||
|
the version number 2.1.]
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
Licenses are intended to guarantee your freedom to share and change
|
||||||
|
free software--to make sure the software is free for all its users.
|
||||||
|
|
||||||
|
This license, the Lesser General Public License, applies to some
|
||||||
|
specially designated software packages--typically libraries--of the
|
||||||
|
Free Software Foundation and other authors who decide to use it. You
|
||||||
|
can use it too, but we suggest you first think carefully about whether
|
||||||
|
this license or the ordinary General Public License is the better
|
||||||
|
strategy to use in any particular case, based on the explanations below.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom of use,
|
||||||
|
not price. Our General Public Licenses are designed to make sure that
|
||||||
|
you have the freedom to distribute copies of free software (and charge
|
||||||
|
for this service if you wish); that you receive source code or can get
|
||||||
|
it if you want it; that you can change the software and use pieces of
|
||||||
|
it in new free programs; and that you are informed that you can do
|
||||||
|
these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
distributors to deny you these rights or to ask you to surrender these
|
||||||
|
rights. These restrictions translate to certain responsibilities for
|
||||||
|
you if you distribute copies of the library or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of the library, whether gratis
|
||||||
|
or for a fee, you must give the recipients all the rights that we gave
|
||||||
|
you. You must make sure that they, too, receive or can get the source
|
||||||
|
code. If you link other code with the library, you must provide
|
||||||
|
complete object files to the recipients, so that they can relink them
|
||||||
|
with the library after making changes to the library and recompiling
|
||||||
|
it. And you must show them these terms so they know their rights.
|
||||||
|
|
||||||
|
We protect your rights with a two-step method: (1) we copyright the
|
||||||
|
library, and (2) we offer you this license, which gives you legal
|
||||||
|
permission to copy, distribute and/or modify the library.
|
||||||
|
|
||||||
|
To protect each distributor, we want to make it very clear that
|
||||||
|
there is no warranty for the free library. Also, if the library is
|
||||||
|
modified by someone else and passed on, the recipients should know
|
||||||
|
that what they have is not the original version, so that the original
|
||||||
|
author's reputation will not be affected by problems that might be
|
||||||
|
introduced by others.
|
||||||
|
|
||||||
|
Finally, software patents pose a constant threat to the existence of
|
||||||
|
any free program. We wish to make sure that a company cannot
|
||||||
|
effectively restrict the users of a free program by obtaining a
|
||||||
|
restrictive license from a patent holder. Therefore, we insist that
|
||||||
|
any patent license obtained for a version of the library must be
|
||||||
|
consistent with the full freedom of use specified in this license.
|
||||||
|
|
||||||
|
Most GNU software, including some libraries, is covered by the
|
||||||
|
ordinary GNU General Public License. This license, the GNU Lesser
|
||||||
|
General Public License, applies to certain designated libraries, and
|
||||||
|
is quite different from the ordinary General Public License. We use
|
||||||
|
this license for certain libraries in order to permit linking those
|
||||||
|
libraries into non-free programs.
|
||||||
|
|
||||||
|
When a program is linked with a library, whether statically or using
|
||||||
|
a shared library, the combination of the two is legally speaking a
|
||||||
|
combined work, a derivative of the original library. The ordinary
|
||||||
|
General Public License therefore permits such linking only if the
|
||||||
|
entire combination fits its criteria of freedom. The Lesser General
|
||||||
|
Public License permits more lax criteria for linking other code with
|
||||||
|
the library.
|
||||||
|
|
||||||
|
We call this license the "Lesser" General Public License because it
|
||||||
|
does Less to protect the user's freedom than the ordinary General
|
||||||
|
Public License. It also provides other free software developers Less
|
||||||
|
of an advantage over competing non-free programs. These disadvantages
|
||||||
|
are the reason we use the ordinary General Public License for many
|
||||||
|
libraries. However, the Lesser license provides advantages in certain
|
||||||
|
special circumstances.
|
||||||
|
|
||||||
|
For example, on rare occasions, there may be a special need to
|
||||||
|
encourage the widest possible use of a certain library, so that it becomes
|
||||||
|
a de-facto standard. To achieve this, non-free programs must be
|
||||||
|
allowed to use the library. A more frequent case is that a free
|
||||||
|
library does the same job as widely used non-free libraries. In this
|
||||||
|
case, there is little to gain by limiting the free library to free
|
||||||
|
software only, so we use the Lesser General Public License.
|
||||||
|
|
||||||
|
In other cases, permission to use a particular library in non-free
|
||||||
|
programs enables a greater number of people to use a large body of
|
||||||
|
free software. For example, permission to use the GNU C Library in
|
||||||
|
non-free programs enables many more people to use the whole GNU
|
||||||
|
operating system, as well as its variant, the GNU/Linux operating
|
||||||
|
system.
|
||||||
|
|
||||||
|
Although the Lesser General Public License is Less protective of the
|
||||||
|
users' freedom, it does ensure that the user of a program that is
|
||||||
|
linked with the Library has the freedom and the wherewithal to run
|
||||||
|
that program using a modified version of the Library.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow. Pay close attention to the difference between a
|
||||||
|
"work based on the library" and a "work that uses the library". The
|
||||||
|
former contains code derived from the library, whereas the latter must
|
||||||
|
be combined with the library in order to run.
|
||||||
|
|
||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License Agreement applies to any software library or other
|
||||||
|
program which contains a notice placed by the copyright holder or
|
||||||
|
other authorized party saying it may be distributed under the terms of
|
||||||
|
this Lesser General Public License (also called "this License").
|
||||||
|
Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
A "library" means a collection of software functions and/or data
|
||||||
|
prepared so as to be conveniently linked with application programs
|
||||||
|
(which use some of those functions and data) to form executables.
|
||||||
|
|
||||||
|
The "Library", below, refers to any such software library or work
|
||||||
|
which has been distributed under these terms. A "work based on the
|
||||||
|
Library" means either the Library or any derivative work under
|
||||||
|
copyright law: that is to say, a work containing the Library or a
|
||||||
|
portion of it, either verbatim or with modifications and/or translated
|
||||||
|
straightforwardly into another language. (Hereinafter, translation is
|
||||||
|
included without limitation in the term "modification".)
|
||||||
|
|
||||||
|
"Source code" for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For a library, complete source code means
|
||||||
|
all the source code for all modules it contains, plus any associated
|
||||||
|
interface definition files, plus the scripts used to control compilation
|
||||||
|
and installation of the library.
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running a program using the Library is not restricted, and output from
|
||||||
|
such a program is covered only if its contents constitute a work based
|
||||||
|
on the Library (independent of the use of the Library in a tool for
|
||||||
|
writing it). Whether that is true depends on what the Library does
|
||||||
|
and what the program that uses the Library does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Library's
|
||||||
|
complete source code as you receive it, in any medium, provided that
|
||||||
|
you conspicuously and appropriately publish on each copy an
|
||||||
|
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||||
|
all the notices that refer to this License and to the absence of any
|
||||||
|
warranty; and distribute a copy of this License along with the
|
||||||
|
Library.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy,
|
||||||
|
and you may at your option offer warranty protection in exchange for a
|
||||||
|
fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Library or any portion
|
||||||
|
of it, thus forming a work based on the Library, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The modified work must itself be a software library.
|
||||||
|
|
||||||
|
b) You must cause the files modified to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
c) You must cause the whole of the work to be licensed at no
|
||||||
|
charge to all third parties under the terms of this License.
|
||||||
|
|
||||||
|
d) If a facility in the modified Library refers to a function or a
|
||||||
|
table of data to be supplied by an application program that uses
|
||||||
|
the facility, other than as an argument passed when the facility
|
||||||
|
is invoked, then you must make a good faith effort to ensure that,
|
||||||
|
in the event an application does not supply such function or
|
||||||
|
table, the facility still operates, and performs whatever part of
|
||||||
|
its purpose remains meaningful.
|
||||||
|
|
||||||
|
(For example, a function in a library to compute square roots has
|
||||||
|
a purpose that is entirely well-defined independent of the
|
||||||
|
application. Therefore, Subsection 2d requires that any
|
||||||
|
application-supplied function or table used by this function must
|
||||||
|
be optional: if the application does not supply it, the square
|
||||||
|
root function must still compute square roots.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Library,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Library, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote
|
||||||
|
it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Library.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Library
|
||||||
|
with the Library (or with a work based on the Library) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||||
|
License instead of this License to a given copy of the Library. To do
|
||||||
|
this, you must alter all the notices that refer to this License, so
|
||||||
|
that they refer to the ordinary GNU General Public License, version 2,
|
||||||
|
instead of to this License. (If a newer version than version 2 of the
|
||||||
|
ordinary GNU General Public License has appeared, then you can specify
|
||||||
|
that version instead if you wish.) Do not make any other change in
|
||||||
|
these notices.
|
||||||
|
|
||||||
|
Once this change is made in a given copy, it is irreversible for
|
||||||
|
that copy, so the ordinary GNU General Public License applies to all
|
||||||
|
subsequent copies and derivative works made from that copy.
|
||||||
|
|
||||||
|
This option is useful when you wish to copy part of the code of
|
||||||
|
the Library into a program that is not a library.
|
||||||
|
|
||||||
|
4. You may copy and distribute the Library (or a portion or
|
||||||
|
derivative of it, under Section 2) in object code or executable form
|
||||||
|
under the terms of Sections 1 and 2 above provided that you accompany
|
||||||
|
it with the complete corresponding machine-readable source code, which
|
||||||
|
must be distributed under the terms of Sections 1 and 2 above on a
|
||||||
|
medium customarily used for software interchange.
|
||||||
|
|
||||||
|
If distribution of object code is made by offering access to copy
|
||||||
|
from a designated place, then offering equivalent access to copy the
|
||||||
|
source code from the same place satisfies the requirement to
|
||||||
|
distribute the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
5. A program that contains no derivative of any portion of the
|
||||||
|
Library, but is designed to work with the Library by being compiled or
|
||||||
|
linked with it, is called a "work that uses the Library". Such a
|
||||||
|
work, in isolation, is not a derivative work of the Library, and
|
||||||
|
therefore falls outside the scope of this License.
|
||||||
|
|
||||||
|
However, linking a "work that uses the Library" with the Library
|
||||||
|
creates an executable that is a derivative of the Library (because it
|
||||||
|
contains portions of the Library), rather than a "work that uses the
|
||||||
|
library". The executable is therefore covered by this License.
|
||||||
|
Section 6 states terms for distribution of such executables.
|
||||||
|
|
||||||
|
When a "work that uses the Library" uses material from a header file
|
||||||
|
that is part of the Library, the object code for the work may be a
|
||||||
|
derivative work of the Library even though the source code is not.
|
||||||
|
Whether this is true is especially significant if the work can be
|
||||||
|
linked without the Library, or if the work is itself a library. The
|
||||||
|
threshold for this to be true is not precisely defined by law.
|
||||||
|
|
||||||
|
If such an object file uses only numerical parameters, data
|
||||||
|
structure layouts and accessors, and small macros and small inline
|
||||||
|
functions (ten lines or less in length), then the use of the object
|
||||||
|
file is unrestricted, regardless of whether it is legally a derivative
|
||||||
|
work. (Executables containing this object code plus portions of the
|
||||||
|
Library will still fall under Section 6.)
|
||||||
|
|
||||||
|
Otherwise, if the work is a derivative of the Library, you may
|
||||||
|
distribute the object code for the work under the terms of Section 6.
|
||||||
|
Any executables containing that work also fall under Section 6,
|
||||||
|
whether or not they are linked directly with the Library itself.
|
||||||
|
|
||||||
|
6. As an exception to the Sections above, you may also combine or
|
||||||
|
link a "work that uses the Library" with the Library to produce a
|
||||||
|
work containing portions of the Library, and distribute that work
|
||||||
|
under terms of your choice, provided that the terms permit
|
||||||
|
modification of the work for the customer's own use and reverse
|
||||||
|
engineering for debugging such modifications.
|
||||||
|
|
||||||
|
You must give prominent notice with each copy of the work that the
|
||||||
|
Library is used in it and that the Library and its use are covered by
|
||||||
|
this License. You must supply a copy of this License. If the work
|
||||||
|
during execution displays copyright notices, you must include the
|
||||||
|
copyright notice for the Library among them, as well as a reference
|
||||||
|
directing the user to the copy of this License. Also, you must do one
|
||||||
|
of these things:
|
||||||
|
|
||||||
|
a) Accompany the work with the complete corresponding
|
||||||
|
machine-readable source code for the Library including whatever
|
||||||
|
changes were used in the work (which must be distributed under
|
||||||
|
Sections 1 and 2 above); and, if the work is an executable linked
|
||||||
|
with the Library, with the complete machine-readable "work that
|
||||||
|
uses the Library", as object code and/or source code, so that the
|
||||||
|
user can modify the Library and then relink to produce a modified
|
||||||
|
executable containing the modified Library. (It is understood
|
||||||
|
that the user who changes the contents of definitions files in the
|
||||||
|
Library will not necessarily be able to recompile the application
|
||||||
|
to use the modified definitions.)
|
||||||
|
|
||||||
|
b) Use a suitable shared library mechanism for linking with the
|
||||||
|
Library. A suitable mechanism is one that (1) uses at run time a
|
||||||
|
copy of the library already present on the user's computer system,
|
||||||
|
rather than copying library functions into the executable, and (2)
|
||||||
|
will operate properly with a modified version of the library, if
|
||||||
|
the user installs one, as long as the modified version is
|
||||||
|
interface-compatible with the version that the work was made with.
|
||||||
|
|
||||||
|
c) Accompany the work with a written offer, valid for at
|
||||||
|
least three years, to give the same user the materials
|
||||||
|
specified in Subsection 6a, above, for a charge no more
|
||||||
|
than the cost of performing this distribution.
|
||||||
|
|
||||||
|
d) If distribution of the work is made by offering access to copy
|
||||||
|
from a designated place, offer equivalent access to copy the above
|
||||||
|
specified materials from the same place.
|
||||||
|
|
||||||
|
e) Verify that the user has already received a copy of these
|
||||||
|
materials or that you have already sent this user a copy.
|
||||||
|
|
||||||
|
For an executable, the required form of the "work that uses the
|
||||||
|
Library" must include any data and utility programs needed for
|
||||||
|
reproducing the executable from it. However, as a special exception,
|
||||||
|
the materials to be distributed need not include anything that is
|
||||||
|
normally distributed (in either source or binary form) with the major
|
||||||
|
components (compiler, kernel, and so on) of the operating system on
|
||||||
|
which the executable runs, unless that component itself accompanies
|
||||||
|
the executable.
|
||||||
|
|
||||||
|
It may happen that this requirement contradicts the license
|
||||||
|
restrictions of other proprietary libraries that do not normally
|
||||||
|
accompany the operating system. Such a contradiction means you cannot
|
||||||
|
use both them and the Library together in an executable that you
|
||||||
|
distribute.
|
||||||
|
|
||||||
|
7. You may place library facilities that are a work based on the
|
||||||
|
Library side-by-side in a single library together with other library
|
||||||
|
facilities not covered by this License, and distribute such a combined
|
||||||
|
library, provided that the separate distribution of the work based on
|
||||||
|
the Library and of the other library facilities is otherwise
|
||||||
|
permitted, and provided that you do these two things:
|
||||||
|
|
||||||
|
a) Accompany the combined library with a copy of the same work
|
||||||
|
based on the Library, uncombined with any other library
|
||||||
|
facilities. This must be distributed under the terms of the
|
||||||
|
Sections above.
|
||||||
|
|
||||||
|
b) Give prominent notice with the combined library of the fact
|
||||||
|
that part of it is a work based on the Library, and explaining
|
||||||
|
where to find the accompanying uncombined form of the same work.
|
||||||
|
|
||||||
|
8. You may not copy, modify, sublicense, link with, or distribute
|
||||||
|
the Library except as expressly provided under this License. Any
|
||||||
|
attempt otherwise to copy, modify, sublicense, link with, or
|
||||||
|
distribute the Library is void, and will automatically terminate your
|
||||||
|
rights under this License. However, parties who have received copies,
|
||||||
|
or rights, from you under this License will not have their licenses
|
||||||
|
terminated so long as such parties remain in full compliance.
|
||||||
|
|
||||||
|
9. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Library or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Library (or any work based on the
|
||||||
|
Library), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Library or works based on it.
|
||||||
|
|
||||||
|
10. Each time you redistribute the Library (or any work based on the
|
||||||
|
Library), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute, link with or modify the Library
|
||||||
|
subject to these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties with
|
||||||
|
this License.
|
||||||
|
|
||||||
|
11. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Library at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Library by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Library.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under any
|
||||||
|
particular circumstance, the balance of the section is intended to apply,
|
||||||
|
and the section as a whole is intended to apply in other circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
12. If the distribution and/or use of the Library is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Library under this License may add
|
||||||
|
an explicit geographical distribution limitation excluding those countries,
|
||||||
|
so that distribution is permitted only in or among countries not thus
|
||||||
|
excluded. In such case, this License incorporates the limitation as if
|
||||||
|
written in the body of this License.
|
||||||
|
|
||||||
|
13. The Free Software Foundation may publish revised and/or new
|
||||||
|
versions of the Lesser General Public License from time to time.
|
||||||
|
Such new versions will be similar in spirit to the present version,
|
||||||
|
but may differ in detail to address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Library
|
||||||
|
specifies a version number of this License which applies to it and
|
||||||
|
"any later version", you have the option of following the terms and
|
||||||
|
conditions either of that version or of any later version published by
|
||||||
|
the Free Software Foundation. If the Library does not specify a
|
||||||
|
license version number, you may choose any version ever published by
|
||||||
|
the Free Software Foundation.
|
||||||
|
|
||||||
|
14. If you wish to incorporate parts of the Library into other free
|
||||||
|
programs whose distribution conditions are incompatible with these,
|
||||||
|
write to the author to ask for permission. For software which is
|
||||||
|
copyrighted by the Free Software Foundation, write to the Free
|
||||||
|
Software Foundation; we sometimes make exceptions for this. Our
|
||||||
|
decision will be guided by the two goals of preserving the free status
|
||||||
|
of all derivatives of our free software and of promoting the sharing
|
||||||
|
and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||||
|
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||||
|
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||||
|
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||||
|
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||||
|
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||||
|
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||||
|
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||||
|
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||||
|
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||||
|
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||||
|
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||||
|
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||||
|
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||||
|
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
|
DAMAGES.
|
||||||
239
vendor/dompdf/dompdf/README.md
vendored
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
Dompdf
|
||||||
|
======
|
||||||
|
|
||||||
|
[](https://github.com/dompdf/dompdf/actions/workflows/test.yml)
|
||||||
|
[](https://packagist.org/packages/dompdf/dompdf)
|
||||||
|
[](https://packagist.org/packages/dompdf/dompdf)
|
||||||
|
[](https://packagist.org/packages/dompdf/dompdf)
|
||||||
|
[](https://packagist.org/packages/dompdf/dompdf)
|
||||||
|
|
||||||
|
**Dompdf is an HTML to PDF converter**
|
||||||
|
|
||||||
|
At its heart, dompdf is (mostly) a [CSS 2.1](http://www.w3.org/TR/CSS2/) compliant
|
||||||
|
HTML layout and rendering engine written in PHP. It is a style-driven renderer:
|
||||||
|
it will download and read external stylesheets, inline style tags, and the style
|
||||||
|
attributes of individual HTML elements. It also supports most presentational
|
||||||
|
HTML attributes.
|
||||||
|
|
||||||
|
*This document applies to the latest stable code which may not reflect the current
|
||||||
|
release. For released code please
|
||||||
|
[navigate to the appropriate tag](https://github.com/dompdf/dompdf/tags).*
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
**Check out the [demo](http://eclecticgeek.com/dompdf/debug.php) and ask any
|
||||||
|
question on [StackOverflow](https://stackoverflow.com/questions/tagged/dompdf) or
|
||||||
|
in [Discussions](https://github.com/dompdf/dompdf/discussions).**
|
||||||
|
|
||||||
|
Follow us on [](http://www.twitter.com/dompdf).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
* Handles most CSS 2.1 and a few CSS3 properties, including @import, @media &
|
||||||
|
@page rules
|
||||||
|
* Supports most presentational HTML 4.0 attributes
|
||||||
|
* Supports external stylesheets, either local or through http/ftp (via
|
||||||
|
fopen-wrappers)
|
||||||
|
* Supports complex tables, including row & column spans, separate & collapsed
|
||||||
|
border models, individual cell styling
|
||||||
|
* Image support (gif, png (8, 24 and 32 bit with alpha channel), bmp & jpeg)
|
||||||
|
* No dependencies on external PDF libraries, thanks to the R&OS PDF class
|
||||||
|
* Inline PHP support
|
||||||
|
* Basic SVG support (see "Limitations" below)
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
* PHP version 7.1 or higher
|
||||||
|
* DOM extension
|
||||||
|
* MBString extension
|
||||||
|
* php-font-lib
|
||||||
|
* php-svg-lib
|
||||||
|
|
||||||
|
Note that some required dependencies may have further dependencies
|
||||||
|
(notably php-svg-lib requires sabberworm/php-css-parser).
|
||||||
|
|
||||||
|
### Recommendations
|
||||||
|
|
||||||
|
* GD (for image processing)
|
||||||
|
* Additionally, the IMagick or GMagick extension improves image processing performance for certain image types
|
||||||
|
* OPcache (OPcache, XCache, APC, etc.): improves performance
|
||||||
|
|
||||||
|
Visit the wiki for more information:
|
||||||
|
https://github.com/dompdf/dompdf/wiki/Requirements
|
||||||
|
|
||||||
|
## About Fonts & Character Encoding
|
||||||
|
|
||||||
|
PDF documents internally support the following fonts: Helvetica, Times-Roman,
|
||||||
|
Courier, Zapf-Dingbats, & Symbol. These fonts only support Windows ANSI
|
||||||
|
encoding. In order for a PDF to display characters that are not available in
|
||||||
|
Windows ANSI, you must supply an external font. Dompdf will embed any referenced
|
||||||
|
font in the PDF so long as it has been pre-loaded or is accessible to dompdf and
|
||||||
|
reference in CSS @font-face rules. See the
|
||||||
|
[font overview](https://github.com/dompdf/dompdf/wiki/About-Fonts-and-Character-Encoding)
|
||||||
|
for more information on how to use fonts.
|
||||||
|
|
||||||
|
The [DejaVu TrueType fonts](https://dejavu-fonts.github.io/) have been pre-installed
|
||||||
|
to give dompdf decent Unicode character coverage by default. To use the DejaVu
|
||||||
|
fonts reference the font in your stylesheet, e.g. `body { font-family: DejaVu
|
||||||
|
Sans; }` (for DejaVu Sans). The following DejaVu 2.34 fonts are available:
|
||||||
|
DejaVu Sans, DejaVu Serif, and DejaVu Sans Mono.
|
||||||
|
|
||||||
|
## Easy Installation
|
||||||
|
|
||||||
|
### Install with composer
|
||||||
|
|
||||||
|
To install with [Composer](https://getcomposer.org/), simply require the
|
||||||
|
latest version of this package.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
composer require dompdf/dompdf
|
||||||
|
```
|
||||||
|
|
||||||
|
Make sure that the autoload file from Composer is loaded.
|
||||||
|
|
||||||
|
```php
|
||||||
|
// somewhere early in your project's loading, require the Composer autoloader
|
||||||
|
// see: http://getcomposer.org/doc/00-intro.md
|
||||||
|
require 'vendor/autoload.php';
|
||||||
|
```
|
||||||
|
|
||||||
|
### Download and install
|
||||||
|
|
||||||
|
Download a packaged archive of dompdf and extract it into the
|
||||||
|
directory where dompdf will reside
|
||||||
|
|
||||||
|
* You can download stable copies of dompdf from
|
||||||
|
https://github.com/dompdf/dompdf/releases
|
||||||
|
* Or download a nightly (the latest, unreleased code) from
|
||||||
|
http://eclecticgeek.com/dompdf
|
||||||
|
|
||||||
|
Use the packaged release autoloader to load dompdf, libraries,
|
||||||
|
and helper functions in your PHP:
|
||||||
|
|
||||||
|
```php
|
||||||
|
// include autoloader
|
||||||
|
require_once 'dompdf/autoload.inc.php';
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: packaged releases are named according using semantic
|
||||||
|
versioning (_dompdf_MAJOR-MINOR-PATCH.zip_). So the 1.0.0
|
||||||
|
release would be dompdf_1-0-0.zip. This is the only download
|
||||||
|
that includes the autoloader for Dompdf and all its dependencies.
|
||||||
|
|
||||||
|
### Install with git
|
||||||
|
|
||||||
|
From the command line, switch to the directory where dompdf will
|
||||||
|
reside and run the following commands:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone https://github.com/dompdf/dompdf.git
|
||||||
|
cd dompdf/lib
|
||||||
|
|
||||||
|
git clone https://github.com/PhenX/php-font-lib.git php-font-lib
|
||||||
|
cd php-font-lib
|
||||||
|
git checkout 0.5.1
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
git clone https://github.com/PhenX/php-svg-lib.git php-svg-lib
|
||||||
|
cd php-svg-lib
|
||||||
|
git checkout v0.3.2
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
git clone https://github.com/sabberworm/PHP-CSS-Parser.git php-css-parser
|
||||||
|
cd php-css-parser
|
||||||
|
git checkout 8.1.0
|
||||||
|
```
|
||||||
|
|
||||||
|
Require dompdf and it's dependencies in your PHP.
|
||||||
|
For details see the [autoloader in the utils project](https://github.com/dompdf/utils/blob/master/autoload.inc.php).
|
||||||
|
|
||||||
|
## Framework Integration
|
||||||
|
|
||||||
|
* For Symfony: [nucleos/dompdf-bundle](https://github.com/nucleos/NucleosDompdfBundle)
|
||||||
|
* For Laravel: [barryvdh/laravel-dompdf](https://github.com/barryvdh/laravel-dompdf)
|
||||||
|
* For Redaxo: [PdfOut](https://github.com/FriendsOfREDAXO/pdfout)
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
Just pass your HTML in to dompdf and stream the output:
|
||||||
|
|
||||||
|
```php
|
||||||
|
// reference the Dompdf namespace
|
||||||
|
use Dompdf\Dompdf;
|
||||||
|
|
||||||
|
// instantiate and use the dompdf class
|
||||||
|
$dompdf = new Dompdf();
|
||||||
|
$dompdf->loadHtml('hello world');
|
||||||
|
|
||||||
|
// (Optional) Setup the paper size and orientation
|
||||||
|
$dompdf->setPaper('A4', 'landscape');
|
||||||
|
|
||||||
|
// Render the HTML as PDF
|
||||||
|
$dompdf->render();
|
||||||
|
|
||||||
|
// Output the generated PDF to Browser
|
||||||
|
$dompdf->stream();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Setting Options
|
||||||
|
|
||||||
|
Set options during dompdf instantiation:
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Dompdf\Dompdf;
|
||||||
|
use Dompdf\Options;
|
||||||
|
|
||||||
|
$options = new Options();
|
||||||
|
$options->set('defaultFont', 'Courier');
|
||||||
|
$dompdf = new Dompdf($options);
|
||||||
|
```
|
||||||
|
|
||||||
|
or at run time
|
||||||
|
|
||||||
|
```php
|
||||||
|
use Dompdf\Dompdf;
|
||||||
|
|
||||||
|
$dompdf = new Dompdf();
|
||||||
|
$options = $dompdf->getOptions();
|
||||||
|
$options->setDefaultFont('Courier');
|
||||||
|
$dompdf->setOptions($options);
|
||||||
|
```
|
||||||
|
|
||||||
|
See [Dompdf\Options](src/Options.php) for a list of available options.
|
||||||
|
|
||||||
|
### Resource Reference Requirements
|
||||||
|
|
||||||
|
In order to protect potentially sensitive information Dompdf imposes
|
||||||
|
restrictions on files referenced from the local file system or the web.
|
||||||
|
|
||||||
|
Files accessed through web-based protocols have the following requirements:
|
||||||
|
* The Dompdf option "isRemoteEnabled" must be set to "true"
|
||||||
|
* PHP must either have the curl extension enabled or the
|
||||||
|
allow_url_fopen setting set to true
|
||||||
|
|
||||||
|
Files accessed through the local file system have the following requirement:
|
||||||
|
* The file must fall within the path(s) specified for the Dompdf "chroot" option
|
||||||
|
|
||||||
|
## Limitations (Known Issues)
|
||||||
|
|
||||||
|
* Table cells are not pageable, meaning a table row must fit on a single page: See https://github.com/dompdf/dompdf/issues/98
|
||||||
|
* Elements are rendered on the active page when they are parsed.
|
||||||
|
* Embedding "raw" SVG's (`<svg><path...></svg>`) isn't working yet: See https://github.com/dompdf/dompdf/issues/320
|
||||||
|
Workaround: Either link to an external SVG file, or use a DataURI like this:
|
||||||
|
```php
|
||||||
|
$html = '<img src="data:image/svg+xml;base64,' . base64_encode($svg) . '">';
|
||||||
|
```
|
||||||
|
* Does not support CSS flexbox: See https://github.com/dompdf/dompdf/issues/971
|
||||||
|
* Does not support CSS Grid: See https://github.com/dompdf/dompdf/issues/2988
|
||||||
|
* A single Dompdf instance should not be used to render more than one HTML document
|
||||||
|
because persisted parsing and rendering artifacts can impact future renders.
|
||||||
|
---
|
||||||
|
|
||||||
|
[](http://goo.gl/DSvWf)
|
||||||
|
|
||||||
|
*If you find this project useful, please consider making a donation.
|
||||||
|
Any funds donated will be used to help further development on this project.)*
|
||||||
1
vendor/dompdf/dompdf/VERSION
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
3.1.4
|
||||||
49
vendor/dompdf/dompdf/composer.json
vendored
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"name": "dompdf/dompdf",
|
||||||
|
"type": "library",
|
||||||
|
"description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter",
|
||||||
|
"homepage": "https://github.com/dompdf/dompdf",
|
||||||
|
"license": "LGPL-2.1",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "The Dompdf Community",
|
||||||
|
"homepage": "https://github.com/dompdf/dompdf/blob/master/AUTHORS.md"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Dompdf\\": "src/"
|
||||||
|
},
|
||||||
|
"classmap": [
|
||||||
|
"lib/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"Dompdf\\Tests\\": "tests/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^7.1 || ^8.0",
|
||||||
|
"ext-dom": "*",
|
||||||
|
"ext-mbstring": "*",
|
||||||
|
"masterminds/html5": "^2.0",
|
||||||
|
"dompdf/php-font-lib": "^1.0.0",
|
||||||
|
"dompdf/php-svg-lib": "^1.0.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"ext-gd": "*",
|
||||||
|
"ext-json": "*",
|
||||||
|
"ext-zip": "*",
|
||||||
|
"phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11",
|
||||||
|
"squizlabs/php_codesniffer": "^3.5",
|
||||||
|
"mockery/mockery": "^1.3",
|
||||||
|
"symfony/process": "^4.4 || ^5.4 || ^6.2 || ^7.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-gd": "Needed to process images",
|
||||||
|
"ext-imagick": "Improves image processing performance",
|
||||||
|
"ext-gmagick": "Improves image processing performance",
|
||||||
|
"ext-zlib": "Needed for pdf stream compression"
|
||||||
|
}
|
||||||
|
}
|
||||||
6904
vendor/dompdf/dompdf/lib/Cpdf.php
vendored
Normal file
344
vendor/dompdf/dompdf/lib/fonts/Courier-Bold.afm
vendored
Normal file
@ -0,0 +1,344 @@
|
|||||||
|
StartFontMetrics 4.1
|
||||||
|
Comment Copyright (c) 1989, 1990, 1991, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
|
||||||
|
Comment Creation Date: Mon Jun 23 16:28:00 0:00:00
|
||||||
|
Comment UniqueID 43048
|
||||||
|
Comment VMusage 41139 52164
|
||||||
|
FontName Courier-Bold
|
||||||
|
FullName Courier Bold
|
||||||
|
FamilyName Courier
|
||||||
|
Weight Bold
|
||||||
|
ItalicAngle 0
|
||||||
|
IsFixedPitch true
|
||||||
|
CharacterSet ExtendedRoman
|
||||||
|
FontBBox -113 -250 749 801
|
||||||
|
UnderlinePosition -100
|
||||||
|
UnderlineThickness 50
|
||||||
|
Version 003.000
|
||||||
|
Notice Copyright (c) 1989, 1990, 1991, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
|
||||||
|
EncodingScheme WinAnsiEncoding
|
||||||
|
CapHeight 562
|
||||||
|
XHeight 439
|
||||||
|
Ascender 629
|
||||||
|
Descender -157
|
||||||
|
StdHW 84
|
||||||
|
StdVW 106
|
||||||
|
StartCharMetrics 317
|
||||||
|
C 32 ; WX 600 ; N space ; B 0 0 0 0 ;
|
||||||
|
C 160 ; WX 600 ; N space ; B 0 0 0 0 ;
|
||||||
|
C 33 ; WX 600 ; N exclam ; B 202 -15 398 572 ;
|
||||||
|
C 34 ; WX 600 ; N quotedbl ; B 135 277 465 562 ;
|
||||||
|
C 35 ; WX 600 ; N numbersign ; B 56 -45 544 651 ;
|
||||||
|
C 36 ; WX 600 ; N dollar ; B 82 -126 519 666 ;
|
||||||
|
C 37 ; WX 600 ; N percent ; B 5 -15 595 616 ;
|
||||||
|
C 38 ; WX 600 ; N ampersand ; B 36 -15 546 543 ;
|
||||||
|
C 146 ; WX 600 ; N quoteright ; B 171 277 423 562 ;
|
||||||
|
C 40 ; WX 600 ; N parenleft ; B 219 -102 461 616 ;
|
||||||
|
C 41 ; WX 600 ; N parenright ; B 139 -102 381 616 ;
|
||||||
|
C 42 ; WX 600 ; N asterisk ; B 91 219 509 601 ;
|
||||||
|
C 43 ; WX 600 ; N plus ; B 71 39 529 478 ;
|
||||||
|
C 44 ; WX 600 ; N comma ; B 123 -111 393 174 ;
|
||||||
|
C 45 ; WX 600 ; N hyphen ; B 100 203 500 313 ;
|
||||||
|
C 173 ; WX 600 ; N hyphen ; B 100 203 500 313 ;
|
||||||
|
C 46 ; WX 600 ; N period ; B 192 -15 408 171 ;
|
||||||
|
C 47 ; WX 600 ; N slash ; B 98 -77 502 626 ;
|
||||||
|
C 48 ; WX 600 ; N zero ; B 87 -15 513 616 ;
|
||||||
|
C 49 ; WX 600 ; N one ; B 81 0 539 616 ;
|
||||||
|
C 50 ; WX 600 ; N two ; B 61 0 499 616 ;
|
||||||
|
C 51 ; WX 600 ; N three ; B 63 -15 501 616 ;
|
||||||
|
C 52 ; WX 600 ; N four ; B 53 0 507 616 ;
|
||||||
|
C 53 ; WX 600 ; N five ; B 70 -15 521 601 ;
|
||||||
|
C 54 ; WX 600 ; N six ; B 90 -15 521 616 ;
|
||||||
|
C 55 ; WX 600 ; N seven ; B 55 0 494 601 ;
|
||||||
|
C 56 ; WX 600 ; N eight ; B 83 -15 517 616 ;
|
||||||
|
C 57 ; WX 600 ; N nine ; B 79 -15 510 616 ;
|
||||||
|
C 58 ; WX 600 ; N colon ; B 191 -15 407 425 ;
|
||||||
|
C 59 ; WX 600 ; N semicolon ; B 123 -111 408 425 ;
|
||||||
|
C 60 ; WX 600 ; N less ; B 66 15 523 501 ;
|
||||||
|
C 61 ; WX 600 ; N equal ; B 71 118 529 398 ;
|
||||||
|
C 62 ; WX 600 ; N greater ; B 77 15 534 501 ;
|
||||||
|
C 63 ; WX 600 ; N question ; B 98 -14 501 580 ;
|
||||||
|
C 64 ; WX 600 ; N at ; B 16 -15 584 616 ;
|
||||||
|
C 65 ; WX 600 ; N A ; B -9 0 609 562 ;
|
||||||
|
C 66 ; WX 600 ; N B ; B 30 0 573 562 ;
|
||||||
|
C 67 ; WX 600 ; N C ; B 22 -18 560 580 ;
|
||||||
|
C 68 ; WX 600 ; N D ; B 30 0 594 562 ;
|
||||||
|
C 69 ; WX 600 ; N E ; B 25 0 560 562 ;
|
||||||
|
C 70 ; WX 600 ; N F ; B 39 0 570 562 ;
|
||||||
|
C 71 ; WX 600 ; N G ; B 22 -18 594 580 ;
|
||||||
|
C 72 ; WX 600 ; N H ; B 20 0 580 562 ;
|
||||||
|
C 73 ; WX 600 ; N I ; B 77 0 523 562 ;
|
||||||
|
C 74 ; WX 600 ; N J ; B 37 -18 601 562 ;
|
||||||
|
C 75 ; WX 600 ; N K ; B 21 0 599 562 ;
|
||||||
|
C 76 ; WX 600 ; N L ; B 39 0 578 562 ;
|
||||||
|
C 77 ; WX 600 ; N M ; B -2 0 602 562 ;
|
||||||
|
C 78 ; WX 600 ; N N ; B 8 -12 610 562 ;
|
||||||
|
C 79 ; WX 600 ; N O ; B 22 -18 578 580 ;
|
||||||
|
C 80 ; WX 600 ; N P ; B 48 0 559 562 ;
|
||||||
|
C 81 ; WX 600 ; N Q ; B 32 -138 578 580 ;
|
||||||
|
C 82 ; WX 600 ; N R ; B 24 0 599 562 ;
|
||||||
|
C 83 ; WX 600 ; N S ; B 47 -22 553 582 ;
|
||||||
|
C 84 ; WX 600 ; N T ; B 21 0 579 562 ;
|
||||||
|
C 85 ; WX 600 ; N U ; B 4 -18 596 562 ;
|
||||||
|
C 86 ; WX 600 ; N V ; B -13 0 613 562 ;
|
||||||
|
C 87 ; WX 600 ; N W ; B -18 0 618 562 ;
|
||||||
|
C 88 ; WX 600 ; N X ; B 12 0 588 562 ;
|
||||||
|
C 89 ; WX 600 ; N Y ; B 12 0 589 562 ;
|
||||||
|
C 90 ; WX 600 ; N Z ; B 62 0 539 562 ;
|
||||||
|
C 91 ; WX 600 ; N bracketleft ; B 245 -102 475 616 ;
|
||||||
|
C 92 ; WX 600 ; N backslash ; B 99 -77 503 626 ;
|
||||||
|
C 93 ; WX 600 ; N bracketright ; B 125 -102 355 616 ;
|
||||||
|
C 94 ; WX 600 ; N asciicircum ; B 108 250 492 616 ;
|
||||||
|
C 95 ; WX 600 ; N underscore ; B 0 -125 600 -75 ;
|
||||||
|
C 145 ; WX 600 ; N quoteleft ; B 178 277 428 562 ;
|
||||||
|
C 97 ; WX 600 ; N a ; B 35 -15 570 454 ;
|
||||||
|
C 98 ; WX 600 ; N b ; B 0 -15 584 626 ;
|
||||||
|
C 99 ; WX 600 ; N c ; B 40 -15 545 459 ;
|
||||||
|
C 100 ; WX 600 ; N d ; B 20 -15 591 626 ;
|
||||||
|
C 101 ; WX 600 ; N e ; B 40 -15 563 454 ;
|
||||||
|
C 102 ; WX 600 ; N f ; B 83 0 547 626 ; L i fi ; L l fl ;
|
||||||
|
C 103 ; WX 600 ; N g ; B 30 -146 580 454 ;
|
||||||
|
C 104 ; WX 600 ; N h ; B 5 0 592 626 ;
|
||||||
|
C 105 ; WX 600 ; N i ; B 77 0 523 658 ;
|
||||||
|
C 106 ; WX 600 ; N j ; B 63 -146 440 658 ;
|
||||||
|
C 107 ; WX 600 ; N k ; B 20 0 585 626 ;
|
||||||
|
C 108 ; WX 600 ; N l ; B 77 0 523 626 ;
|
||||||
|
C 109 ; WX 600 ; N m ; B -22 0 626 454 ;
|
||||||
|
C 110 ; WX 600 ; N n ; B 18 0 592 454 ;
|
||||||
|
C 111 ; WX 600 ; N o ; B 30 -15 570 454 ;
|
||||||
|
C 112 ; WX 600 ; N p ; B -1 -142 570 454 ;
|
||||||
|
C 113 ; WX 600 ; N q ; B 20 -142 591 454 ;
|
||||||
|
C 114 ; WX 600 ; N r ; B 47 0 580 454 ;
|
||||||
|
C 115 ; WX 600 ; N s ; B 68 -17 535 459 ;
|
||||||
|
C 116 ; WX 600 ; N t ; B 47 -15 532 562 ;
|
||||||
|
C 117 ; WX 600 ; N u ; B -1 -15 569 439 ;
|
||||||
|
C 118 ; WX 600 ; N v ; B -1 0 601 439 ;
|
||||||
|
C 119 ; WX 600 ; N w ; B -18 0 618 439 ;
|
||||||
|
C 120 ; WX 600 ; N x ; B 6 0 594 439 ;
|
||||||
|
C 121 ; WX 600 ; N y ; B -4 -142 601 439 ;
|
||||||
|
C 122 ; WX 600 ; N z ; B 81 0 520 439 ;
|
||||||
|
C 123 ; WX 600 ; N braceleft ; B 160 -102 464 616 ;
|
||||||
|
C 124 ; WX 600 ; N bar ; B 255 -250 345 750 ;
|
||||||
|
C 125 ; WX 600 ; N braceright ; B 136 -102 440 616 ;
|
||||||
|
C 126 ; WX 600 ; N asciitilde ; B 71 153 530 356 ;
|
||||||
|
C 161 ; WX 600 ; N exclamdown ; B 202 -146 398 449 ;
|
||||||
|
C 162 ; WX 600 ; N cent ; B 66 -49 518 614 ;
|
||||||
|
C 163 ; WX 600 ; N sterling ; B 72 -28 558 611 ;
|
||||||
|
C -1 ; WX 600 ; N fraction ; B 25 -60 576 661 ;
|
||||||
|
C 165 ; WX 600 ; N yen ; B 10 0 590 562 ;
|
||||||
|
C 131 ; WX 600 ; N florin ; B -30 -131 572 616 ;
|
||||||
|
C 167 ; WX 600 ; N section ; B 83 -70 517 580 ;
|
||||||
|
C 164 ; WX 600 ; N currency ; B 54 49 546 517 ;
|
||||||
|
C 39 ; WX 600 ; N quotesingle ; B 227 277 373 562 ;
|
||||||
|
C 147 ; WX 600 ; N quotedblleft ; B 71 277 535 562 ;
|
||||||
|
C 171 ; WX 600 ; N guillemotleft ; B 8 70 553 446 ;
|
||||||
|
C 139 ; WX 600 ; N guilsinglleft ; B 141 70 459 446 ;
|
||||||
|
C 155 ; WX 600 ; N guilsinglright ; B 141 70 459 446 ;
|
||||||
|
C -1 ; WX 600 ; N fi ; B 12 0 593 626 ;
|
||||||
|
C -1 ; WX 600 ; N fl ; B 12 0 593 626 ;
|
||||||
|
C 150 ; WX 600 ; N endash ; B 65 203 535 313 ;
|
||||||
|
C 134 ; WX 600 ; N dagger ; B 106 -70 494 580 ;
|
||||||
|
C 135 ; WX 600 ; N daggerdbl ; B 106 -70 494 580 ;
|
||||||
|
C 183 ; WX 600 ; N periodcentered ; B 196 165 404 351 ;
|
||||||
|
C 182 ; WX 600 ; N paragraph ; B 6 -70 576 580 ;
|
||||||
|
C 149 ; WX 600 ; N bullet ; B 140 132 460 430 ;
|
||||||
|
C 130 ; WX 600 ; N quotesinglbase ; B 175 -142 427 143 ;
|
||||||
|
C 132 ; WX 600 ; N quotedblbase ; B 65 -142 529 143 ;
|
||||||
|
C 148 ; WX 600 ; N quotedblright ; B 61 277 525 562 ;
|
||||||
|
C 187 ; WX 600 ; N guillemotright ; B 47 70 592 446 ;
|
||||||
|
C 133 ; WX 600 ; N ellipsis ; B 26 -15 574 116 ;
|
||||||
|
C 137 ; WX 600 ; N perthousand ; B -113 -15 713 616 ;
|
||||||
|
C 191 ; WX 600 ; N questiondown ; B 99 -146 502 449 ;
|
||||||
|
C 96 ; WX 600 ; N grave ; B 132 508 395 661 ;
|
||||||
|
C 180 ; WX 600 ; N acute ; B 205 508 468 661 ;
|
||||||
|
C 136 ; WX 600 ; N circumflex ; B 103 483 497 657 ;
|
||||||
|
C 152 ; WX 600 ; N tilde ; B 89 493 512 636 ;
|
||||||
|
C 175 ; WX 600 ; N macron ; B 88 505 512 585 ;
|
||||||
|
C -1 ; WX 600 ; N breve ; B 83 468 517 631 ;
|
||||||
|
C -1 ; WX 600 ; N dotaccent ; B 230 498 370 638 ;
|
||||||
|
C 168 ; WX 600 ; N dieresis ; B 128 498 472 638 ;
|
||||||
|
C -1 ; WX 600 ; N ring ; B 198 481 402 678 ;
|
||||||
|
C 184 ; WX 600 ; N cedilla ; B 205 -206 387 0 ;
|
||||||
|
C -1 ; WX 600 ; N hungarumlaut ; B 68 488 588 661 ;
|
||||||
|
C -1 ; WX 600 ; N ogonek ; B 169 -199 400 0 ;
|
||||||
|
C -1 ; WX 600 ; N caron ; B 103 493 497 667 ;
|
||||||
|
C 151 ; WX 600 ; N emdash ; B -10 203 610 313 ;
|
||||||
|
C 198 ; WX 600 ; N AE ; B -29 0 602 562 ;
|
||||||
|
C 170 ; WX 600 ; N ordfeminine ; B 147 196 453 580 ;
|
||||||
|
C -1 ; WX 600 ; N Lslash ; B 39 0 578 562 ;
|
||||||
|
C 216 ; WX 600 ; N Oslash ; B 22 -22 578 584 ;
|
||||||
|
C 140 ; WX 600 ; N OE ; B -25 0 595 562 ;
|
||||||
|
C 186 ; WX 600 ; N ordmasculine ; B 147 196 453 580 ;
|
||||||
|
C 230 ; WX 600 ; N ae ; B -4 -15 601 454 ;
|
||||||
|
C -1 ; WX 600 ; N dotlessi ; B 77 0 523 439 ;
|
||||||
|
C -1 ; WX 600 ; N lslash ; B 77 0 523 626 ;
|
||||||
|
C 248 ; WX 600 ; N oslash ; B 30 -24 570 463 ;
|
||||||
|
C 156 ; WX 600 ; N oe ; B -18 -15 611 454 ;
|
||||||
|
C 223 ; WX 600 ; N germandbls ; B 22 -15 596 626 ;
|
||||||
|
C 207 ; WX 600 ; N Idieresis ; B 77 0 523 761 ;
|
||||||
|
C 233 ; WX 600 ; N eacute ; B 40 -15 563 661 ;
|
||||||
|
C -1 ; WX 600 ; N abreve ; B 35 -15 570 661 ;
|
||||||
|
C -1 ; WX 600 ; N uhungarumlaut ; B -1 -15 628 661 ;
|
||||||
|
C -1 ; WX 600 ; N ecaron ; B 40 -15 563 667 ;
|
||||||
|
C 159 ; WX 600 ; N Ydieresis ; B 12 0 589 761 ;
|
||||||
|
C 247 ; WX 600 ; N divide ; B 71 16 529 500 ;
|
||||||
|
C 221 ; WX 600 ; N Yacute ; B 12 0 589 784 ;
|
||||||
|
C 194 ; WX 600 ; N Acircumflex ; B -9 0 609 780 ;
|
||||||
|
C 225 ; WX 600 ; N aacute ; B 35 -15 570 661 ;
|
||||||
|
C 219 ; WX 600 ; N Ucircumflex ; B 4 -18 596 780 ;
|
||||||
|
C 253 ; WX 600 ; N yacute ; B -4 -142 601 661 ;
|
||||||
|
C -1 ; WX 600 ; N scommaaccent ; B 68 -250 535 459 ;
|
||||||
|
C 234 ; WX 600 ; N ecircumflex ; B 40 -15 563 657 ;
|
||||||
|
C -1 ; WX 600 ; N Uring ; B 4 -18 596 801 ;
|
||||||
|
C 220 ; WX 600 ; N Udieresis ; B 4 -18 596 761 ;
|
||||||
|
C -1 ; WX 600 ; N aogonek ; B 35 -199 586 454 ;
|
||||||
|
C 218 ; WX 600 ; N Uacute ; B 4 -18 596 784 ;
|
||||||
|
C -1 ; WX 600 ; N uogonek ; B -1 -199 585 439 ;
|
||||||
|
C 203 ; WX 600 ; N Edieresis ; B 25 0 560 761 ;
|
||||||
|
C -1 ; WX 600 ; N Dcroat ; B 30 0 594 562 ;
|
||||||
|
C -1 ; WX 600 ; N commaaccent ; B 205 -250 397 -57 ;
|
||||||
|
C 169 ; WX 600 ; N copyright ; B 0 -18 600 580 ;
|
||||||
|
C -1 ; WX 600 ; N Emacron ; B 25 0 560 708 ;
|
||||||
|
C -1 ; WX 600 ; N ccaron ; B 40 -15 545 667 ;
|
||||||
|
C 229 ; WX 600 ; N aring ; B 35 -15 570 678 ;
|
||||||
|
C -1 ; WX 600 ; N Ncommaaccent ; B 8 -250 610 562 ;
|
||||||
|
C -1 ; WX 600 ; N lacute ; B 77 0 523 801 ;
|
||||||
|
C 224 ; WX 600 ; N agrave ; B 35 -15 570 661 ;
|
||||||
|
C -1 ; WX 600 ; N Tcommaaccent ; B 21 -250 579 562 ;
|
||||||
|
C -1 ; WX 600 ; N Cacute ; B 22 -18 560 784 ;
|
||||||
|
C 227 ; WX 600 ; N atilde ; B 35 -15 570 636 ;
|
||||||
|
C -1 ; WX 600 ; N Edotaccent ; B 25 0 560 761 ;
|
||||||
|
C 154 ; WX 600 ; N scaron ; B 68 -17 535 667 ;
|
||||||
|
C -1 ; WX 600 ; N scedilla ; B 68 -206 535 459 ;
|
||||||
|
C 237 ; WX 600 ; N iacute ; B 77 0 523 661 ;
|
||||||
|
C -1 ; WX 600 ; N lozenge ; B 66 0 534 740 ;
|
||||||
|
C -1 ; WX 600 ; N Rcaron ; B 24 0 599 790 ;
|
||||||
|
C -1 ; WX 600 ; N Gcommaaccent ; B 22 -250 594 580 ;
|
||||||
|
C 251 ; WX 600 ; N ucircumflex ; B -1 -15 569 657 ;
|
||||||
|
C 226 ; WX 600 ; N acircumflex ; B 35 -15 570 657 ;
|
||||||
|
C -1 ; WX 600 ; N Amacron ; B -9 0 609 708 ;
|
||||||
|
C -1 ; WX 600 ; N rcaron ; B 47 0 580 667 ;
|
||||||
|
C 231 ; WX 600 ; N ccedilla ; B 40 -206 545 459 ;
|
||||||
|
C -1 ; WX 600 ; N Zdotaccent ; B 62 0 539 761 ;
|
||||||
|
C 222 ; WX 600 ; N Thorn ; B 48 0 557 562 ;
|
||||||
|
C -1 ; WX 600 ; N Omacron ; B 22 -18 578 708 ;
|
||||||
|
C -1 ; WX 600 ; N Racute ; B 24 0 599 784 ;
|
||||||
|
C -1 ; WX 600 ; N Sacute ; B 47 -22 553 784 ;
|
||||||
|
C -1 ; WX 600 ; N dcaron ; B 20 -15 727 626 ;
|
||||||
|
C -1 ; WX 600 ; N Umacron ; B 4 -18 596 708 ;
|
||||||
|
C -1 ; WX 600 ; N uring ; B -1 -15 569 678 ;
|
||||||
|
C 179 ; WX 600 ; N threesuperior ; B 138 222 433 616 ;
|
||||||
|
C 210 ; WX 600 ; N Ograve ; B 22 -18 578 784 ;
|
||||||
|
C 192 ; WX 600 ; N Agrave ; B -9 0 609 784 ;
|
||||||
|
C -1 ; WX 600 ; N Abreve ; B -9 0 609 784 ;
|
||||||
|
C 215 ; WX 600 ; N multiply ; B 81 39 520 478 ;
|
||||||
|
C 250 ; WX 600 ; N uacute ; B -1 -15 569 661 ;
|
||||||
|
C -1 ; WX 600 ; N Tcaron ; B 21 0 579 790 ;
|
||||||
|
C -1 ; WX 600 ; N partialdiff ; B 63 -38 537 728 ;
|
||||||
|
C 255 ; WX 600 ; N ydieresis ; B -4 -142 601 638 ;
|
||||||
|
C -1 ; WX 600 ; N Nacute ; B 8 -12 610 784 ;
|
||||||
|
C 238 ; WX 600 ; N icircumflex ; B 73 0 523 657 ;
|
||||||
|
C 202 ; WX 600 ; N Ecircumflex ; B 25 0 560 780 ;
|
||||||
|
C 228 ; WX 600 ; N adieresis ; B 35 -15 570 638 ;
|
||||||
|
C 235 ; WX 600 ; N edieresis ; B 40 -15 563 638 ;
|
||||||
|
C -1 ; WX 600 ; N cacute ; B 40 -15 545 661 ;
|
||||||
|
C -1 ; WX 600 ; N nacute ; B 18 0 592 661 ;
|
||||||
|
C -1 ; WX 600 ; N umacron ; B -1 -15 569 585 ;
|
||||||
|
C -1 ; WX 600 ; N Ncaron ; B 8 -12 610 790 ;
|
||||||
|
C 205 ; WX 600 ; N Iacute ; B 77 0 523 784 ;
|
||||||
|
C 177 ; WX 600 ; N plusminus ; B 71 24 529 515 ;
|
||||||
|
C 166 ; WX 600 ; N brokenbar ; B 255 -175 345 675 ;
|
||||||
|
C 174 ; WX 600 ; N registered ; B 0 -18 600 580 ;
|
||||||
|
C -1 ; WX 600 ; N Gbreve ; B 22 -18 594 784 ;
|
||||||
|
C -1 ; WX 600 ; N Idotaccent ; B 77 0 523 761 ;
|
||||||
|
C -1 ; WX 600 ; N summation ; B 15 -10 586 706 ;
|
||||||
|
C 200 ; WX 600 ; N Egrave ; B 25 0 560 784 ;
|
||||||
|
C -1 ; WX 600 ; N racute ; B 47 0 580 661 ;
|
||||||
|
C -1 ; WX 600 ; N omacron ; B 30 -15 570 585 ;
|
||||||
|
C -1 ; WX 600 ; N Zacute ; B 62 0 539 784 ;
|
||||||
|
C 142 ; WX 600 ; N Zcaron ; B 62 0 539 790 ;
|
||||||
|
C -1 ; WX 600 ; N greaterequal ; B 26 0 523 696 ;
|
||||||
|
C 208 ; WX 600 ; N Eth ; B 30 0 594 562 ;
|
||||||
|
C 199 ; WX 600 ; N Ccedilla ; B 22 -206 560 580 ;
|
||||||
|
C -1 ; WX 600 ; N lcommaaccent ; B 77 -250 523 626 ;
|
||||||
|
C -1 ; WX 600 ; N tcaron ; B 47 -15 532 703 ;
|
||||||
|
C -1 ; WX 600 ; N eogonek ; B 40 -199 563 454 ;
|
||||||
|
C -1 ; WX 600 ; N Uogonek ; B 4 -199 596 562 ;
|
||||||
|
C 193 ; WX 600 ; N Aacute ; B -9 0 609 784 ;
|
||||||
|
C 196 ; WX 600 ; N Adieresis ; B -9 0 609 761 ;
|
||||||
|
C 232 ; WX 600 ; N egrave ; B 40 -15 563 661 ;
|
||||||
|
C -1 ; WX 600 ; N zacute ; B 81 0 520 661 ;
|
||||||
|
C -1 ; WX 600 ; N iogonek ; B 77 -199 523 658 ;
|
||||||
|
C 211 ; WX 600 ; N Oacute ; B 22 -18 578 784 ;
|
||||||
|
C 243 ; WX 600 ; N oacute ; B 30 -15 570 661 ;
|
||||||
|
C -1 ; WX 600 ; N amacron ; B 35 -15 570 585 ;
|
||||||
|
C -1 ; WX 600 ; N sacute ; B 68 -17 535 661 ;
|
||||||
|
C 239 ; WX 600 ; N idieresis ; B 77 0 523 618 ;
|
||||||
|
C 212 ; WX 600 ; N Ocircumflex ; B 22 -18 578 780 ;
|
||||||
|
C 217 ; WX 600 ; N Ugrave ; B 4 -18 596 784 ;
|
||||||
|
C -1 ; WX 600 ; N Delta ; B 6 0 594 688 ;
|
||||||
|
C 254 ; WX 600 ; N thorn ; B -14 -142 570 626 ;
|
||||||
|
C 178 ; WX 600 ; N twosuperior ; B 143 230 436 616 ;
|
||||||
|
C 214 ; WX 600 ; N Odieresis ; B 22 -18 578 761 ;
|
||||||
|
C 181 ; WX 600 ; N mu ; B -1 -142 569 439 ;
|
||||||
|
C 236 ; WX 600 ; N igrave ; B 77 0 523 661 ;
|
||||||
|
C -1 ; WX 600 ; N ohungarumlaut ; B 30 -15 668 661 ;
|
||||||
|
C -1 ; WX 600 ; N Eogonek ; B 25 -199 576 562 ;
|
||||||
|
C -1 ; WX 600 ; N dcroat ; B 20 -15 591 626 ;
|
||||||
|
C 190 ; WX 600 ; N threequarters ; B -47 -60 648 661 ;
|
||||||
|
C -1 ; WX 600 ; N Scedilla ; B 47 -206 553 582 ;
|
||||||
|
C -1 ; WX 600 ; N lcaron ; B 77 0 597 626 ;
|
||||||
|
C -1 ; WX 600 ; N Kcommaaccent ; B 21 -250 599 562 ;
|
||||||
|
C -1 ; WX 600 ; N Lacute ; B 39 0 578 784 ;
|
||||||
|
C 153 ; WX 600 ; N trademark ; B -9 230 749 562 ;
|
||||||
|
C -1 ; WX 600 ; N edotaccent ; B 40 -15 563 638 ;
|
||||||
|
C 204 ; WX 600 ; N Igrave ; B 77 0 523 784 ;
|
||||||
|
C -1 ; WX 600 ; N Imacron ; B 77 0 523 708 ;
|
||||||
|
C -1 ; WX 600 ; N Lcaron ; B 39 0 637 562 ;
|
||||||
|
C 189 ; WX 600 ; N onehalf ; B -47 -60 648 661 ;
|
||||||
|
C -1 ; WX 600 ; N lessequal ; B 26 0 523 696 ;
|
||||||
|
C 244 ; WX 600 ; N ocircumflex ; B 30 -15 570 657 ;
|
||||||
|
C 241 ; WX 600 ; N ntilde ; B 18 0 592 636 ;
|
||||||
|
C -1 ; WX 600 ; N Uhungarumlaut ; B 4 -18 638 784 ;
|
||||||
|
C 201 ; WX 600 ; N Eacute ; B 25 0 560 784 ;
|
||||||
|
C -1 ; WX 600 ; N emacron ; B 40 -15 563 585 ;
|
||||||
|
C -1 ; WX 600 ; N gbreve ; B 30 -146 580 661 ;
|
||||||
|
C 188 ; WX 600 ; N onequarter ; B -56 -60 656 661 ;
|
||||||
|
C 138 ; WX 600 ; N Scaron ; B 47 -22 553 790 ;
|
||||||
|
C -1 ; WX 600 ; N Scommaaccent ; B 47 -250 553 582 ;
|
||||||
|
C -1 ; WX 600 ; N Ohungarumlaut ; B 22 -18 628 784 ;
|
||||||
|
C 176 ; WX 600 ; N degree ; B 86 243 474 616 ;
|
||||||
|
C 242 ; WX 600 ; N ograve ; B 30 -15 570 661 ;
|
||||||
|
C -1 ; WX 600 ; N Ccaron ; B 22 -18 560 790 ;
|
||||||
|
C 249 ; WX 600 ; N ugrave ; B -1 -15 569 661 ;
|
||||||
|
C -1 ; WX 600 ; N radical ; B -19 -104 473 778 ;
|
||||||
|
C -1 ; WX 600 ; N Dcaron ; B 30 0 594 790 ;
|
||||||
|
C -1 ; WX 600 ; N rcommaaccent ; B 47 -250 580 454 ;
|
||||||
|
C 209 ; WX 600 ; N Ntilde ; B 8 -12 610 759 ;
|
||||||
|
C 245 ; WX 600 ; N otilde ; B 30 -15 570 636 ;
|
||||||
|
C -1 ; WX 600 ; N Rcommaaccent ; B 24 -250 599 562 ;
|
||||||
|
C -1 ; WX 600 ; N Lcommaaccent ; B 39 -250 578 562 ;
|
||||||
|
C 195 ; WX 600 ; N Atilde ; B -9 0 609 759 ;
|
||||||
|
C -1 ; WX 600 ; N Aogonek ; B -9 -199 625 562 ;
|
||||||
|
C 197 ; WX 600 ; N Aring ; B -9 0 609 801 ;
|
||||||
|
C 213 ; WX 600 ; N Otilde ; B 22 -18 578 759 ;
|
||||||
|
C -1 ; WX 600 ; N zdotaccent ; B 81 0 520 638 ;
|
||||||
|
C -1 ; WX 600 ; N Ecaron ; B 25 0 560 790 ;
|
||||||
|
C -1 ; WX 600 ; N Iogonek ; B 77 -199 523 562 ;
|
||||||
|
C -1 ; WX 600 ; N kcommaaccent ; B 20 -250 585 626 ;
|
||||||
|
C -1 ; WX 600 ; N minus ; B 71 203 529 313 ;
|
||||||
|
C 206 ; WX 600 ; N Icircumflex ; B 77 0 523 780 ;
|
||||||
|
C -1 ; WX 600 ; N ncaron ; B 18 0 592 667 ;
|
||||||
|
C -1 ; WX 600 ; N tcommaaccent ; B 47 -250 532 562 ;
|
||||||
|
C 172 ; WX 600 ; N logicalnot ; B 71 103 529 413 ;
|
||||||
|
C 246 ; WX 600 ; N odieresis ; B 30 -15 570 638 ;
|
||||||
|
C 252 ; WX 600 ; N udieresis ; B -1 -15 569 638 ;
|
||||||
|
C -1 ; WX 600 ; N notequal ; B 12 -47 537 563 ;
|
||||||
|
C -1 ; WX 600 ; N gcommaaccent ; B 30 -146 580 714 ;
|
||||||
|
C 240 ; WX 600 ; N eth ; B 58 -27 543 626 ;
|
||||||
|
C 158 ; WX 600 ; N zcaron ; B 81 0 520 667 ;
|
||||||
|
C -1 ; WX 600 ; N ncommaaccent ; B 18 -250 592 454 ;
|
||||||
|
C 185 ; WX 600 ; N onesuperior ; B 153 230 447 616 ;
|
||||||
|
C -1 ; WX 600 ; N imacron ; B 77 0 523 585 ;
|
||||||
|
C 128 ; WX 600 ; N Euro ; B 0 0 0 0 ;
|
||||||
|
EndCharMetrics
|
||||||
|
EndFontMetrics
|
||||||
344
vendor/dompdf/dompdf/lib/fonts/Courier-BoldOblique.afm
vendored
Normal file
@ -0,0 +1,344 @@
|
|||||||
|
StartFontMetrics 4.1
|
||||||
|
Comment Copyright (c) 1989, 1990, 1991, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
|
||||||
|
Comment Creation Date: Mon Jun 23 16:28:46 0:00:00
|
||||||
|
Comment UniqueID 43049
|
||||||
|
Comment VMusage 17529 79244
|
||||||
|
FontName Courier-BoldOblique
|
||||||
|
FullName Courier Bold Oblique
|
||||||
|
FamilyName Courier
|
||||||
|
Weight Bold
|
||||||
|
ItalicAngle -12
|
||||||
|
IsFixedPitch true
|
||||||
|
CharacterSet ExtendedRoman
|
||||||
|
FontBBox -57 -250 869 801
|
||||||
|
UnderlinePosition -100
|
||||||
|
UnderlineThickness 50
|
||||||
|
Version 3
|
||||||
|
Notice Copyright (c) 1989, 1990, 1991, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
|
||||||
|
EncodingScheme WinAnsiEncoding
|
||||||
|
CapHeight 562
|
||||||
|
XHeight 439
|
||||||
|
Ascender 629
|
||||||
|
Descender -157
|
||||||
|
StdHW 84
|
||||||
|
StdVW 106
|
||||||
|
StartCharMetrics 317
|
||||||
|
C 32 ; WX 600 ; N space ; B 0 0 0 0 ;
|
||||||
|
C 160 ; WX 600 ; N space ; B 0 0 0 0 ;
|
||||||
|
C 33 ; WX 600 ; N exclam ; B 215 -15 495 572 ;
|
||||||
|
C 34 ; WX 600 ; N quotedbl ; B 211 277 585 562 ;
|
||||||
|
C 35 ; WX 600 ; N numbersign ; B 88 -45 641 651 ;
|
||||||
|
C 36 ; WX 600 ; N dollar ; B 87 -126 630 666 ;
|
||||||
|
C 37 ; WX 600 ; N percent ; B 101 -15 625 616 ;
|
||||||
|
C 38 ; WX 600 ; N ampersand ; B 61 -15 595 543 ;
|
||||||
|
C 146 ; WX 600 ; N quoteright ; B 229 277 543 562 ;
|
||||||
|
C 40 ; WX 600 ; N parenleft ; B 265 -102 592 616 ;
|
||||||
|
C 41 ; WX 600 ; N parenright ; B 117 -102 444 616 ;
|
||||||
|
C 42 ; WX 600 ; N asterisk ; B 179 219 598 601 ;
|
||||||
|
C 43 ; WX 600 ; N plus ; B 114 39 596 478 ;
|
||||||
|
C 44 ; WX 600 ; N comma ; B 99 -111 430 174 ;
|
||||||
|
C 45 ; WX 600 ; N hyphen ; B 143 203 567 313 ;
|
||||||
|
C 173 ; WX 600 ; N hyphen ; B 143 203 567 313 ;
|
||||||
|
C 46 ; WX 600 ; N period ; B 206 -15 427 171 ;
|
||||||
|
C 47 ; WX 600 ; N slash ; B 90 -77 626 626 ;
|
||||||
|
C 48 ; WX 600 ; N zero ; B 135 -15 593 616 ;
|
||||||
|
C 49 ; WX 600 ; N one ; B 93 0 562 616 ;
|
||||||
|
C 50 ; WX 600 ; N two ; B 61 0 594 616 ;
|
||||||
|
C 51 ; WX 600 ; N three ; B 71 -15 571 616 ;
|
||||||
|
C 52 ; WX 600 ; N four ; B 81 0 559 616 ;
|
||||||
|
C 53 ; WX 600 ; N five ; B 77 -15 621 601 ;
|
||||||
|
C 54 ; WX 600 ; N six ; B 135 -15 652 616 ;
|
||||||
|
C 55 ; WX 600 ; N seven ; B 147 0 622 601 ;
|
||||||
|
C 56 ; WX 600 ; N eight ; B 115 -15 604 616 ;
|
||||||
|
C 57 ; WX 600 ; N nine ; B 75 -15 592 616 ;
|
||||||
|
C 58 ; WX 600 ; N colon ; B 205 -15 480 425 ;
|
||||||
|
C 59 ; WX 600 ; N semicolon ; B 99 -111 481 425 ;
|
||||||
|
C 60 ; WX 600 ; N less ; B 120 15 613 501 ;
|
||||||
|
C 61 ; WX 600 ; N equal ; B 96 118 614 398 ;
|
||||||
|
C 62 ; WX 600 ; N greater ; B 97 15 589 501 ;
|
||||||
|
C 63 ; WX 600 ; N question ; B 183 -14 592 580 ;
|
||||||
|
C 64 ; WX 600 ; N at ; B 65 -15 642 616 ;
|
||||||
|
C 65 ; WX 600 ; N A ; B -9 0 632 562 ;
|
||||||
|
C 66 ; WX 600 ; N B ; B 30 0 630 562 ;
|
||||||
|
C 67 ; WX 600 ; N C ; B 74 -18 675 580 ;
|
||||||
|
C 68 ; WX 600 ; N D ; B 30 0 664 562 ;
|
||||||
|
C 69 ; WX 600 ; N E ; B 25 0 670 562 ;
|
||||||
|
C 70 ; WX 600 ; N F ; B 39 0 684 562 ;
|
||||||
|
C 71 ; WX 600 ; N G ; B 74 -18 675 580 ;
|
||||||
|
C 72 ; WX 600 ; N H ; B 20 0 700 562 ;
|
||||||
|
C 73 ; WX 600 ; N I ; B 77 0 643 562 ;
|
||||||
|
C 74 ; WX 600 ; N J ; B 58 -18 721 562 ;
|
||||||
|
C 75 ; WX 600 ; N K ; B 21 0 692 562 ;
|
||||||
|
C 76 ; WX 600 ; N L ; B 39 0 636 562 ;
|
||||||
|
C 77 ; WX 600 ; N M ; B -2 0 722 562 ;
|
||||||
|
C 78 ; WX 600 ; N N ; B 8 -12 730 562 ;
|
||||||
|
C 79 ; WX 600 ; N O ; B 74 -18 645 580 ;
|
||||||
|
C 80 ; WX 600 ; N P ; B 48 0 643 562 ;
|
||||||
|
C 81 ; WX 600 ; N Q ; B 83 -138 636 580 ;
|
||||||
|
C 82 ; WX 600 ; N R ; B 24 0 617 562 ;
|
||||||
|
C 83 ; WX 600 ; N S ; B 54 -22 673 582 ;
|
||||||
|
C 84 ; WX 600 ; N T ; B 86 0 679 562 ;
|
||||||
|
C 85 ; WX 600 ; N U ; B 101 -18 716 562 ;
|
||||||
|
C 86 ; WX 600 ; N V ; B 84 0 733 562 ;
|
||||||
|
C 87 ; WX 600 ; N W ; B 79 0 738 562 ;
|
||||||
|
C 88 ; WX 600 ; N X ; B 12 0 690 562 ;
|
||||||
|
C 89 ; WX 600 ; N Y ; B 109 0 709 562 ;
|
||||||
|
C 90 ; WX 600 ; N Z ; B 62 0 637 562 ;
|
||||||
|
C 91 ; WX 600 ; N bracketleft ; B 223 -102 606 616 ;
|
||||||
|
C 92 ; WX 600 ; N backslash ; B 222 -77 496 626 ;
|
||||||
|
C 93 ; WX 600 ; N bracketright ; B 103 -102 486 616 ;
|
||||||
|
C 94 ; WX 600 ; N asciicircum ; B 171 250 556 616 ;
|
||||||
|
C 95 ; WX 600 ; N underscore ; B -27 -125 585 -75 ;
|
||||||
|
C 145 ; WX 600 ; N quoteleft ; B 297 277 487 562 ;
|
||||||
|
C 97 ; WX 600 ; N a ; B 61 -15 593 454 ;
|
||||||
|
C 98 ; WX 600 ; N b ; B 13 -15 636 626 ;
|
||||||
|
C 99 ; WX 600 ; N c ; B 81 -15 631 459 ;
|
||||||
|
C 100 ; WX 600 ; N d ; B 60 -15 645 626 ;
|
||||||
|
C 101 ; WX 600 ; N e ; B 81 -15 605 454 ;
|
||||||
|
C 102 ; WX 600 ; N f ; B 83 0 677 626 ; L i fi ; L l fl ;
|
||||||
|
C 103 ; WX 600 ; N g ; B 40 -146 674 454 ;
|
||||||
|
C 104 ; WX 600 ; N h ; B 18 0 615 626 ;
|
||||||
|
C 105 ; WX 600 ; N i ; B 77 0 546 658 ;
|
||||||
|
C 106 ; WX 600 ; N j ; B 36 -146 580 658 ;
|
||||||
|
C 107 ; WX 600 ; N k ; B 33 0 643 626 ;
|
||||||
|
C 108 ; WX 600 ; N l ; B 77 0 546 626 ;
|
||||||
|
C 109 ; WX 600 ; N m ; B -22 0 649 454 ;
|
||||||
|
C 110 ; WX 600 ; N n ; B 18 0 615 454 ;
|
||||||
|
C 111 ; WX 600 ; N o ; B 71 -15 622 454 ;
|
||||||
|
C 112 ; WX 600 ; N p ; B -32 -142 622 454 ;
|
||||||
|
C 113 ; WX 600 ; N q ; B 60 -142 685 454 ;
|
||||||
|
C 114 ; WX 600 ; N r ; B 47 0 655 454 ;
|
||||||
|
C 115 ; WX 600 ; N s ; B 66 -17 608 459 ;
|
||||||
|
C 116 ; WX 600 ; N t ; B 118 -15 567 562 ;
|
||||||
|
C 117 ; WX 600 ; N u ; B 70 -15 592 439 ;
|
||||||
|
C 118 ; WX 600 ; N v ; B 70 0 695 439 ;
|
||||||
|
C 119 ; WX 600 ; N w ; B 53 0 712 439 ;
|
||||||
|
C 120 ; WX 600 ; N x ; B 6 0 671 439 ;
|
||||||
|
C 121 ; WX 600 ; N y ; B -21 -142 695 439 ;
|
||||||
|
C 122 ; WX 600 ; N z ; B 81 0 614 439 ;
|
||||||
|
C 123 ; WX 600 ; N braceleft ; B 203 -102 595 616 ;
|
||||||
|
C 124 ; WX 600 ; N bar ; B 201 -250 505 750 ;
|
||||||
|
C 125 ; WX 600 ; N braceright ; B 114 -102 506 616 ;
|
||||||
|
C 126 ; WX 600 ; N asciitilde ; B 120 153 590 356 ;
|
||||||
|
C 161 ; WX 600 ; N exclamdown ; B 196 -146 477 449 ;
|
||||||
|
C 162 ; WX 600 ; N cent ; B 121 -49 605 614 ;
|
||||||
|
C 163 ; WX 600 ; N sterling ; B 106 -28 650 611 ;
|
||||||
|
C -1 ; WX 600 ; N fraction ; B 22 -60 708 661 ;
|
||||||
|
C 165 ; WX 600 ; N yen ; B 98 0 710 562 ;
|
||||||
|
C 131 ; WX 600 ; N florin ; B -57 -131 702 616 ;
|
||||||
|
C 167 ; WX 600 ; N section ; B 74 -70 620 580 ;
|
||||||
|
C 164 ; WX 600 ; N currency ; B 77 49 644 517 ;
|
||||||
|
C 39 ; WX 600 ; N quotesingle ; B 303 277 493 562 ;
|
||||||
|
C 147 ; WX 600 ; N quotedblleft ; B 190 277 594 562 ;
|
||||||
|
C 171 ; WX 600 ; N guillemotleft ; B 62 70 639 446 ;
|
||||||
|
C 139 ; WX 600 ; N guilsinglleft ; B 195 70 545 446 ;
|
||||||
|
C 155 ; WX 600 ; N guilsinglright ; B 165 70 514 446 ;
|
||||||
|
C -1 ; WX 600 ; N fi ; B 12 0 644 626 ;
|
||||||
|
C -1 ; WX 600 ; N fl ; B 12 0 644 626 ;
|
||||||
|
C 150 ; WX 600 ; N endash ; B 108 203 602 313 ;
|
||||||
|
C 134 ; WX 600 ; N dagger ; B 175 -70 586 580 ;
|
||||||
|
C 135 ; WX 600 ; N daggerdbl ; B 121 -70 587 580 ;
|
||||||
|
C 183 ; WX 600 ; N periodcentered ; B 248 165 461 351 ;
|
||||||
|
C 182 ; WX 600 ; N paragraph ; B 61 -70 700 580 ;
|
||||||
|
C 149 ; WX 600 ; N bullet ; B 196 132 523 430 ;
|
||||||
|
C 130 ; WX 600 ; N quotesinglbase ; B 144 -142 458 143 ;
|
||||||
|
C 132 ; WX 600 ; N quotedblbase ; B 34 -142 560 143 ;
|
||||||
|
C 148 ; WX 600 ; N quotedblright ; B 119 277 645 562 ;
|
||||||
|
C 187 ; WX 600 ; N guillemotright ; B 71 70 647 446 ;
|
||||||
|
C 133 ; WX 600 ; N ellipsis ; B 35 -15 587 116 ;
|
||||||
|
C 137 ; WX 600 ; N perthousand ; B -45 -15 743 616 ;
|
||||||
|
C 191 ; WX 600 ; N questiondown ; B 100 -146 509 449 ;
|
||||||
|
C 96 ; WX 600 ; N grave ; B 272 508 503 661 ;
|
||||||
|
C 180 ; WX 600 ; N acute ; B 312 508 609 661 ;
|
||||||
|
C 136 ; WX 600 ; N circumflex ; B 212 483 607 657 ;
|
||||||
|
C 152 ; WX 600 ; N tilde ; B 199 493 643 636 ;
|
||||||
|
C 175 ; WX 600 ; N macron ; B 195 505 637 585 ;
|
||||||
|
C -1 ; WX 600 ; N breve ; B 217 468 652 631 ;
|
||||||
|
C -1 ; WX 600 ; N dotaccent ; B 348 498 493 638 ;
|
||||||
|
C 168 ; WX 600 ; N dieresis ; B 246 498 595 638 ;
|
||||||
|
C -1 ; WX 600 ; N ring ; B 319 481 528 678 ;
|
||||||
|
C 184 ; WX 600 ; N cedilla ; B 168 -206 368 0 ;
|
||||||
|
C -1 ; WX 600 ; N hungarumlaut ; B 171 488 729 661 ;
|
||||||
|
C -1 ; WX 600 ; N ogonek ; B 143 -199 367 0 ;
|
||||||
|
C -1 ; WX 600 ; N caron ; B 238 493 633 667 ;
|
||||||
|
C 151 ; WX 600 ; N emdash ; B 33 203 677 313 ;
|
||||||
|
C 198 ; WX 600 ; N AE ; B -29 0 708 562 ;
|
||||||
|
C 170 ; WX 600 ; N ordfeminine ; B 188 196 526 580 ;
|
||||||
|
C -1 ; WX 600 ; N Lslash ; B 39 0 636 562 ;
|
||||||
|
C 216 ; WX 600 ; N Oslash ; B 48 -22 673 584 ;
|
||||||
|
C 140 ; WX 600 ; N OE ; B 26 0 701 562 ;
|
||||||
|
C 186 ; WX 600 ; N ordmasculine ; B 188 196 543 580 ;
|
||||||
|
C 230 ; WX 600 ; N ae ; B 21 -15 652 454 ;
|
||||||
|
C -1 ; WX 600 ; N dotlessi ; B 77 0 546 439 ;
|
||||||
|
C -1 ; WX 600 ; N lslash ; B 77 0 587 626 ;
|
||||||
|
C 248 ; WX 600 ; N oslash ; B 54 -24 638 463 ;
|
||||||
|
C 156 ; WX 600 ; N oe ; B 18 -15 662 454 ;
|
||||||
|
C 223 ; WX 600 ; N germandbls ; B 22 -15 629 626 ;
|
||||||
|
C 207 ; WX 600 ; N Idieresis ; B 77 0 643 761 ;
|
||||||
|
C 233 ; WX 600 ; N eacute ; B 81 -15 609 661 ;
|
||||||
|
C -1 ; WX 600 ; N abreve ; B 61 -15 658 661 ;
|
||||||
|
C -1 ; WX 600 ; N uhungarumlaut ; B 70 -15 769 661 ;
|
||||||
|
C -1 ; WX 600 ; N ecaron ; B 81 -15 633 667 ;
|
||||||
|
C 159 ; WX 600 ; N Ydieresis ; B 109 0 709 761 ;
|
||||||
|
C 247 ; WX 600 ; N divide ; B 114 16 596 500 ;
|
||||||
|
C 221 ; WX 600 ; N Yacute ; B 109 0 709 784 ;
|
||||||
|
C 194 ; WX 600 ; N Acircumflex ; B -9 0 632 780 ;
|
||||||
|
C 225 ; WX 600 ; N aacute ; B 61 -15 609 661 ;
|
||||||
|
C 219 ; WX 600 ; N Ucircumflex ; B 101 -18 716 780 ;
|
||||||
|
C 253 ; WX 600 ; N yacute ; B -21 -142 695 661 ;
|
||||||
|
C -1 ; WX 600 ; N scommaaccent ; B 66 -250 608 459 ;
|
||||||
|
C 234 ; WX 600 ; N ecircumflex ; B 81 -15 607 657 ;
|
||||||
|
C -1 ; WX 600 ; N Uring ; B 101 -18 716 801 ;
|
||||||
|
C 220 ; WX 600 ; N Udieresis ; B 101 -18 716 761 ;
|
||||||
|
C -1 ; WX 600 ; N aogonek ; B 61 -199 593 454 ;
|
||||||
|
C 218 ; WX 600 ; N Uacute ; B 101 -18 716 784 ;
|
||||||
|
C -1 ; WX 600 ; N uogonek ; B 70 -199 592 439 ;
|
||||||
|
C 203 ; WX 600 ; N Edieresis ; B 25 0 670 761 ;
|
||||||
|
C -1 ; WX 600 ; N Dcroat ; B 30 0 664 562 ;
|
||||||
|
C -1 ; WX 600 ; N commaaccent ; B 151 -250 385 -57 ;
|
||||||
|
C 169 ; WX 600 ; N copyright ; B 53 -18 667 580 ;
|
||||||
|
C -1 ; WX 600 ; N Emacron ; B 25 0 670 708 ;
|
||||||
|
C -1 ; WX 600 ; N ccaron ; B 81 -15 633 667 ;
|
||||||
|
C 229 ; WX 600 ; N aring ; B 61 -15 593 678 ;
|
||||||
|
C -1 ; WX 600 ; N Ncommaaccent ; B 8 -250 730 562 ;
|
||||||
|
C -1 ; WX 600 ; N lacute ; B 77 0 639 801 ;
|
||||||
|
C 224 ; WX 600 ; N agrave ; B 61 -15 593 661 ;
|
||||||
|
C -1 ; WX 600 ; N Tcommaaccent ; B 86 -250 679 562 ;
|
||||||
|
C -1 ; WX 600 ; N Cacute ; B 74 -18 675 784 ;
|
||||||
|
C 227 ; WX 600 ; N atilde ; B 61 -15 643 636 ;
|
||||||
|
C -1 ; WX 600 ; N Edotaccent ; B 25 0 670 761 ;
|
||||||
|
C 154 ; WX 600 ; N scaron ; B 66 -17 633 667 ;
|
||||||
|
C -1 ; WX 600 ; N scedilla ; B 66 -206 608 459 ;
|
||||||
|
C 237 ; WX 600 ; N iacute ; B 77 0 609 661 ;
|
||||||
|
C -1 ; WX 600 ; N lozenge ; B 145 0 614 740 ;
|
||||||
|
C -1 ; WX 600 ; N Rcaron ; B 24 0 659 790 ;
|
||||||
|
C -1 ; WX 600 ; N Gcommaaccent ; B 74 -250 675 580 ;
|
||||||
|
C 251 ; WX 600 ; N ucircumflex ; B 70 -15 597 657 ;
|
||||||
|
C 226 ; WX 600 ; N acircumflex ; B 61 -15 607 657 ;
|
||||||
|
C -1 ; WX 600 ; N Amacron ; B -9 0 633 708 ;
|
||||||
|
C -1 ; WX 600 ; N rcaron ; B 47 0 655 667 ;
|
||||||
|
C 231 ; WX 600 ; N ccedilla ; B 81 -206 631 459 ;
|
||||||
|
C -1 ; WX 600 ; N Zdotaccent ; B 62 0 637 761 ;
|
||||||
|
C 222 ; WX 600 ; N Thorn ; B 48 0 620 562 ;
|
||||||
|
C -1 ; WX 600 ; N Omacron ; B 74 -18 663 708 ;
|
||||||
|
C -1 ; WX 600 ; N Racute ; B 24 0 665 784 ;
|
||||||
|
C -1 ; WX 600 ; N Sacute ; B 54 -22 673 784 ;
|
||||||
|
C -1 ; WX 600 ; N dcaron ; B 60 -15 861 626 ;
|
||||||
|
C -1 ; WX 600 ; N Umacron ; B 101 -18 716 708 ;
|
||||||
|
C -1 ; WX 600 ; N uring ; B 70 -15 592 678 ;
|
||||||
|
C 179 ; WX 600 ; N threesuperior ; B 193 222 526 616 ;
|
||||||
|
C 210 ; WX 600 ; N Ograve ; B 74 -18 645 784 ;
|
||||||
|
C 192 ; WX 600 ; N Agrave ; B -9 0 632 784 ;
|
||||||
|
C -1 ; WX 600 ; N Abreve ; B -9 0 684 784 ;
|
||||||
|
C 215 ; WX 600 ; N multiply ; B 104 39 606 478 ;
|
||||||
|
C 250 ; WX 600 ; N uacute ; B 70 -15 599 661 ;
|
||||||
|
C -1 ; WX 600 ; N Tcaron ; B 86 0 679 790 ;
|
||||||
|
C -1 ; WX 600 ; N partialdiff ; B 91 -38 627 728 ;
|
||||||
|
C 255 ; WX 600 ; N ydieresis ; B -21 -142 695 638 ;
|
||||||
|
C -1 ; WX 600 ; N Nacute ; B 8 -12 730 784 ;
|
||||||
|
C 238 ; WX 600 ; N icircumflex ; B 77 0 577 657 ;
|
||||||
|
C 202 ; WX 600 ; N Ecircumflex ; B 25 0 670 780 ;
|
||||||
|
C 228 ; WX 600 ; N adieresis ; B 61 -15 595 638 ;
|
||||||
|
C 235 ; WX 600 ; N edieresis ; B 81 -15 605 638 ;
|
||||||
|
C -1 ; WX 600 ; N cacute ; B 81 -15 649 661 ;
|
||||||
|
C -1 ; WX 600 ; N nacute ; B 18 0 639 661 ;
|
||||||
|
C -1 ; WX 600 ; N umacron ; B 70 -15 637 585 ;
|
||||||
|
C -1 ; WX 600 ; N Ncaron ; B 8 -12 730 790 ;
|
||||||
|
C 205 ; WX 600 ; N Iacute ; B 77 0 643 784 ;
|
||||||
|
C 177 ; WX 600 ; N plusminus ; B 76 24 614 515 ;
|
||||||
|
C 166 ; WX 600 ; N brokenbar ; B 217 -175 489 675 ;
|
||||||
|
C 174 ; WX 600 ; N registered ; B 53 -18 667 580 ;
|
||||||
|
C -1 ; WX 600 ; N Gbreve ; B 74 -18 684 784 ;
|
||||||
|
C -1 ; WX 600 ; N Idotaccent ; B 77 0 643 761 ;
|
||||||
|
C -1 ; WX 600 ; N summation ; B 15 -10 672 706 ;
|
||||||
|
C 200 ; WX 600 ; N Egrave ; B 25 0 670 784 ;
|
||||||
|
C -1 ; WX 600 ; N racute ; B 47 0 655 661 ;
|
||||||
|
C -1 ; WX 600 ; N omacron ; B 71 -15 637 585 ;
|
||||||
|
C -1 ; WX 600 ; N Zacute ; B 62 0 665 784 ;
|
||||||
|
C 142 ; WX 600 ; N Zcaron ; B 62 0 659 790 ;
|
||||||
|
C -1 ; WX 600 ; N greaterequal ; B 26 0 627 696 ;
|
||||||
|
C 208 ; WX 600 ; N Eth ; B 30 0 664 562 ;
|
||||||
|
C 199 ; WX 600 ; N Ccedilla ; B 74 -206 675 580 ;
|
||||||
|
C -1 ; WX 600 ; N lcommaaccent ; B 77 -250 546 626 ;
|
||||||
|
C -1 ; WX 600 ; N tcaron ; B 118 -15 627 703 ;
|
||||||
|
C -1 ; WX 600 ; N eogonek ; B 81 -199 605 454 ;
|
||||||
|
C -1 ; WX 600 ; N Uogonek ; B 101 -199 716 562 ;
|
||||||
|
C 193 ; WX 600 ; N Aacute ; B -9 0 655 784 ;
|
||||||
|
C 196 ; WX 600 ; N Adieresis ; B -9 0 632 761 ;
|
||||||
|
C 232 ; WX 600 ; N egrave ; B 81 -15 605 661 ;
|
||||||
|
C -1 ; WX 600 ; N zacute ; B 81 0 614 661 ;
|
||||||
|
C -1 ; WX 600 ; N iogonek ; B 77 -199 546 658 ;
|
||||||
|
C 211 ; WX 600 ; N Oacute ; B 74 -18 645 784 ;
|
||||||
|
C 243 ; WX 600 ; N oacute ; B 71 -15 649 661 ;
|
||||||
|
C -1 ; WX 600 ; N amacron ; B 61 -15 637 585 ;
|
||||||
|
C -1 ; WX 600 ; N sacute ; B 66 -17 609 661 ;
|
||||||
|
C 239 ; WX 600 ; N idieresis ; B 77 0 561 618 ;
|
||||||
|
C 212 ; WX 600 ; N Ocircumflex ; B 74 -18 645 780 ;
|
||||||
|
C 217 ; WX 600 ; N Ugrave ; B 101 -18 716 784 ;
|
||||||
|
C -1 ; WX 600 ; N Delta ; B 6 0 594 688 ;
|
||||||
|
C 254 ; WX 600 ; N thorn ; B -32 -142 622 626 ;
|
||||||
|
C 178 ; WX 600 ; N twosuperior ; B 191 230 542 616 ;
|
||||||
|
C 214 ; WX 600 ; N Odieresis ; B 74 -18 645 761 ;
|
||||||
|
C 181 ; WX 600 ; N mu ; B 49 -142 592 439 ;
|
||||||
|
C 236 ; WX 600 ; N igrave ; B 77 0 546 661 ;
|
||||||
|
C -1 ; WX 600 ; N ohungarumlaut ; B 71 -15 809 661 ;
|
||||||
|
C -1 ; WX 600 ; N Eogonek ; B 25 -199 670 562 ;
|
||||||
|
C -1 ; WX 600 ; N dcroat ; B 60 -15 712 626 ;
|
||||||
|
C 190 ; WX 600 ; N threequarters ; B 8 -60 699 661 ;
|
||||||
|
C -1 ; WX 600 ; N Scedilla ; B 54 -206 673 582 ;
|
||||||
|
C -1 ; WX 600 ; N lcaron ; B 77 0 731 626 ;
|
||||||
|
C -1 ; WX 600 ; N Kcommaaccent ; B 21 -250 692 562 ;
|
||||||
|
C -1 ; WX 600 ; N Lacute ; B 39 0 636 784 ;
|
||||||
|
C 153 ; WX 600 ; N trademark ; B 86 230 869 562 ;
|
||||||
|
C -1 ; WX 600 ; N edotaccent ; B 81 -15 605 638 ;
|
||||||
|
C 204 ; WX 600 ; N Igrave ; B 77 0 643 784 ;
|
||||||
|
C -1 ; WX 600 ; N Imacron ; B 77 0 663 708 ;
|
||||||
|
C -1 ; WX 600 ; N Lcaron ; B 39 0 757 562 ;
|
||||||
|
C 189 ; WX 600 ; N onehalf ; B 22 -60 716 661 ;
|
||||||
|
C -1 ; WX 600 ; N lessequal ; B 26 0 671 696 ;
|
||||||
|
C 244 ; WX 600 ; N ocircumflex ; B 71 -15 622 657 ;
|
||||||
|
C 241 ; WX 600 ; N ntilde ; B 18 0 643 636 ;
|
||||||
|
C -1 ; WX 600 ; N Uhungarumlaut ; B 101 -18 805 784 ;
|
||||||
|
C 201 ; WX 600 ; N Eacute ; B 25 0 670 784 ;
|
||||||
|
C -1 ; WX 600 ; N emacron ; B 81 -15 637 585 ;
|
||||||
|
C -1 ; WX 600 ; N gbreve ; B 40 -146 674 661 ;
|
||||||
|
C 188 ; WX 600 ; N onequarter ; B 13 -60 707 661 ;
|
||||||
|
C 138 ; WX 600 ; N Scaron ; B 54 -22 689 790 ;
|
||||||
|
C -1 ; WX 600 ; N Scommaaccent ; B 54 -250 673 582 ;
|
||||||
|
C -1 ; WX 600 ; N Ohungarumlaut ; B 74 -18 795 784 ;
|
||||||
|
C 176 ; WX 600 ; N degree ; B 173 243 570 616 ;
|
||||||
|
C 242 ; WX 600 ; N ograve ; B 71 -15 622 661 ;
|
||||||
|
C -1 ; WX 600 ; N Ccaron ; B 74 -18 689 790 ;
|
||||||
|
C 249 ; WX 600 ; N ugrave ; B 70 -15 592 661 ;
|
||||||
|
C -1 ; WX 600 ; N radical ; B 67 -104 635 778 ;
|
||||||
|
C -1 ; WX 600 ; N Dcaron ; B 30 0 664 790 ;
|
||||||
|
C -1 ; WX 600 ; N rcommaaccent ; B 47 -250 655 454 ;
|
||||||
|
C 209 ; WX 600 ; N Ntilde ; B 8 -12 730 759 ;
|
||||||
|
C 245 ; WX 600 ; N otilde ; B 71 -15 643 636 ;
|
||||||
|
C -1 ; WX 600 ; N Rcommaaccent ; B 24 -250 617 562 ;
|
||||||
|
C -1 ; WX 600 ; N Lcommaaccent ; B 39 -250 636 562 ;
|
||||||
|
C 195 ; WX 600 ; N Atilde ; B -9 0 669 759 ;
|
||||||
|
C -1 ; WX 600 ; N Aogonek ; B -9 -199 632 562 ;
|
||||||
|
C 197 ; WX 600 ; N Aring ; B -9 0 632 801 ;
|
||||||
|
C 213 ; WX 600 ; N Otilde ; B 74 -18 669 759 ;
|
||||||
|
C -1 ; WX 600 ; N zdotaccent ; B 81 0 614 638 ;
|
||||||
|
C -1 ; WX 600 ; N Ecaron ; B 25 0 670 790 ;
|
||||||
|
C -1 ; WX 600 ; N Iogonek ; B 77 -199 643 562 ;
|
||||||
|
C -1 ; WX 600 ; N kcommaaccent ; B 33 -250 643 626 ;
|
||||||
|
C -1 ; WX 600 ; N minus ; B 114 203 596 313 ;
|
||||||
|
C 206 ; WX 600 ; N Icircumflex ; B 77 0 643 780 ;
|
||||||
|
C -1 ; WX 600 ; N ncaron ; B 18 0 633 667 ;
|
||||||
|
C -1 ; WX 600 ; N tcommaaccent ; B 118 -250 567 562 ;
|
||||||
|
C 172 ; WX 600 ; N logicalnot ; B 135 103 617 413 ;
|
||||||
|
C 246 ; WX 600 ; N odieresis ; B 71 -15 622 638 ;
|
||||||
|
C 252 ; WX 600 ; N udieresis ; B 70 -15 595 638 ;
|
||||||
|
C -1 ; WX 600 ; N notequal ; B 30 -47 626 563 ;
|
||||||
|
C -1 ; WX 600 ; N gcommaaccent ; B 40 -146 674 714 ;
|
||||||
|
C 240 ; WX 600 ; N eth ; B 93 -27 661 626 ;
|
||||||
|
C 158 ; WX 600 ; N zcaron ; B 81 0 643 667 ;
|
||||||
|
C -1 ; WX 600 ; N ncommaaccent ; B 18 -250 615 454 ;
|
||||||
|
C 185 ; WX 600 ; N onesuperior ; B 212 230 514 616 ;
|
||||||
|
C -1 ; WX 600 ; N imacron ; B 77 0 575 585 ;
|
||||||
|
C 128 ; WX 600 ; N Euro ; B 0 0 0 0 ;
|
||||||
|
EndCharMetrics
|
||||||
|
EndFontMetrics
|
||||||
344
vendor/dompdf/dompdf/lib/fonts/Courier-Oblique.afm
vendored
Normal file
@ -0,0 +1,344 @@
|
|||||||
|
StartFontMetrics 4.1
|
||||||
|
Comment Copyright (c) 1989, 1990, 1991, 1992, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
|
||||||
|
Comment Creation Date: Thu May 0:00:00 17:37:52 1997
|
||||||
|
Comment UniqueID 43051
|
||||||
|
Comment VMusage 16248 75829
|
||||||
|
FontName Courier-Oblique
|
||||||
|
FullName Courier Oblique
|
||||||
|
FamilyName Courier
|
||||||
|
Weight Medium
|
||||||
|
ItalicAngle -12
|
||||||
|
IsFixedPitch true
|
||||||
|
CharacterSet ExtendedRoman
|
||||||
|
FontBBox -27 -250 849 805
|
||||||
|
UnderlinePosition -100
|
||||||
|
UnderlineThickness 50
|
||||||
|
Version 003.000
|
||||||
|
Notice Copyright (c) 1989, 1990, 1991, 1992, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
|
||||||
|
EncodingScheme WinAnsiEncoding
|
||||||
|
CapHeight 562
|
||||||
|
XHeight 426
|
||||||
|
Ascender 629
|
||||||
|
Descender -157
|
||||||
|
StdHW 51
|
||||||
|
StdVW 51
|
||||||
|
StartCharMetrics 317
|
||||||
|
C 32 ; WX 600 ; N space ; B 0 0 0 0 ;
|
||||||
|
C 160 ; WX 600 ; N space ; B 0 0 0 0 ;
|
||||||
|
C 33 ; WX 600 ; N exclam ; B 243 -15 464 572 ;
|
||||||
|
C 34 ; WX 600 ; N quotedbl ; B 273 328 532 562 ;
|
||||||
|
C 35 ; WX 600 ; N numbersign ; B 133 -32 596 639 ;
|
||||||
|
C 36 ; WX 600 ; N dollar ; B 108 -126 596 662 ;
|
||||||
|
C 37 ; WX 600 ; N percent ; B 134 -15 599 622 ;
|
||||||
|
C 38 ; WX 600 ; N ampersand ; B 87 -15 580 543 ;
|
||||||
|
C 146 ; WX 600 ; N quoteright ; B 283 328 495 562 ;
|
||||||
|
C 40 ; WX 600 ; N parenleft ; B 313 -108 572 622 ;
|
||||||
|
C 41 ; WX 600 ; N parenright ; B 137 -108 396 622 ;
|
||||||
|
C 42 ; WX 600 ; N asterisk ; B 212 257 580 607 ;
|
||||||
|
C 43 ; WX 600 ; N plus ; B 129 44 580 470 ;
|
||||||
|
C 44 ; WX 600 ; N comma ; B 157 -112 370 122 ;
|
||||||
|
C 45 ; WX 600 ; N hyphen ; B 152 231 558 285 ;
|
||||||
|
C 173 ; WX 600 ; N hyphen ; B 152 231 558 285 ;
|
||||||
|
C 46 ; WX 600 ; N period ; B 238 -15 382 109 ;
|
||||||
|
C 47 ; WX 600 ; N slash ; B 112 -80 604 629 ;
|
||||||
|
C 48 ; WX 600 ; N zero ; B 154 -15 575 622 ;
|
||||||
|
C 49 ; WX 600 ; N one ; B 98 0 515 622 ;
|
||||||
|
C 50 ; WX 600 ; N two ; B 70 0 568 622 ;
|
||||||
|
C 51 ; WX 600 ; N three ; B 82 -15 538 622 ;
|
||||||
|
C 52 ; WX 600 ; N four ; B 108 0 541 622 ;
|
||||||
|
C 53 ; WX 600 ; N five ; B 99 -15 589 607 ;
|
||||||
|
C 54 ; WX 600 ; N six ; B 155 -15 629 622 ;
|
||||||
|
C 55 ; WX 600 ; N seven ; B 182 0 612 607 ;
|
||||||
|
C 56 ; WX 600 ; N eight ; B 132 -15 588 622 ;
|
||||||
|
C 57 ; WX 600 ; N nine ; B 93 -15 574 622 ;
|
||||||
|
C 58 ; WX 600 ; N colon ; B 238 -15 441 385 ;
|
||||||
|
C 59 ; WX 600 ; N semicolon ; B 157 -112 441 385 ;
|
||||||
|
C 60 ; WX 600 ; N less ; B 96 42 610 472 ;
|
||||||
|
C 61 ; WX 600 ; N equal ; B 109 138 600 376 ;
|
||||||
|
C 62 ; WX 600 ; N greater ; B 85 42 599 472 ;
|
||||||
|
C 63 ; WX 600 ; N question ; B 222 -15 583 572 ;
|
||||||
|
C 64 ; WX 600 ; N at ; B 127 -15 582 622 ;
|
||||||
|
C 65 ; WX 600 ; N A ; B 3 0 607 562 ;
|
||||||
|
C 66 ; WX 600 ; N B ; B 43 0 616 562 ;
|
||||||
|
C 67 ; WX 600 ; N C ; B 93 -18 655 580 ;
|
||||||
|
C 68 ; WX 600 ; N D ; B 43 0 645 562 ;
|
||||||
|
C 69 ; WX 600 ; N E ; B 53 0 660 562 ;
|
||||||
|
C 70 ; WX 600 ; N F ; B 53 0 660 562 ;
|
||||||
|
C 71 ; WX 600 ; N G ; B 83 -18 645 580 ;
|
||||||
|
C 72 ; WX 600 ; N H ; B 32 0 687 562 ;
|
||||||
|
C 73 ; WX 600 ; N I ; B 96 0 623 562 ;
|
||||||
|
C 74 ; WX 600 ; N J ; B 52 -18 685 562 ;
|
||||||
|
C 75 ; WX 600 ; N K ; B 38 0 671 562 ;
|
||||||
|
C 76 ; WX 600 ; N L ; B 47 0 607 562 ;
|
||||||
|
C 77 ; WX 600 ; N M ; B 4 0 715 562 ;
|
||||||
|
C 78 ; WX 600 ; N N ; B 7 -13 712 562 ;
|
||||||
|
C 79 ; WX 600 ; N O ; B 94 -18 625 580 ;
|
||||||
|
C 80 ; WX 600 ; N P ; B 79 0 644 562 ;
|
||||||
|
C 81 ; WX 600 ; N Q ; B 95 -138 625 580 ;
|
||||||
|
C 82 ; WX 600 ; N R ; B 38 0 598 562 ;
|
||||||
|
C 83 ; WX 600 ; N S ; B 76 -20 650 580 ;
|
||||||
|
C 84 ; WX 600 ; N T ; B 108 0 665 562 ;
|
||||||
|
C 85 ; WX 600 ; N U ; B 125 -18 702 562 ;
|
||||||
|
C 86 ; WX 600 ; N V ; B 105 -13 723 562 ;
|
||||||
|
C 87 ; WX 600 ; N W ; B 106 -13 722 562 ;
|
||||||
|
C 88 ; WX 600 ; N X ; B 23 0 675 562 ;
|
||||||
|
C 89 ; WX 600 ; N Y ; B 133 0 695 562 ;
|
||||||
|
C 90 ; WX 600 ; N Z ; B 86 0 610 562 ;
|
||||||
|
C 91 ; WX 600 ; N bracketleft ; B 246 -108 574 622 ;
|
||||||
|
C 92 ; WX 600 ; N backslash ; B 249 -80 468 629 ;
|
||||||
|
C 93 ; WX 600 ; N bracketright ; B 135 -108 463 622 ;
|
||||||
|
C 94 ; WX 600 ; N asciicircum ; B 175 354 587 622 ;
|
||||||
|
C 95 ; WX 600 ; N underscore ; B -27 -125 584 -75 ;
|
||||||
|
C 145 ; WX 600 ; N quoteleft ; B 343 328 457 562 ;
|
||||||
|
C 97 ; WX 600 ; N a ; B 76 -15 569 441 ;
|
||||||
|
C 98 ; WX 600 ; N b ; B 29 -15 625 629 ;
|
||||||
|
C 99 ; WX 600 ; N c ; B 106 -15 608 441 ;
|
||||||
|
C 100 ; WX 600 ; N d ; B 85 -15 640 629 ;
|
||||||
|
C 101 ; WX 600 ; N e ; B 106 -15 598 441 ;
|
||||||
|
C 102 ; WX 600 ; N f ; B 114 0 662 629 ; L i fi ; L l fl ;
|
||||||
|
C 103 ; WX 600 ; N g ; B 61 -157 657 441 ;
|
||||||
|
C 104 ; WX 600 ; N h ; B 33 0 592 629 ;
|
||||||
|
C 105 ; WX 600 ; N i ; B 95 0 515 657 ;
|
||||||
|
C 106 ; WX 600 ; N j ; B 52 -157 550 657 ;
|
||||||
|
C 107 ; WX 600 ; N k ; B 58 0 633 629 ;
|
||||||
|
C 108 ; WX 600 ; N l ; B 95 0 515 629 ;
|
||||||
|
C 109 ; WX 600 ; N m ; B -5 0 615 441 ;
|
||||||
|
C 110 ; WX 600 ; N n ; B 26 0 585 441 ;
|
||||||
|
C 111 ; WX 600 ; N o ; B 102 -15 588 441 ;
|
||||||
|
C 112 ; WX 600 ; N p ; B -24 -157 605 441 ;
|
||||||
|
C 113 ; WX 600 ; N q ; B 85 -157 682 441 ;
|
||||||
|
C 114 ; WX 600 ; N r ; B 60 0 636 441 ;
|
||||||
|
C 115 ; WX 600 ; N s ; B 78 -15 584 441 ;
|
||||||
|
C 116 ; WX 600 ; N t ; B 167 -15 561 561 ;
|
||||||
|
C 117 ; WX 600 ; N u ; B 101 -15 572 426 ;
|
||||||
|
C 118 ; WX 600 ; N v ; B 90 -10 681 426 ;
|
||||||
|
C 119 ; WX 600 ; N w ; B 76 -10 695 426 ;
|
||||||
|
C 120 ; WX 600 ; N x ; B 20 0 655 426 ;
|
||||||
|
C 121 ; WX 600 ; N y ; B -4 -157 683 426 ;
|
||||||
|
C 122 ; WX 600 ; N z ; B 99 0 593 426 ;
|
||||||
|
C 123 ; WX 600 ; N braceleft ; B 233 -108 569 622 ;
|
||||||
|
C 124 ; WX 600 ; N bar ; B 222 -250 485 750 ;
|
||||||
|
C 125 ; WX 600 ; N braceright ; B 140 -108 477 622 ;
|
||||||
|
C 126 ; WX 600 ; N asciitilde ; B 116 197 600 320 ;
|
||||||
|
C 161 ; WX 600 ; N exclamdown ; B 225 -157 445 430 ;
|
||||||
|
C 162 ; WX 600 ; N cent ; B 151 -49 588 614 ;
|
||||||
|
C 163 ; WX 600 ; N sterling ; B 124 -21 621 611 ;
|
||||||
|
C -1 ; WX 600 ; N fraction ; B 84 -57 646 665 ;
|
||||||
|
C 165 ; WX 600 ; N yen ; B 120 0 693 562 ;
|
||||||
|
C 131 ; WX 600 ; N florin ; B -26 -143 671 622 ;
|
||||||
|
C 167 ; WX 600 ; N section ; B 104 -78 590 580 ;
|
||||||
|
C 164 ; WX 600 ; N currency ; B 94 58 628 506 ;
|
||||||
|
C 39 ; WX 600 ; N quotesingle ; B 345 328 460 562 ;
|
||||||
|
C 147 ; WX 600 ; N quotedblleft ; B 262 328 541 562 ;
|
||||||
|
C 171 ; WX 600 ; N guillemotleft ; B 92 70 652 446 ;
|
||||||
|
C 139 ; WX 600 ; N guilsinglleft ; B 204 70 540 446 ;
|
||||||
|
C 155 ; WX 600 ; N guilsinglright ; B 170 70 506 446 ;
|
||||||
|
C -1 ; WX 600 ; N fi ; B 3 0 619 629 ;
|
||||||
|
C -1 ; WX 600 ; N fl ; B 3 0 619 629 ;
|
||||||
|
C 150 ; WX 600 ; N endash ; B 124 231 586 285 ;
|
||||||
|
C 134 ; WX 600 ; N dagger ; B 217 -78 546 580 ;
|
||||||
|
C 135 ; WX 600 ; N daggerdbl ; B 163 -78 546 580 ;
|
||||||
|
C 183 ; WX 600 ; N periodcentered ; B 275 189 434 327 ;
|
||||||
|
C 182 ; WX 600 ; N paragraph ; B 100 -78 630 562 ;
|
||||||
|
C 149 ; WX 600 ; N bullet ; B 224 130 485 383 ;
|
||||||
|
C 130 ; WX 600 ; N quotesinglbase ; B 185 -134 397 100 ;
|
||||||
|
C 132 ; WX 600 ; N quotedblbase ; B 115 -134 478 100 ;
|
||||||
|
C 148 ; WX 600 ; N quotedblright ; B 213 328 576 562 ;
|
||||||
|
C 187 ; WX 600 ; N guillemotright ; B 58 70 618 446 ;
|
||||||
|
C 133 ; WX 600 ; N ellipsis ; B 46 -15 575 111 ;
|
||||||
|
C 137 ; WX 600 ; N perthousand ; B 59 -15 627 622 ;
|
||||||
|
C 191 ; WX 600 ; N questiondown ; B 105 -157 466 430 ;
|
||||||
|
C 96 ; WX 600 ; N grave ; B 294 497 484 672 ;
|
||||||
|
C 180 ; WX 600 ; N acute ; B 348 497 612 672 ;
|
||||||
|
C 136 ; WX 600 ; N circumflex ; B 229 477 581 654 ;
|
||||||
|
C 152 ; WX 600 ; N tilde ; B 212 489 629 606 ;
|
||||||
|
C 175 ; WX 600 ; N macron ; B 232 525 600 565 ;
|
||||||
|
C -1 ; WX 600 ; N breve ; B 279 501 576 609 ;
|
||||||
|
C -1 ; WX 600 ; N dotaccent ; B 373 537 478 640 ;
|
||||||
|
C 168 ; WX 600 ; N dieresis ; B 272 537 579 640 ;
|
||||||
|
C -1 ; WX 600 ; N ring ; B 332 463 500 627 ;
|
||||||
|
C 184 ; WX 600 ; N cedilla ; B 197 -151 344 10 ;
|
||||||
|
C -1 ; WX 600 ; N hungarumlaut ; B 239 497 683 672 ;
|
||||||
|
C -1 ; WX 600 ; N ogonek ; B 189 -172 377 4 ;
|
||||||
|
C -1 ; WX 600 ; N caron ; B 262 492 614 669 ;
|
||||||
|
C 151 ; WX 600 ; N emdash ; B 49 231 661 285 ;
|
||||||
|
C 198 ; WX 600 ; N AE ; B 3 0 655 562 ;
|
||||||
|
C 170 ; WX 600 ; N ordfeminine ; B 209 249 512 580 ;
|
||||||
|
C -1 ; WX 600 ; N Lslash ; B 47 0 607 562 ;
|
||||||
|
C 216 ; WX 600 ; N Oslash ; B 94 -80 625 629 ;
|
||||||
|
C 140 ; WX 600 ; N OE ; B 59 0 672 562 ;
|
||||||
|
C 186 ; WX 600 ; N ordmasculine ; B 210 249 535 580 ;
|
||||||
|
C 230 ; WX 600 ; N ae ; B 41 -15 626 441 ;
|
||||||
|
C -1 ; WX 600 ; N dotlessi ; B 95 0 515 426 ;
|
||||||
|
C -1 ; WX 600 ; N lslash ; B 95 0 587 629 ;
|
||||||
|
C 248 ; WX 600 ; N oslash ; B 102 -80 588 506 ;
|
||||||
|
C 156 ; WX 600 ; N oe ; B 54 -15 615 441 ;
|
||||||
|
C 223 ; WX 600 ; N germandbls ; B 48 -15 617 629 ;
|
||||||
|
C 207 ; WX 600 ; N Idieresis ; B 96 0 623 753 ;
|
||||||
|
C 233 ; WX 600 ; N eacute ; B 106 -15 612 672 ;
|
||||||
|
C -1 ; WX 600 ; N abreve ; B 76 -15 576 609 ;
|
||||||
|
C -1 ; WX 600 ; N uhungarumlaut ; B 101 -15 723 672 ;
|
||||||
|
C -1 ; WX 600 ; N ecaron ; B 106 -15 614 669 ;
|
||||||
|
C 159 ; WX 600 ; N Ydieresis ; B 133 0 695 753 ;
|
||||||
|
C 247 ; WX 600 ; N divide ; B 136 48 573 467 ;
|
||||||
|
C 221 ; WX 600 ; N Yacute ; B 133 0 695 805 ;
|
||||||
|
C 194 ; WX 600 ; N Acircumflex ; B 3 0 607 787 ;
|
||||||
|
C 225 ; WX 600 ; N aacute ; B 76 -15 612 672 ;
|
||||||
|
C 219 ; WX 600 ; N Ucircumflex ; B 125 -18 702 787 ;
|
||||||
|
C 253 ; WX 600 ; N yacute ; B -4 -157 683 672 ;
|
||||||
|
C -1 ; WX 600 ; N scommaaccent ; B 78 -250 584 441 ;
|
||||||
|
C 234 ; WX 600 ; N ecircumflex ; B 106 -15 598 654 ;
|
||||||
|
C -1 ; WX 600 ; N Uring ; B 125 -18 702 760 ;
|
||||||
|
C 220 ; WX 600 ; N Udieresis ; B 125 -18 702 753 ;
|
||||||
|
C -1 ; WX 600 ; N aogonek ; B 76 -172 569 441 ;
|
||||||
|
C 218 ; WX 600 ; N Uacute ; B 125 -18 702 805 ;
|
||||||
|
C -1 ; WX 600 ; N uogonek ; B 101 -172 572 426 ;
|
||||||
|
C 203 ; WX 600 ; N Edieresis ; B 53 0 660 753 ;
|
||||||
|
C -1 ; WX 600 ; N Dcroat ; B 43 0 645 562 ;
|
||||||
|
C -1 ; WX 600 ; N commaaccent ; B 145 -250 323 -58 ;
|
||||||
|
C 169 ; WX 600 ; N copyright ; B 53 -18 667 580 ;
|
||||||
|
C -1 ; WX 600 ; N Emacron ; B 53 0 660 698 ;
|
||||||
|
C -1 ; WX 600 ; N ccaron ; B 106 -15 614 669 ;
|
||||||
|
C 229 ; WX 600 ; N aring ; B 76 -15 569 627 ;
|
||||||
|
C -1 ; WX 600 ; N Ncommaaccent ; B 7 -250 712 562 ;
|
||||||
|
C -1 ; WX 600 ; N lacute ; B 95 0 640 805 ;
|
||||||
|
C 224 ; WX 600 ; N agrave ; B 76 -15 569 672 ;
|
||||||
|
C -1 ; WX 600 ; N Tcommaaccent ; B 108 -250 665 562 ;
|
||||||
|
C -1 ; WX 600 ; N Cacute ; B 93 -18 655 805 ;
|
||||||
|
C 227 ; WX 600 ; N atilde ; B 76 -15 629 606 ;
|
||||||
|
C -1 ; WX 600 ; N Edotaccent ; B 53 0 660 753 ;
|
||||||
|
C 154 ; WX 600 ; N scaron ; B 78 -15 614 669 ;
|
||||||
|
C -1 ; WX 600 ; N scedilla ; B 78 -151 584 441 ;
|
||||||
|
C 237 ; WX 600 ; N iacute ; B 95 0 612 672 ;
|
||||||
|
C -1 ; WX 600 ; N lozenge ; B 94 0 519 706 ;
|
||||||
|
C -1 ; WX 600 ; N Rcaron ; B 38 0 642 802 ;
|
||||||
|
C -1 ; WX 600 ; N Gcommaaccent ; B 83 -250 645 580 ;
|
||||||
|
C 251 ; WX 600 ; N ucircumflex ; B 101 -15 572 654 ;
|
||||||
|
C 226 ; WX 600 ; N acircumflex ; B 76 -15 581 654 ;
|
||||||
|
C -1 ; WX 600 ; N Amacron ; B 3 0 607 698 ;
|
||||||
|
C -1 ; WX 600 ; N rcaron ; B 60 0 636 669 ;
|
||||||
|
C 231 ; WX 600 ; N ccedilla ; B 106 -151 614 441 ;
|
||||||
|
C -1 ; WX 600 ; N Zdotaccent ; B 86 0 610 753 ;
|
||||||
|
C 222 ; WX 600 ; N Thorn ; B 79 0 606 562 ;
|
||||||
|
C -1 ; WX 600 ; N Omacron ; B 94 -18 628 698 ;
|
||||||
|
C -1 ; WX 600 ; N Racute ; B 38 0 670 805 ;
|
||||||
|
C -1 ; WX 600 ; N Sacute ; B 76 -20 650 805 ;
|
||||||
|
C -1 ; WX 600 ; N dcaron ; B 85 -15 849 629 ;
|
||||||
|
C -1 ; WX 600 ; N Umacron ; B 125 -18 702 698 ;
|
||||||
|
C -1 ; WX 600 ; N uring ; B 101 -15 572 627 ;
|
||||||
|
C 179 ; WX 600 ; N threesuperior ; B 213 240 501 622 ;
|
||||||
|
C 210 ; WX 600 ; N Ograve ; B 94 -18 625 805 ;
|
||||||
|
C 192 ; WX 600 ; N Agrave ; B 3 0 607 805 ;
|
||||||
|
C -1 ; WX 600 ; N Abreve ; B 3 0 607 732 ;
|
||||||
|
C 215 ; WX 600 ; N multiply ; B 103 43 607 470 ;
|
||||||
|
C 250 ; WX 600 ; N uacute ; B 101 -15 602 672 ;
|
||||||
|
C -1 ; WX 600 ; N Tcaron ; B 108 0 665 802 ;
|
||||||
|
C -1 ; WX 600 ; N partialdiff ; B 45 -38 546 710 ;
|
||||||
|
C 255 ; WX 600 ; N ydieresis ; B -4 -157 683 620 ;
|
||||||
|
C -1 ; WX 600 ; N Nacute ; B 7 -13 712 805 ;
|
||||||
|
C 238 ; WX 600 ; N icircumflex ; B 95 0 551 654 ;
|
||||||
|
C 202 ; WX 600 ; N Ecircumflex ; B 53 0 660 787 ;
|
||||||
|
C 228 ; WX 600 ; N adieresis ; B 76 -15 575 620 ;
|
||||||
|
C 235 ; WX 600 ; N edieresis ; B 106 -15 598 620 ;
|
||||||
|
C -1 ; WX 600 ; N cacute ; B 106 -15 612 672 ;
|
||||||
|
C -1 ; WX 600 ; N nacute ; B 26 0 602 672 ;
|
||||||
|
C -1 ; WX 600 ; N umacron ; B 101 -15 600 565 ;
|
||||||
|
C -1 ; WX 600 ; N Ncaron ; B 7 -13 712 802 ;
|
||||||
|
C 205 ; WX 600 ; N Iacute ; B 96 0 640 805 ;
|
||||||
|
C 177 ; WX 600 ; N plusminus ; B 96 44 594 558 ;
|
||||||
|
C 166 ; WX 600 ; N brokenbar ; B 238 -175 469 675 ;
|
||||||
|
C 174 ; WX 600 ; N registered ; B 53 -18 667 580 ;
|
||||||
|
C -1 ; WX 600 ; N Gbreve ; B 83 -18 645 732 ;
|
||||||
|
C -1 ; WX 600 ; N Idotaccent ; B 96 0 623 753 ;
|
||||||
|
C -1 ; WX 600 ; N summation ; B 15 -10 670 706 ;
|
||||||
|
C 200 ; WX 600 ; N Egrave ; B 53 0 660 805 ;
|
||||||
|
C -1 ; WX 600 ; N racute ; B 60 0 636 672 ;
|
||||||
|
C -1 ; WX 600 ; N omacron ; B 102 -15 600 565 ;
|
||||||
|
C -1 ; WX 600 ; N Zacute ; B 86 0 670 805 ;
|
||||||
|
C 142 ; WX 600 ; N Zcaron ; B 86 0 642 802 ;
|
||||||
|
C -1 ; WX 600 ; N greaterequal ; B 98 0 594 710 ;
|
||||||
|
C 208 ; WX 600 ; N Eth ; B 43 0 645 562 ;
|
||||||
|
C 199 ; WX 600 ; N Ccedilla ; B 93 -151 658 580 ;
|
||||||
|
C -1 ; WX 600 ; N lcommaaccent ; B 95 -250 515 629 ;
|
||||||
|
C -1 ; WX 600 ; N tcaron ; B 167 -15 587 717 ;
|
||||||
|
C -1 ; WX 600 ; N eogonek ; B 106 -172 598 441 ;
|
||||||
|
C -1 ; WX 600 ; N Uogonek ; B 124 -172 702 562 ;
|
||||||
|
C 193 ; WX 600 ; N Aacute ; B 3 0 660 805 ;
|
||||||
|
C 196 ; WX 600 ; N Adieresis ; B 3 0 607 753 ;
|
||||||
|
C 232 ; WX 600 ; N egrave ; B 106 -15 598 672 ;
|
||||||
|
C -1 ; WX 600 ; N zacute ; B 99 0 612 672 ;
|
||||||
|
C -1 ; WX 600 ; N iogonek ; B 95 -172 515 657 ;
|
||||||
|
C 211 ; WX 600 ; N Oacute ; B 94 -18 640 805 ;
|
||||||
|
C 243 ; WX 600 ; N oacute ; B 102 -15 612 672 ;
|
||||||
|
C -1 ; WX 600 ; N amacron ; B 76 -15 600 565 ;
|
||||||
|
C -1 ; WX 600 ; N sacute ; B 78 -15 612 672 ;
|
||||||
|
C 239 ; WX 600 ; N idieresis ; B 95 0 545 620 ;
|
||||||
|
C 212 ; WX 600 ; N Ocircumflex ; B 94 -18 625 787 ;
|
||||||
|
C 217 ; WX 600 ; N Ugrave ; B 125 -18 702 805 ;
|
||||||
|
C -1 ; WX 600 ; N Delta ; B 6 0 598 688 ;
|
||||||
|
C 254 ; WX 600 ; N thorn ; B -24 -157 605 629 ;
|
||||||
|
C 178 ; WX 600 ; N twosuperior ; B 230 249 535 622 ;
|
||||||
|
C 214 ; WX 600 ; N Odieresis ; B 94 -18 625 753 ;
|
||||||
|
C 181 ; WX 600 ; N mu ; B 72 -157 572 426 ;
|
||||||
|
C 236 ; WX 600 ; N igrave ; B 95 0 515 672 ;
|
||||||
|
C -1 ; WX 600 ; N ohungarumlaut ; B 102 -15 723 672 ;
|
||||||
|
C -1 ; WX 600 ; N Eogonek ; B 53 -172 660 562 ;
|
||||||
|
C -1 ; WX 600 ; N dcroat ; B 85 -15 704 629 ;
|
||||||
|
C 190 ; WX 600 ; N threequarters ; B 73 -56 659 666 ;
|
||||||
|
C -1 ; WX 600 ; N Scedilla ; B 76 -151 650 580 ;
|
||||||
|
C -1 ; WX 600 ; N lcaron ; B 95 0 667 629 ;
|
||||||
|
C -1 ; WX 600 ; N Kcommaaccent ; B 38 -250 671 562 ;
|
||||||
|
C -1 ; WX 600 ; N Lacute ; B 47 0 607 805 ;
|
||||||
|
C 153 ; WX 600 ; N trademark ; B 75 263 742 562 ;
|
||||||
|
C -1 ; WX 600 ; N edotaccent ; B 106 -15 598 620 ;
|
||||||
|
C 204 ; WX 600 ; N Igrave ; B 96 0 623 805 ;
|
||||||
|
C -1 ; WX 600 ; N Imacron ; B 96 0 628 698 ;
|
||||||
|
C -1 ; WX 600 ; N Lcaron ; B 47 0 632 562 ;
|
||||||
|
C 189 ; WX 600 ; N onehalf ; B 65 -57 669 665 ;
|
||||||
|
C -1 ; WX 600 ; N lessequal ; B 98 0 645 710 ;
|
||||||
|
C 244 ; WX 600 ; N ocircumflex ; B 102 -15 588 654 ;
|
||||||
|
C 241 ; WX 600 ; N ntilde ; B 26 0 629 606 ;
|
||||||
|
C -1 ; WX 600 ; N Uhungarumlaut ; B 125 -18 761 805 ;
|
||||||
|
C 201 ; WX 600 ; N Eacute ; B 53 0 670 805 ;
|
||||||
|
C -1 ; WX 600 ; N emacron ; B 106 -15 600 565 ;
|
||||||
|
C -1 ; WX 600 ; N gbreve ; B 61 -157 657 609 ;
|
||||||
|
C 188 ; WX 600 ; N onequarter ; B 65 -57 674 665 ;
|
||||||
|
C 138 ; WX 600 ; N Scaron ; B 76 -20 672 802 ;
|
||||||
|
C -1 ; WX 600 ; N Scommaaccent ; B 76 -250 650 580 ;
|
||||||
|
C -1 ; WX 600 ; N Ohungarumlaut ; B 94 -18 751 805 ;
|
||||||
|
C 176 ; WX 600 ; N degree ; B 214 269 576 622 ;
|
||||||
|
C 242 ; WX 600 ; N ograve ; B 102 -15 588 672 ;
|
||||||
|
C -1 ; WX 600 ; N Ccaron ; B 93 -18 672 802 ;
|
||||||
|
C 249 ; WX 600 ; N ugrave ; B 101 -15 572 672 ;
|
||||||
|
C -1 ; WX 600 ; N radical ; B 85 -15 765 792 ;
|
||||||
|
C -1 ; WX 600 ; N Dcaron ; B 43 0 645 802 ;
|
||||||
|
C -1 ; WX 600 ; N rcommaaccent ; B 60 -250 636 441 ;
|
||||||
|
C 209 ; WX 600 ; N Ntilde ; B 7 -13 712 729 ;
|
||||||
|
C 245 ; WX 600 ; N otilde ; B 102 -15 629 606 ;
|
||||||
|
C -1 ; WX 600 ; N Rcommaaccent ; B 38 -250 598 562 ;
|
||||||
|
C -1 ; WX 600 ; N Lcommaaccent ; B 47 -250 607 562 ;
|
||||||
|
C 195 ; WX 600 ; N Atilde ; B 3 0 655 729 ;
|
||||||
|
C -1 ; WX 600 ; N Aogonek ; B 3 -172 607 562 ;
|
||||||
|
C 197 ; WX 600 ; N Aring ; B 3 0 607 750 ;
|
||||||
|
C 213 ; WX 600 ; N Otilde ; B 94 -18 655 729 ;
|
||||||
|
C -1 ; WX 600 ; N zdotaccent ; B 99 0 593 620 ;
|
||||||
|
C -1 ; WX 600 ; N Ecaron ; B 53 0 660 802 ;
|
||||||
|
C -1 ; WX 600 ; N Iogonek ; B 96 -172 623 562 ;
|
||||||
|
C -1 ; WX 600 ; N kcommaaccent ; B 58 -250 633 629 ;
|
||||||
|
C -1 ; WX 600 ; N minus ; B 129 232 580 283 ;
|
||||||
|
C 206 ; WX 600 ; N Icircumflex ; B 96 0 623 787 ;
|
||||||
|
C -1 ; WX 600 ; N ncaron ; B 26 0 614 669 ;
|
||||||
|
C -1 ; WX 600 ; N tcommaaccent ; B 165 -250 561 561 ;
|
||||||
|
C 172 ; WX 600 ; N logicalnot ; B 155 108 591 369 ;
|
||||||
|
C 246 ; WX 600 ; N odieresis ; B 102 -15 588 620 ;
|
||||||
|
C 252 ; WX 600 ; N udieresis ; B 101 -15 575 620 ;
|
||||||
|
C -1 ; WX 600 ; N notequal ; B 43 -16 621 529 ;
|
||||||
|
C -1 ; WX 600 ; N gcommaaccent ; B 61 -157 657 708 ;
|
||||||
|
C 240 ; WX 600 ; N eth ; B 102 -15 639 629 ;
|
||||||
|
C 158 ; WX 600 ; N zcaron ; B 99 0 624 669 ;
|
||||||
|
C -1 ; WX 600 ; N ncommaaccent ; B 26 -250 585 441 ;
|
||||||
|
C 185 ; WX 600 ; N onesuperior ; B 231 249 491 622 ;
|
||||||
|
C -1 ; WX 600 ; N imacron ; B 95 0 543 565 ;
|
||||||
|
C 128 ; WX 600 ; N Euro ; B 0 0 0 0 ;
|
||||||
|
EndCharMetrics
|
||||||
|
EndFontMetrics
|
||||||
344
vendor/dompdf/dompdf/lib/fonts/Courier.afm
vendored
Normal file
@ -0,0 +1,344 @@
|
|||||||
|
StartFontMetrics 4.1
|
||||||
|
Comment Copyright (c) 1989, 1990, 1991, 1992, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
|
||||||
|
Comment Creation Date: Thu May 1 17:27:09 1997
|
||||||
|
Comment UniqueID 43050
|
||||||
|
Comment VMusage 39754 50779
|
||||||
|
FontName Courier
|
||||||
|
FullName Courier
|
||||||
|
FamilyName Courier
|
||||||
|
Weight Medium
|
||||||
|
ItalicAngle 0
|
||||||
|
IsFixedPitch true
|
||||||
|
CharacterSet ExtendedRoman
|
||||||
|
FontBBox -23 -250 715 805
|
||||||
|
UnderlinePosition -100
|
||||||
|
UnderlineThickness 50
|
||||||
|
Version 003.000
|
||||||
|
Notice Copyright (c) 1989, 1990, 1991, 1992, 1993, 1997 Adobe Systems Incorporated. All Rights Reserved.
|
||||||
|
EncodingScheme WinAnsiEncoding
|
||||||
|
CapHeight 562
|
||||||
|
XHeight 426
|
||||||
|
Ascender 629
|
||||||
|
Descender -157
|
||||||
|
StdHW 51
|
||||||
|
StdVW 51
|
||||||
|
StartCharMetrics 317
|
||||||
|
C 32 ; WX 600 ; N space ; B 0 0 0 0 ;
|
||||||
|
C 160 ; WX 600 ; N space ; B 0 0 0 0 ;
|
||||||
|
C 33 ; WX 600 ; N exclam ; B 236 -15 364 572 ;
|
||||||
|
C 34 ; WX 600 ; N quotedbl ; B 187 328 413 562 ;
|
||||||
|
C 35 ; WX 600 ; N numbersign ; B 93 -32 507 639 ;
|
||||||
|
C 36 ; WX 600 ; N dollar ; B 105 -126 496 662 ;
|
||||||
|
C 37 ; WX 600 ; N percent ; B 81 -15 518 622 ;
|
||||||
|
C 38 ; WX 600 ; N ampersand ; B 63 -15 538 543 ;
|
||||||
|
C 146 ; WX 600 ; N quoteright ; B 213 328 376 562 ;
|
||||||
|
C 40 ; WX 600 ; N parenleft ; B 269 -108 440 622 ;
|
||||||
|
C 41 ; WX 600 ; N parenright ; B 160 -108 331 622 ;
|
||||||
|
C 42 ; WX 600 ; N asterisk ; B 116 257 484 607 ;
|
||||||
|
C 43 ; WX 600 ; N plus ; B 80 44 520 470 ;
|
||||||
|
C 44 ; WX 600 ; N comma ; B 181 -112 344 122 ;
|
||||||
|
C 45 ; WX 600 ; N hyphen ; B 103 231 497 285 ;
|
||||||
|
C 173 ; WX 600 ; N hyphen ; B 103 231 497 285 ;
|
||||||
|
C 46 ; WX 600 ; N period ; B 229 -15 371 109 ;
|
||||||
|
C 47 ; WX 600 ; N slash ; B 125 -80 475 629 ;
|
||||||
|
C 48 ; WX 600 ; N zero ; B 106 -15 494 622 ;
|
||||||
|
C 49 ; WX 600 ; N one ; B 96 0 505 622 ;
|
||||||
|
C 50 ; WX 600 ; N two ; B 70 0 471 622 ;
|
||||||
|
C 51 ; WX 600 ; N three ; B 75 -15 466 622 ;
|
||||||
|
C 52 ; WX 600 ; N four ; B 78 0 500 622 ;
|
||||||
|
C 53 ; WX 600 ; N five ; B 92 -15 497 607 ;
|
||||||
|
C 54 ; WX 600 ; N six ; B 111 -15 497 622 ;
|
||||||
|
C 55 ; WX 600 ; N seven ; B 82 0 483 607 ;
|
||||||
|
C 56 ; WX 600 ; N eight ; B 102 -15 498 622 ;
|
||||||
|
C 57 ; WX 600 ; N nine ; B 96 -15 489 622 ;
|
||||||
|
C 58 ; WX 600 ; N colon ; B 229 -15 371 385 ;
|
||||||
|
C 59 ; WX 600 ; N semicolon ; B 181 -112 371 385 ;
|
||||||
|
C 60 ; WX 600 ; N less ; B 41 42 519 472 ;
|
||||||
|
C 61 ; WX 600 ; N equal ; B 80 138 520 376 ;
|
||||||
|
C 62 ; WX 600 ; N greater ; B 66 42 544 472 ;
|
||||||
|
C 63 ; WX 600 ; N question ; B 129 -15 492 572 ;
|
||||||
|
C 64 ; WX 600 ; N at ; B 77 -15 533 622 ;
|
||||||
|
C 65 ; WX 600 ; N A ; B 3 0 597 562 ;
|
||||||
|
C 66 ; WX 600 ; N B ; B 43 0 559 562 ;
|
||||||
|
C 67 ; WX 600 ; N C ; B 41 -18 540 580 ;
|
||||||
|
C 68 ; WX 600 ; N D ; B 43 0 574 562 ;
|
||||||
|
C 69 ; WX 600 ; N E ; B 53 0 550 562 ;
|
||||||
|
C 70 ; WX 600 ; N F ; B 53 0 545 562 ;
|
||||||
|
C 71 ; WX 600 ; N G ; B 31 -18 575 580 ;
|
||||||
|
C 72 ; WX 600 ; N H ; B 32 0 568 562 ;
|
||||||
|
C 73 ; WX 600 ; N I ; B 96 0 504 562 ;
|
||||||
|
C 74 ; WX 600 ; N J ; B 34 -18 566 562 ;
|
||||||
|
C 75 ; WX 600 ; N K ; B 38 0 582 562 ;
|
||||||
|
C 76 ; WX 600 ; N L ; B 47 0 554 562 ;
|
||||||
|
C 77 ; WX 600 ; N M ; B 4 0 596 562 ;
|
||||||
|
C 78 ; WX 600 ; N N ; B 7 -13 593 562 ;
|
||||||
|
C 79 ; WX 600 ; N O ; B 43 -18 557 580 ;
|
||||||
|
C 80 ; WX 600 ; N P ; B 79 0 558 562 ;
|
||||||
|
C 81 ; WX 600 ; N Q ; B 43 -138 557 580 ;
|
||||||
|
C 82 ; WX 600 ; N R ; B 38 0 588 562 ;
|
||||||
|
C 83 ; WX 600 ; N S ; B 72 -20 529 580 ;
|
||||||
|
C 84 ; WX 600 ; N T ; B 38 0 563 562 ;
|
||||||
|
C 85 ; WX 600 ; N U ; B 17 -18 583 562 ;
|
||||||
|
C 86 ; WX 600 ; N V ; B -4 -13 604 562 ;
|
||||||
|
C 87 ; WX 600 ; N W ; B -3 -13 603 562 ;
|
||||||
|
C 88 ; WX 600 ; N X ; B 23 0 577 562 ;
|
||||||
|
C 89 ; WX 600 ; N Y ; B 24 0 576 562 ;
|
||||||
|
C 90 ; WX 600 ; N Z ; B 86 0 514 562 ;
|
||||||
|
C 91 ; WX 600 ; N bracketleft ; B 269 -108 442 622 ;
|
||||||
|
C 92 ; WX 600 ; N backslash ; B 118 -80 482 629 ;
|
||||||
|
C 93 ; WX 600 ; N bracketright ; B 158 -108 331 622 ;
|
||||||
|
C 94 ; WX 600 ; N asciicircum ; B 94 354 506 622 ;
|
||||||
|
C 95 ; WX 600 ; N underscore ; B 0 -125 600 -75 ;
|
||||||
|
C 145 ; WX 600 ; N quoteleft ; B 224 328 387 562 ;
|
||||||
|
C 97 ; WX 600 ; N a ; B 53 -15 559 441 ;
|
||||||
|
C 98 ; WX 600 ; N b ; B 14 -15 575 629 ;
|
||||||
|
C 99 ; WX 600 ; N c ; B 66 -15 529 441 ;
|
||||||
|
C 100 ; WX 600 ; N d ; B 45 -15 591 629 ;
|
||||||
|
C 101 ; WX 600 ; N e ; B 66 -15 548 441 ;
|
||||||
|
C 102 ; WX 600 ; N f ; B 114 0 531 629 ; L i fi ; L l fl ;
|
||||||
|
C 103 ; WX 600 ; N g ; B 45 -157 566 441 ;
|
||||||
|
C 104 ; WX 600 ; N h ; B 18 0 582 629 ;
|
||||||
|
C 105 ; WX 600 ; N i ; B 95 0 505 657 ;
|
||||||
|
C 106 ; WX 600 ; N j ; B 82 -157 410 657 ;
|
||||||
|
C 107 ; WX 600 ; N k ; B 43 0 580 629 ;
|
||||||
|
C 108 ; WX 600 ; N l ; B 95 0 505 629 ;
|
||||||
|
C 109 ; WX 600 ; N m ; B -5 0 605 441 ;
|
||||||
|
C 110 ; WX 600 ; N n ; B 26 0 575 441 ;
|
||||||
|
C 111 ; WX 600 ; N o ; B 62 -15 538 441 ;
|
||||||
|
C 112 ; WX 600 ; N p ; B 9 -157 555 441 ;
|
||||||
|
C 113 ; WX 600 ; N q ; B 45 -157 591 441 ;
|
||||||
|
C 114 ; WX 600 ; N r ; B 60 0 559 441 ;
|
||||||
|
C 115 ; WX 600 ; N s ; B 80 -15 513 441 ;
|
||||||
|
C 116 ; WX 600 ; N t ; B 87 -15 530 561 ;
|
||||||
|
C 117 ; WX 600 ; N u ; B 21 -15 562 426 ;
|
||||||
|
C 118 ; WX 600 ; N v ; B 10 -10 590 426 ;
|
||||||
|
C 119 ; WX 600 ; N w ; B -4 -10 604 426 ;
|
||||||
|
C 120 ; WX 600 ; N x ; B 20 0 580 426 ;
|
||||||
|
C 121 ; WX 600 ; N y ; B 7 -157 592 426 ;
|
||||||
|
C 122 ; WX 600 ; N z ; B 99 0 502 426 ;
|
||||||
|
C 123 ; WX 600 ; N braceleft ; B 182 -108 437 622 ;
|
||||||
|
C 124 ; WX 600 ; N bar ; B 275 -250 326 750 ;
|
||||||
|
C 125 ; WX 600 ; N braceright ; B 163 -108 418 622 ;
|
||||||
|
C 126 ; WX 600 ; N asciitilde ; B 63 197 540 320 ;
|
||||||
|
C 161 ; WX 600 ; N exclamdown ; B 236 -157 364 430 ;
|
||||||
|
C 162 ; WX 600 ; N cent ; B 96 -49 500 614 ;
|
||||||
|
C 163 ; WX 600 ; N sterling ; B 84 -21 521 611 ;
|
||||||
|
C -1 ; WX 600 ; N fraction ; B 92 -57 509 665 ;
|
||||||
|
C 165 ; WX 600 ; N yen ; B 26 0 574 562 ;
|
||||||
|
C 131 ; WX 600 ; N florin ; B 4 -143 539 622 ;
|
||||||
|
C 167 ; WX 600 ; N section ; B 113 -78 488 580 ;
|
||||||
|
C 164 ; WX 600 ; N currency ; B 73 58 527 506 ;
|
||||||
|
C 39 ; WX 600 ; N quotesingle ; B 259 328 341 562 ;
|
||||||
|
C 147 ; WX 600 ; N quotedblleft ; B 143 328 471 562 ;
|
||||||
|
C 171 ; WX 600 ; N guillemotleft ; B 37 70 563 446 ;
|
||||||
|
C 139 ; WX 600 ; N guilsinglleft ; B 149 70 451 446 ;
|
||||||
|
C 155 ; WX 600 ; N guilsinglright ; B 149 70 451 446 ;
|
||||||
|
C -1 ; WX 600 ; N fi ; B 3 0 597 629 ;
|
||||||
|
C -1 ; WX 600 ; N fl ; B 3 0 597 629 ;
|
||||||
|
C 150 ; WX 600 ; N endash ; B 75 231 525 285 ;
|
||||||
|
C 134 ; WX 600 ; N dagger ; B 141 -78 459 580 ;
|
||||||
|
C 135 ; WX 600 ; N daggerdbl ; B 141 -78 459 580 ;
|
||||||
|
C 183 ; WX 600 ; N periodcentered ; B 222 189 378 327 ;
|
||||||
|
C 182 ; WX 600 ; N paragraph ; B 50 -78 511 562 ;
|
||||||
|
C 149 ; WX 600 ; N bullet ; B 172 130 428 383 ;
|
||||||
|
C 130 ; WX 600 ; N quotesinglbase ; B 213 -134 376 100 ;
|
||||||
|
C 132 ; WX 600 ; N quotedblbase ; B 143 -134 457 100 ;
|
||||||
|
C 148 ; WX 600 ; N quotedblright ; B 143 328 457 562 ;
|
||||||
|
C 187 ; WX 600 ; N guillemotright ; B 37 70 563 446 ;
|
||||||
|
C 133 ; WX 600 ; N ellipsis ; B 37 -15 563 111 ;
|
||||||
|
C 137 ; WX 600 ; N perthousand ; B 3 -15 600 622 ;
|
||||||
|
C 191 ; WX 600 ; N questiondown ; B 108 -157 471 430 ;
|
||||||
|
C 96 ; WX 600 ; N grave ; B 151 497 378 672 ;
|
||||||
|
C 180 ; WX 600 ; N acute ; B 242 497 469 672 ;
|
||||||
|
C 136 ; WX 600 ; N circumflex ; B 124 477 476 654 ;
|
||||||
|
C 152 ; WX 600 ; N tilde ; B 105 489 503 606 ;
|
||||||
|
C 175 ; WX 600 ; N macron ; B 120 525 480 565 ;
|
||||||
|
C -1 ; WX 600 ; N breve ; B 153 501 447 609 ;
|
||||||
|
C -1 ; WX 600 ; N dotaccent ; B 249 537 352 640 ;
|
||||||
|
C 168 ; WX 600 ; N dieresis ; B 148 537 453 640 ;
|
||||||
|
C -1 ; WX 600 ; N ring ; B 218 463 382 627 ;
|
||||||
|
C 184 ; WX 600 ; N cedilla ; B 224 -151 362 10 ;
|
||||||
|
C -1 ; WX 600 ; N hungarumlaut ; B 133 497 540 672 ;
|
||||||
|
C -1 ; WX 600 ; N ogonek ; B 211 -172 407 4 ;
|
||||||
|
C -1 ; WX 600 ; N caron ; B 124 492 476 669 ;
|
||||||
|
C 151 ; WX 600 ; N emdash ; B 0 231 600 285 ;
|
||||||
|
C 198 ; WX 600 ; N AE ; B 3 0 550 562 ;
|
||||||
|
C 170 ; WX 600 ; N ordfeminine ; B 156 249 442 580 ;
|
||||||
|
C -1 ; WX 600 ; N Lslash ; B 47 0 554 562 ;
|
||||||
|
C 216 ; WX 600 ; N Oslash ; B 43 -80 557 629 ;
|
||||||
|
C 140 ; WX 600 ; N OE ; B 7 0 567 562 ;
|
||||||
|
C 186 ; WX 600 ; N ordmasculine ; B 157 249 443 580 ;
|
||||||
|
C 230 ; WX 600 ; N ae ; B 19 -15 570 441 ;
|
||||||
|
C -1 ; WX 600 ; N dotlessi ; B 95 0 505 426 ;
|
||||||
|
C -1 ; WX 600 ; N lslash ; B 95 0 505 629 ;
|
||||||
|
C 248 ; WX 600 ; N oslash ; B 62 -80 538 506 ;
|
||||||
|
C 156 ; WX 600 ; N oe ; B 19 -15 559 441 ;
|
||||||
|
C 223 ; WX 600 ; N germandbls ; B 48 -15 588 629 ;
|
||||||
|
C 207 ; WX 600 ; N Idieresis ; B 96 0 504 753 ;
|
||||||
|
C 233 ; WX 600 ; N eacute ; B 66 -15 548 672 ;
|
||||||
|
C -1 ; WX 600 ; N abreve ; B 53 -15 559 609 ;
|
||||||
|
C -1 ; WX 600 ; N uhungarumlaut ; B 21 -15 580 672 ;
|
||||||
|
C -1 ; WX 600 ; N ecaron ; B 66 -15 548 669 ;
|
||||||
|
C 159 ; WX 600 ; N Ydieresis ; B 24 0 576 753 ;
|
||||||
|
C 247 ; WX 600 ; N divide ; B 87 48 513 467 ;
|
||||||
|
C 221 ; WX 600 ; N Yacute ; B 24 0 576 805 ;
|
||||||
|
C 194 ; WX 600 ; N Acircumflex ; B 3 0 597 787 ;
|
||||||
|
C 225 ; WX 600 ; N aacute ; B 53 -15 559 672 ;
|
||||||
|
C 219 ; WX 600 ; N Ucircumflex ; B 17 -18 583 787 ;
|
||||||
|
C 253 ; WX 600 ; N yacute ; B 7 -157 592 672 ;
|
||||||
|
C -1 ; WX 600 ; N scommaaccent ; B 80 -250 513 441 ;
|
||||||
|
C 234 ; WX 600 ; N ecircumflex ; B 66 -15 548 654 ;
|
||||||
|
C -1 ; WX 600 ; N Uring ; B 17 -18 583 760 ;
|
||||||
|
C 220 ; WX 600 ; N Udieresis ; B 17 -18 583 753 ;
|
||||||
|
C -1 ; WX 600 ; N aogonek ; B 53 -172 587 441 ;
|
||||||
|
C 218 ; WX 600 ; N Uacute ; B 17 -18 583 805 ;
|
||||||
|
C -1 ; WX 600 ; N uogonek ; B 21 -172 590 426 ;
|
||||||
|
C 203 ; WX 600 ; N Edieresis ; B 53 0 550 753 ;
|
||||||
|
C -1 ; WX 600 ; N Dcroat ; B 30 0 574 562 ;
|
||||||
|
C -1 ; WX 600 ; N commaaccent ; B 198 -250 335 -58 ;
|
||||||
|
C 169 ; WX 600 ; N copyright ; B 0 -18 600 580 ;
|
||||||
|
C -1 ; WX 600 ; N Emacron ; B 53 0 550 698 ;
|
||||||
|
C -1 ; WX 600 ; N ccaron ; B 66 -15 529 669 ;
|
||||||
|
C 229 ; WX 600 ; N aring ; B 53 -15 559 627 ;
|
||||||
|
C -1 ; WX 600 ; N Ncommaaccent ; B 7 -250 593 562 ;
|
||||||
|
C -1 ; WX 600 ; N lacute ; B 95 0 505 805 ;
|
||||||
|
C 224 ; WX 600 ; N agrave ; B 53 -15 559 672 ;
|
||||||
|
C -1 ; WX 600 ; N Tcommaaccent ; B 38 -250 563 562 ;
|
||||||
|
C -1 ; WX 600 ; N Cacute ; B 41 -18 540 805 ;
|
||||||
|
C 227 ; WX 600 ; N atilde ; B 53 -15 559 606 ;
|
||||||
|
C -1 ; WX 600 ; N Edotaccent ; B 53 0 550 753 ;
|
||||||
|
C 154 ; WX 600 ; N scaron ; B 80 -15 513 669 ;
|
||||||
|
C -1 ; WX 600 ; N scedilla ; B 80 -151 513 441 ;
|
||||||
|
C 237 ; WX 600 ; N iacute ; B 95 0 505 672 ;
|
||||||
|
C -1 ; WX 600 ; N lozenge ; B 18 0 443 706 ;
|
||||||
|
C -1 ; WX 600 ; N Rcaron ; B 38 0 588 802 ;
|
||||||
|
C -1 ; WX 600 ; N Gcommaaccent ; B 31 -250 575 580 ;
|
||||||
|
C 251 ; WX 600 ; N ucircumflex ; B 21 -15 562 654 ;
|
||||||
|
C 226 ; WX 600 ; N acircumflex ; B 53 -15 559 654 ;
|
||||||
|
C -1 ; WX 600 ; N Amacron ; B 3 0 597 698 ;
|
||||||
|
C -1 ; WX 600 ; N rcaron ; B 60 0 559 669 ;
|
||||||
|
C 231 ; WX 600 ; N ccedilla ; B 66 -151 529 441 ;
|
||||||
|
C -1 ; WX 600 ; N Zdotaccent ; B 86 0 514 753 ;
|
||||||
|
C 222 ; WX 600 ; N Thorn ; B 79 0 538 562 ;
|
||||||
|
C -1 ; WX 600 ; N Omacron ; B 43 -18 557 698 ;
|
||||||
|
C -1 ; WX 600 ; N Racute ; B 38 0 588 805 ;
|
||||||
|
C -1 ; WX 600 ; N Sacute ; B 72 -20 529 805 ;
|
||||||
|
C -1 ; WX 600 ; N dcaron ; B 45 -15 715 629 ;
|
||||||
|
C -1 ; WX 600 ; N Umacron ; B 17 -18 583 698 ;
|
||||||
|
C -1 ; WX 600 ; N uring ; B 21 -15 562 627 ;
|
||||||
|
C 179 ; WX 600 ; N threesuperior ; B 155 240 406 622 ;
|
||||||
|
C 210 ; WX 600 ; N Ograve ; B 43 -18 557 805 ;
|
||||||
|
C 192 ; WX 600 ; N Agrave ; B 3 0 597 805 ;
|
||||||
|
C -1 ; WX 600 ; N Abreve ; B 3 0 597 732 ;
|
||||||
|
C 215 ; WX 600 ; N multiply ; B 87 43 515 470 ;
|
||||||
|
C 250 ; WX 600 ; N uacute ; B 21 -15 562 672 ;
|
||||||
|
C -1 ; WX 600 ; N Tcaron ; B 38 0 563 802 ;
|
||||||
|
C -1 ; WX 600 ; N partialdiff ; B 17 -38 459 710 ;
|
||||||
|
C 255 ; WX 600 ; N ydieresis ; B 7 -157 592 620 ;
|
||||||
|
C -1 ; WX 600 ; N Nacute ; B 7 -13 593 805 ;
|
||||||
|
C 238 ; WX 600 ; N icircumflex ; B 94 0 505 654 ;
|
||||||
|
C 202 ; WX 600 ; N Ecircumflex ; B 53 0 550 787 ;
|
||||||
|
C 228 ; WX 600 ; N adieresis ; B 53 -15 559 620 ;
|
||||||
|
C 235 ; WX 600 ; N edieresis ; B 66 -15 548 620 ;
|
||||||
|
C -1 ; WX 600 ; N cacute ; B 66 -15 529 672 ;
|
||||||
|
C -1 ; WX 600 ; N nacute ; B 26 0 575 672 ;
|
||||||
|
C -1 ; WX 600 ; N umacron ; B 21 -15 562 565 ;
|
||||||
|
C -1 ; WX 600 ; N Ncaron ; B 7 -13 593 802 ;
|
||||||
|
C 205 ; WX 600 ; N Iacute ; B 96 0 504 805 ;
|
||||||
|
C 177 ; WX 600 ; N plusminus ; B 87 44 513 558 ;
|
||||||
|
C 166 ; WX 600 ; N brokenbar ; B 275 -175 326 675 ;
|
||||||
|
C 174 ; WX 600 ; N registered ; B 0 -18 600 580 ;
|
||||||
|
C -1 ; WX 600 ; N Gbreve ; B 31 -18 575 732 ;
|
||||||
|
C -1 ; WX 600 ; N Idotaccent ; B 96 0 504 753 ;
|
||||||
|
C -1 ; WX 600 ; N summation ; B 15 -10 585 706 ;
|
||||||
|
C 200 ; WX 600 ; N Egrave ; B 53 0 550 805 ;
|
||||||
|
C -1 ; WX 600 ; N racute ; B 60 0 559 672 ;
|
||||||
|
C -1 ; WX 600 ; N omacron ; B 62 -15 538 565 ;
|
||||||
|
C -1 ; WX 600 ; N Zacute ; B 86 0 514 805 ;
|
||||||
|
C 142 ; WX 600 ; N Zcaron ; B 86 0 514 802 ;
|
||||||
|
C -1 ; WX 600 ; N greaterequal ; B 98 0 502 710 ;
|
||||||
|
C 208 ; WX 600 ; N Eth ; B 30 0 574 562 ;
|
||||||
|
C 199 ; WX 600 ; N Ccedilla ; B 41 -151 540 580 ;
|
||||||
|
C -1 ; WX 600 ; N lcommaaccent ; B 95 -250 505 629 ;
|
||||||
|
C -1 ; WX 600 ; N tcaron ; B 87 -15 530 717 ;
|
||||||
|
C -1 ; WX 600 ; N eogonek ; B 66 -172 548 441 ;
|
||||||
|
C -1 ; WX 600 ; N Uogonek ; B 17 -172 583 562 ;
|
||||||
|
C 193 ; WX 600 ; N Aacute ; B 3 0 597 805 ;
|
||||||
|
C 196 ; WX 600 ; N Adieresis ; B 3 0 597 753 ;
|
||||||
|
C 232 ; WX 600 ; N egrave ; B 66 -15 548 672 ;
|
||||||
|
C -1 ; WX 600 ; N zacute ; B 99 0 502 672 ;
|
||||||
|
C -1 ; WX 600 ; N iogonek ; B 95 -172 505 657 ;
|
||||||
|
C 211 ; WX 600 ; N Oacute ; B 43 -18 557 805 ;
|
||||||
|
C 243 ; WX 600 ; N oacute ; B 62 -15 538 672 ;
|
||||||
|
C -1 ; WX 600 ; N amacron ; B 53 -15 559 565 ;
|
||||||
|
C -1 ; WX 600 ; N sacute ; B 80 -15 513 672 ;
|
||||||
|
C 239 ; WX 600 ; N idieresis ; B 95 0 505 620 ;
|
||||||
|
C 212 ; WX 600 ; N Ocircumflex ; B 43 -18 557 787 ;
|
||||||
|
C 217 ; WX 600 ; N Ugrave ; B 17 -18 583 805 ;
|
||||||
|
C -1 ; WX 600 ; N Delta ; B 6 0 598 688 ;
|
||||||
|
C 254 ; WX 600 ; N thorn ; B -6 -157 555 629 ;
|
||||||
|
C 178 ; WX 600 ; N twosuperior ; B 177 249 424 622 ;
|
||||||
|
C 214 ; WX 600 ; N Odieresis ; B 43 -18 557 753 ;
|
||||||
|
C 181 ; WX 600 ; N mu ; B 21 -157 562 426 ;
|
||||||
|
C 236 ; WX 600 ; N igrave ; B 95 0 505 672 ;
|
||||||
|
C -1 ; WX 600 ; N ohungarumlaut ; B 62 -15 580 672 ;
|
||||||
|
C -1 ; WX 600 ; N Eogonek ; B 53 -172 561 562 ;
|
||||||
|
C -1 ; WX 600 ; N dcroat ; B 45 -15 591 629 ;
|
||||||
|
C 190 ; WX 600 ; N threequarters ; B 8 -56 593 666 ;
|
||||||
|
C -1 ; WX 600 ; N Scedilla ; B 72 -151 529 580 ;
|
||||||
|
C -1 ; WX 600 ; N lcaron ; B 95 0 533 629 ;
|
||||||
|
C -1 ; WX 600 ; N Kcommaaccent ; B 38 -250 582 562 ;
|
||||||
|
C -1 ; WX 600 ; N Lacute ; B 47 0 554 805 ;
|
||||||
|
C 153 ; WX 600 ; N trademark ; B -23 263 623 562 ;
|
||||||
|
C -1 ; WX 600 ; N edotaccent ; B 66 -15 548 620 ;
|
||||||
|
C 204 ; WX 600 ; N Igrave ; B 96 0 504 805 ;
|
||||||
|
C -1 ; WX 600 ; N Imacron ; B 96 0 504 698 ;
|
||||||
|
C -1 ; WX 600 ; N Lcaron ; B 47 0 554 562 ;
|
||||||
|
C 189 ; WX 600 ; N onehalf ; B 0 -57 611 665 ;
|
||||||
|
C -1 ; WX 600 ; N lessequal ; B 98 0 502 710 ;
|
||||||
|
C 244 ; WX 600 ; N ocircumflex ; B 62 -15 538 654 ;
|
||||||
|
C 241 ; WX 600 ; N ntilde ; B 26 0 575 606 ;
|
||||||
|
C -1 ; WX 600 ; N Uhungarumlaut ; B 17 -18 590 805 ;
|
||||||
|
C 201 ; WX 600 ; N Eacute ; B 53 0 550 805 ;
|
||||||
|
C -1 ; WX 600 ; N emacron ; B 66 -15 548 565 ;
|
||||||
|
C -1 ; WX 600 ; N gbreve ; B 45 -157 566 609 ;
|
||||||
|
C 188 ; WX 600 ; N onequarter ; B 0 -57 600 665 ;
|
||||||
|
C 138 ; WX 600 ; N Scaron ; B 72 -20 529 802 ;
|
||||||
|
C -1 ; WX 600 ; N Scommaaccent ; B 72 -250 529 580 ;
|
||||||
|
C -1 ; WX 600 ; N Ohungarumlaut ; B 43 -18 580 805 ;
|
||||||
|
C 176 ; WX 600 ; N degree ; B 123 269 477 622 ;
|
||||||
|
C 242 ; WX 600 ; N ograve ; B 62 -15 538 672 ;
|
||||||
|
C -1 ; WX 600 ; N Ccaron ; B 41 -18 540 802 ;
|
||||||
|
C 249 ; WX 600 ; N ugrave ; B 21 -15 562 672 ;
|
||||||
|
C -1 ; WX 600 ; N radical ; B 3 -15 597 792 ;
|
||||||
|
C -1 ; WX 600 ; N Dcaron ; B 43 0 574 802 ;
|
||||||
|
C -1 ; WX 600 ; N rcommaaccent ; B 60 -250 559 441 ;
|
||||||
|
C 209 ; WX 600 ; N Ntilde ; B 7 -13 593 729 ;
|
||||||
|
C 245 ; WX 600 ; N otilde ; B 62 -15 538 606 ;
|
||||||
|
C -1 ; WX 600 ; N Rcommaaccent ; B 38 -250 588 562 ;
|
||||||
|
C -1 ; WX 600 ; N Lcommaaccent ; B 47 -250 554 562 ;
|
||||||
|
C 195 ; WX 600 ; N Atilde ; B 3 0 597 729 ;
|
||||||
|
C -1 ; WX 600 ; N Aogonek ; B 3 -172 608 562 ;
|
||||||
|
C 197 ; WX 600 ; N Aring ; B 3 0 597 750 ;
|
||||||
|
C 213 ; WX 600 ; N Otilde ; B 43 -18 557 729 ;
|
||||||
|
C -1 ; WX 600 ; N zdotaccent ; B 99 0 502 620 ;
|
||||||
|
C -1 ; WX 600 ; N Ecaron ; B 53 0 550 802 ;
|
||||||
|
C -1 ; WX 600 ; N Iogonek ; B 96 -172 504 562 ;
|
||||||
|
C -1 ; WX 600 ; N kcommaaccent ; B 43 -250 580 629 ;
|
||||||
|
C -1 ; WX 600 ; N minus ; B 80 232 520 283 ;
|
||||||
|
C 206 ; WX 600 ; N Icircumflex ; B 96 0 504 787 ;
|
||||||
|
C -1 ; WX 600 ; N ncaron ; B 26 0 575 669 ;
|
||||||
|
C -1 ; WX 600 ; N tcommaaccent ; B 87 -250 530 561 ;
|
||||||
|
C 172 ; WX 600 ; N logicalnot ; B 87 108 513 369 ;
|
||||||
|
C 246 ; WX 600 ; N odieresis ; B 62 -15 538 620 ;
|
||||||
|
C 252 ; WX 600 ; N udieresis ; B 21 -15 562 620 ;
|
||||||
|
C -1 ; WX 600 ; N notequal ; B 15 -16 540 529 ;
|
||||||
|
C -1 ; WX 600 ; N gcommaaccent ; B 45 -157 566 708 ;
|
||||||
|
C 240 ; WX 600 ; N eth ; B 62 -15 538 629 ;
|
||||||
|
C 158 ; WX 600 ; N zcaron ; B 99 0 502 669 ;
|
||||||
|
C -1 ; WX 600 ; N ncommaaccent ; B 26 -250 575 441 ;
|
||||||
|
C 185 ; WX 600 ; N onesuperior ; B 172 249 428 622 ;
|
||||||
|
C -1 ; WX 600 ; N imacron ; B 95 0 505 565 ;
|
||||||
|
C 128 ; WX 600 ; N Euro ; B 0 0 0 0 ;
|
||||||
|
EndCharMetrics
|
||||||
|
EndFontMetrics
|
||||||