fixed a bit of stuff the current but API is broken again for logging in so will be fixing that with the next push

This commit is contained in:
bobbert committed 2025-03-14 19:33:13 +00:00
1 parent 6ad943a868
commit ea38775a82
20 files changed
+1643 -1027

No files matched your search

+44
View File
@@ -0,0 +1,44 @@
/* Login page specific styles */
.loginForm {
display: flex;
flex-direction: column;
width: 100%;
margin-bottom: 8px; /* Reduced spacing (was 15px) */
}
.input-container {
margin-bottom: 10px; /* Add consistent spacing between input fields */
}
.errorMessage {
color: #e53935;
margin-top: 10px;
margin-bottom: 10px; /* Add space after error message */
font-size: 0.875rem;
}
.register-button-container {
margin-top: 5px; /* Reduced spacing (was 10px) */
}
.auth-button {
padding: 10px;
border: none;
border-radius: 4px;
background-color: #68543c; /* Changed back to dark brown */
color: white;
font-size: 16px;
cursor: pointer;
transition: background-color 0.3s;
}
.auth-button:hover {
background-color: #53402d; /* Darker brown on hover */
}
.auth-button:disabled {
background-color: #cccccc;
cursor: not-allowed;
}
/* You can also add other component-specific styles here */
+58 -105
View File
@@ -1,4 +1,5 @@
"use client";
import { useState } from "react";
import { signIn } from "next-auth/react";
import { useRouter } from "next/navigation";
@@ -19,84 +20,39 @@ export default function Login() {
try {
console.log("Attempting to sign in with:", username);
// First try using the NextAuth signIn method
try {
const result = await signIn("credentials", {
redirect: false,
username,
password,
callbackUrl: "/team-selection",
});
const result = await signIn("credentials", {
redirect: false,
username,
password,
callbackUrl: `${window.location.origin}/team-selection`,
});
if (result?.error) {
throw new Error(result.error);
}
console.log("Sign in result:", result);
// If the user has a team, redirect directly to the team page
if (result?.url) {
// Extract the teamId from the URL or session data if available
// This part depends on how your auth system returns the result
router.push(`/${session?.user?.teamId || ""}`);
} else {
// Otherwise go to team selection
router.push("/team-selection");
}
return;
} catch (signInError) {
console.error("Error with signIn method:", signInError);
console.log("Falling back to direct API call");
// Fall back to direct fetch approach with explicit JSON content-type
const loginResponse = await fetch("/api/auth/callback/credentials", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
username,
password,
callbackUrl: "/team-selection",
}),
credentials: "include", // Important for cookie handling
});
if (!loginResponse.ok) {
const errorData = await loginResponse
.json()
.catch(() => ({ error: "Failed to parse error response" }));
throw new Error(
errorData.error ||
`Login failed with status ${loginResponse.status}`
);
}
// On successful login
const userData = await loginResponse
.json()
.catch(() => ({ url: "/team-selection" }));
// Allow time for cookie to be set
setTimeout(() => {
router.push(userData.url || "/team-selection");
}, 100);
if (result?.error) {
throw new Error(result.error);
}
} catch (err) {
setError(err.message || "An unexpected error occurred");
console.error("Login error:", err);
if (result?.ok) {
console.log("Sign in successful, redirecting...");
// Use router.push with { replace: true } to avoid history issues
router.push("/team-selection", { replace: true });
return;
}
} catch (error) {
console.error("Login error:", error);
setError(error.message || "Failed to login. Please try again.");
} finally {
setIsLoading(false);
}
};
return (
<div className="auth-page">
<div className="page-header">
<div className="page-title">Login</div>
<div className="placeholder"></div>
</div>
<div className="auth-container">
<div className="auth-card">
<form onSubmit={handleLogin}>
<h2>Login to Treasure Hunt</h2>
<form onSubmit={handleLogin} className="loginForm">
<div className="input-container">
<input
type="text"
@@ -119,64 +75,61 @@ export default function Login() {
</div>
{error && <div className="error-message">{error}</div>}
<button type="submit" className="auth-button" disabled={isLoading}>
{isLoading ? "Logging in..." : "Log In"}
{isLoading ? "Logging in..." : "Login"}
</button>
</form>
<Link href="/register">
<button className="auth-button">Register</button>
</Link>
{/* Add separate div for register button with margin-top */}
<div className="register-button-container">
<Link href="/register">
<button className="auth-button register-button">Register</button>
</Link>
</div>
</div>
</div>
{/* Update styles to include spacing between buttons */}
<style jsx>{`
.auth-page {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
overflow: hidden;
}
.auth-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
max-width: 400px;
padding: 20px;
box-sizing: border-box;
}
.auth-card {
width: 100%;
padding: 20px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
border-radius: 8px;
background-color: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
.loginForm {
display: flex;
flex-direction: column;
width: 100%;
margin-bottom: 8px; /* Reduced margin below the form (was 15px) */
}
.input-container {
margin-bottom: 10px;
margin-bottom: 10px; /* Add consistent spacing between input fields */
}
.auth-input {
width: 100%;
padding: 10px;
border: 1px solid #ccc;
border-radius: 4px;
.register-button-container {
margin-top: 5px; /* Reduced margin above register button (was 10px) */
}
.auth-button {
width: 100%;
padding: 10px;
margin-top: 10px;
background-color: #68543c; /* Updated brown color */
color: white;
border: none;
border-radius: 4px;
background-color: #68543c; /* Dark brown */
color: white;
font-size: 16px;
cursor: pointer;
text-align: center;
transition: background-color 0.3s;
}
.auth-button:hover {
background-color: #53402d; /* Darker brown on hover */
}
.auth-button:disabled {
background-color: #cccccc;
cursor: not-allowed;
}
.error-message {
color: red;
color: #e53935;
margin-top: 10px;
margin-bottom: 10px;
font-size: 0.875rem;
}
`}</style>
</div>
+25 -69
View File
@@ -194,8 +194,6 @@ export default function TeamPage({ params }) {
) : (
<div className="empty-state">No team members found</div>
)}
{/* Remove the add member button - it was here before */}
</div>
<div className="team-actions">
@@ -243,61 +241,31 @@ export default function TeamPage({ params }) {
try {
setLoading(true);
if (!huntActive) {
// If hunt is not active, redirect to the "not started" page
// Use the dedicated start hunt API endpoint
const response = await fetch("/api/hunt/start", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Cache-Control": "no-cache, no-store, must-revalidate",
},
credentials: "include",
});
const data = await response.json();
if (data.success && data.active) {
// Redirect to map page using window.location for a clean reload
window.location.href = data.redirectUrl || "/map";
} else if (!data.active) {
// Hunt is not active
router.push(`/hunt-not-started?teamId=${teamId}`);
} else {
// If hunt is active, try to start the hunt
const response = await fetch(
`/api/teams/${teamId}/start-hunt`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
credentials: "include",
}
);
if (response.ok) {
fetchTeamData();
} else {
const error = await response.json();
throw new Error(error.message || "Failed to start hunt");
}
// Some other error
throw new Error(data.error || "Failed to start hunt journey");
}
} catch (err) {
setError(err.message);
setLoading(false);
}
}}
>
Start Hunt
</button>
)}
{/* Keep the admin start button which directly starts the hunt */}
{session?.user?.role === "admin" && (
<button
className="action-button start-button"
onClick={async () => {
try {
setLoading(true);
const response = await fetch(
`/api/teams/${teamId}/start-hunt`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
credentials: "include",
}
);
if (response.ok) {
fetchTeamData();
} else {
const error = await response.json();
throw new Error(error.message || "Failed to start hunt");
}
} catch (err) {
setError(err.message);
console.error("Error starting hunt:", err);
setError(`Failed to start hunt: ${err.message}`);
setLoading(false);
}
}}
@@ -352,7 +320,7 @@ export default function TeamPage({ params }) {
.team-info {
flex: 1;
display: flex;
justify-content: space-between;
justify-content: space-between; /* This spreads items to opposite ends */
align-items: center;
}
@@ -360,13 +328,14 @@ export default function TeamPage({ params }) {
margin: 0;
font-size: 24px;
font-weight: bold;
color: white;
color: white; /* Explicitly setting color to white */
}
.team-code {
font-size: 24px;
font-weight: bold;
margin-left: auto;
color: white; /* Ensuring team code is also white */
margin-left: auto; /* Pushes the code to the right */
}
.members-container {
@@ -411,19 +380,6 @@ export default function TeamPage({ params }) {
color: #888;
}
.add-member-button {
background-color: #68543c;
color: white;
border: none;
border-radius: 8px;
padding: 15px;
margin-top: 20px;
width: 100%;
font-size: 16px;
font-weight: bold;
cursor: pointer;
}
.team-actions {
display: flex;
gap: 10px;
+50 -44
View File
@@ -1,68 +1,74 @@
"use client";
import { useState, useEffect } from "react";
import { useSession } from "next-auth/react";
import { useRouter } from "next/navigation";
import { useHuntStatusCheck } from "@/hooks/useHuntStatusCheck";
import Link from "next/link";
import { use } from "react"; // Add this import for React.use()
export default function CluePage({ params }) {
const { clueId } = params;
const { data: session, status } = useSession();
// Unwrap the params Promise using React.use()
const unwrappedParams = use(params);
const { clueId } = unwrappedParams;
const [clue, setClue] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const router = useRouter();
// Add this line to use the hunt status hook
const huntActive = useHuntStatusCheck();
useEffect(() => {
async function checkHuntStatus() {
try {
const response = await fetch("/api/hunt-status", {
credentials: "include",
});
if (response.ok) {
const data = await response.json();
// If hunt is not active, redirect to the home page
if (!data.active) {
router.push("/");
return false;
}
return true;
} else {
console.error("Failed to check hunt status");
return false;
}
} catch (err) {
console.error("Error checking hunt status:", err);
return false;
}
}
async function fetchClueDetails() {
try {
// First verify the hunt is active
const huntIsActive = await checkHuntStatus();
if (!huntIsActive) return;
// Try to check hunt status first with robust error handling
try {
const statusResponse = await fetch("/api/hunt-status", {
credentials: "include",
headers: { Accept: "application/json" },
});
// Fetch the specific clue from the API with improved error handling
const response = await fetch(`/api/clues/${clueId}`, {
credentials: "include",
});
// Read as text first
const statusText = await statusResponse.text();
// Better error handling for non-JSON responses
if (!response.ok) {
const contentType = response.headers.get("content-type");
if (contentType && contentType.includes("application/json")) {
const errorData = await response.json();
throw new Error(errorData.error || "Failed to fetch clue details");
} else {
throw new Error(
`Failed to fetch clue details: ${response.status} ${response.statusText}`
);
try {
const statusData = JSON.parse(statusText);
if (!statusData.active && statusData.authenticated) {
router.push("/");
return;
}
} catch (parseError) {
console.error("Failed to parse hunt status response:", parseError);
// Continue anyway to try fetching clue details
}
} catch (statusErr) {
console.error("Error checking hunt status:", statusErr);
// Continue anyway to try fetching clue details
}
const data = await response.json();
// Now fetch clue details with robust error handling
const response = await fetch(`/api/clues/${clueId}`, {
credentials: "include",
headers: { Accept: "application/json" },
});
// If we got back an error field, show it as an error
// Read as text first
const responseText = await response.text();
// Try to parse as JSON
let data;
try {
data = JSON.parse(responseText);
} catch (parseError) {
console.error("Failed to parse clue details response:", parseError);
console.log("Response received:", responseText.slice(0, 200));
throw new Error("Invalid response from server. Please try again.");
}
// Check for error in the response
if (data.error) {
throw new Error(data.error);
}
+55
View File
@@ -0,0 +1,55 @@
"use client";
import { useState, useEffect } from "react";
import { useSearchParams } from "next/navigation";
// ...other imports
export default function LeaderboardPage() {
const [teams, setTeams] = useState([]);
const [loading, setLoading] = useState(true);
const searchParams = useSearchParams();
const huntJustEnded = searchParams.get("huntEnded") === "true";
// ...existing fetch logic
return (
<div className="leaderboard-page">
<div className="page-header">
<div className="back-button"></div>
<div className="page-title">Leaderboard</div>
</div>
{huntJustEnded && (
<div className="hunt-ended-alert">
<div className="hunt-ended-icon">🎯</div>
<h2>The Hunt Has Ended!</h2>
<p>
The timer has been stopped by an administrator. Here are the final
results.
</p>
</div>
)}
{/* Rest of the leaderboard content */}
{/* ...existing code */}
<style jsx>{`
/* ...existing styles */
.hunt-ended-alert {
background-color: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
border-radius: 8px;
padding: 15px;
margin: 20px;
text-align: center;
}
.hunt-ended-icon {
font-size: 36px;
margin-bottom: 10px;
}
`}</style>
</div>
);
}
+178
View File
@@ -0,0 +1,178 @@
.map-page {
display: flex;
flex-direction: column;
width: 100%;
height: 100vh; /* Full viewport height */
overflow: hidden; /* Hide overflow at page level */
position: relative;
background-color: #69b5a8;
}
.map-banner {
background-color: #68543c;
color: white;
padding: 15px;
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 2px solid #4a3c2a;
z-index: 10;
flex-shrink: 0; /* Prevent banner from shrinking */
}
.team-name {
font-size: 18px;
font-weight: bold;
flex: 1;
text-align: left;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
padding-right: 5px;
}
.elapsed-time {
text-align: center;
padding: 5px 10px;
background-color: rgba(0, 0, 0, 0.2);
border-radius: 8px;
flex: 0 0 auto; /* Don't grow or shrink */
margin: 0 10px;
}
.time-value {
font-size: 18px;
font-weight: bold;
}
.team-code {
font-size: 16px;
font-weight: bold;
flex: 1;
text-align: right;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
padding-left: 5px;
}
/* Map container takes all available space */
.map-container {
flex: 1; /* Take all available space */
overflow: auto; /* Enable scrolling */
position: relative;
width: 100%;
height: 100%;
}
.treasure-map {
width: 100%;
height: 100%;
min-height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.map-svg {
width: 100% !important; /* Override Next.js Image default width */
height: auto !important; /* Override Next.js Image default height */
max-width: none; /* Allow image to grow beyond container */
object-fit: contain;
display: block;
}
.loading-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
width: 100%;
}
.loading-spinner {
border: 4px solid #f3f3f3;
border-top: 4px solid #68543c;
border-radius: 50%;
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
margin-bottom: 20px;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.map-error {
padding: 20px;
text-align: center;
}
/* Navigation bar - now sticky at the bottom */
.nav-bar {
display: flex;
justify-content: space-around;
background-color: white;
border-top: 1px solid #ddd;
padding: 10px 0;
position: sticky; /* Sticky positioning */
bottom: 0; /* Stick to bottom */
left: 0;
width: 100%;
box-sizing: border-box;
z-index: 100; /* Ensure it stays on top */
flex-shrink: 0; /* Prevent navbar from shrinking */
}
.nav-item {
display: flex;
flex-direction: column;
align-items: center;
text-decoration: none;
color: #666;
flex: 1;
padding: 8px 0;
}
.nav-icon {
font-size: 22px;
margin-bottom: 3px;
}
.nav-label {
font-size: 12px;
}
.nav-item.active {
color: #68543c;
}
/* Make sure the map is responsive */
@media (max-width: 480px) {
.team-name {
font-size: 16px;
}
.team-code {
font-size: 14px;
}
.time-value {
font-size: 16px;
}
.nav-icon {
font-size: 20px;
}
.nav-label {
font-size: 11px;
}
}
+181 -316
View File
@@ -1,358 +1,223 @@
"use client";
import { useState, useEffect } from "react";
import { useState, useEffect, useRef } from "react";
import { useSession } from "next-auth/react";
import { useRouter } from "next/navigation";
import Link from "next/link";
import Image from "next/image";
import styles from "./map.module.css";
import { useHuntStatusCheck } from "@/hooks/useHuntStatusCheck";
export default function MapPage() {
const [clues, setClues] = useState([]);
const { data: session, status } = useSession();
const [loading, setLoading] = useState(true);
const [mapError, setMapError] = useState(false);
const [error, setError] = useState(null);
const [huntActive, setHuntActive] = useState(false);
const [teamData, setTeamData] = useState(null);
const [elapsedTime, setElapsedTime] = useState("00:00:00");
const mapContainerRef = useRef(null);
const router = useRouter();
// Use the custom hook to check if hunt is still active
const huntActive = useHuntStatusCheck();
// Debug log for hunt status
useEffect(() => {
async function checkHuntStatus() {
try {
const response = await fetch("/api/hunt-status", {
credentials: "include",
});
console.log("Hunt active status in map page:", huntActive);
}, [huntActive]);
if (response.ok) {
const data = await response.json();
setHuntActive(data.active || false);
// If hunt is not active, redirect to the home page
if (!data.active) {
router.push("/");
return false;
}
return true;
} else {
console.error("Failed to check hunt status");
return false;
}
} catch (err) {
console.error("Error checking hunt status:", err);
return false;
}
useEffect(() => {
// Only redirect if explicitly not authenticated
if (status === "unauthenticated") {
router.push("/login");
return;
}
async function fetchClues() {
try {
// First verify the hunt is active
const huntIsActive = await checkHuntStatus();
if (!huntIsActive) return;
// Fetch the clues from the API with proper error handling
const response = await fetch("/api/clues", {
credentials: "include",
});
// Handle non-OK responses without throwing
if (!response.ok) {
const contentType = response.headers.get("content-type");
if (contentType && contentType.includes("application/json")) {
// If it's JSON, parse it for the error message
const errorData = await response.json();
throw new Error(errorData.error || "Failed to fetch clues");
} else {
// If it's not JSON, use the status text
throw new Error(
`Failed to fetch clues: ${response.status} ${response.statusText}`
);
}
}
// Parse the JSON response
const data = await response.json();
// If we got back an error field, show it as an error
if (data.error) {
throw new Error(data.error);
}
setClues(data.clues || []);
} catch (err) {
console.error("Error fetching clues:", err);
setError(err.message);
} finally {
setLoading(false);
}
// If hunt is not active, redirect to waiting page
if (huntActive === false) {
console.log("Hunt is not active, redirecting to waiting page");
router.push("/waiting");
return;
}
fetchClues();
}, [router]);
// Only fetch team data if authenticated and hunt is active or status unknown
if (status === "authenticated" && huntActive !== false) {
fetchTeamData();
}
}, [status, huntActive, router]);
// Generate random x positions and sort by descending y positions
const generatePositions = (clues) => {
const positions = [];
const maxWidth = 800;
const maxHeight = 500;
const padding = 50;
// Update elapsed time every second
useEffect(() => {
if (!teamData?.team) return;
for (let i = 0; i < clues.length; i++) {
positions.push({
id: clues[i].id,
title: clues[i].title || `Clue ${i + 1}`,
x: Math.random() * (maxWidth - 2 * padding) + padding,
y: (i + 1) * (maxHeight / (clues.length + 1)),
const startTime = new Date(teamData?.huntStartTime || Date.now()).getTime();
const timer = setInterval(() => {
const now = Date.now();
const elapsed = Math.floor((now - startTime) / 1000);
const hours = Math.floor(elapsed / 3600)
.toString()
.padStart(2, "0");
const minutes = Math.floor((elapsed % 3600) / 60)
.toString()
.padStart(2, "0");
const seconds = Math.floor(elapsed % 60)
.toString()
.padStart(2, "0");
setElapsedTime(`${hours}:${minutes}:${seconds}`);
}, 1000);
return () => clearInterval(timer);
}, [teamData]);
const fetchTeamData = async () => {
try {
setLoading(true);
setError(null);
const response = await fetch("/api/user/team", {
method: "GET",
headers: {
"Content-Type": "application/json",
"Cache-Control": "no-cache, no-store, must-revalidate",
},
credentials: "include",
});
}
return positions;
if (!response.ok) {
// Handle specific error cases without immediate redirect
const errorData = await response.json().catch(() => ({}));
if (response.status === 401) {
// Set error but don't redirect immediately - let the session handling take care of it
setError(
"Authentication error: " + (errorData.error || "Not logged in")
);
setLoading(false);
return;
} else if (
response.status === 404 ||
errorData.error?.includes("not part of a team")
) {
setError("You need to join a team before viewing the map");
setLoading(false);
// Give user time to read the error message before redirect
setTimeout(() => router.push("/team-selection"), 2000);
return;
} else {
throw new Error(errorData.error || "Failed to fetch team data");
}
}
const data = await response.json();
setTeamData(data);
setLoading(false);
} catch (err) {
console.error("Error fetching team data:", err);
setError(err.message);
setLoading(false);
}
};
const cluePositions = clues.length > 0 ? generatePositions(clues) : [];
if (loading) {
if (status === "loading" || loading) {
return (
<div className="map-container">
<div className="loading">Loading clues...</div>
<div className={styles["loading-container"]}>
<div className={styles["loading-spinner"]}></div>
<div>Loading map...</div>
</div>
);
}
// If hunt status is known to be inactive, show message
if (huntActive === false) {
return (
<div className={styles["map-error"]}>
<h2>Hunt Not Active</h2>
<p>The treasure hunt has not started yet.</p>
<button onClick={() => router.push("/waiting")}>
Go to Waiting Room
</button>
</div>
);
}
if (error) {
return (
<div className="map-container">
<div className="error">Error: {error}</div>
<button onClick={() => router.push("/")} className="back-button">
Back to Home
</button>
<div className={styles["map-error"]}>
<h2>Error</h2>
<p>{error}</p>
<button onClick={fetchTeamData}>Retry</button>
</div>
);
}
if (clues.length === 0) {
if (mapError) {
return (
<div className="map-container">
<div className="no-clues">No clues available yet.</div>
<button onClick={() => router.push("/")} className="back-button">
Back to Home
</button>
<div className={styles["map-error"]}>
<h2>Error Loading Map</h2>
<p>We couldn't load the treasure map. Please try again.</p>
<button onClick={fetchTeamData}>Retry</button>
</div>
);
}
return (
<div className="map-container">
<h1>Treasure Map</h1>
<div className="map-wrapper">
<svg
className="map-svg"
viewBox="0 0 800 500"
xmlns="http://www.w3.org/2000/svg"
<div className={styles["map-page"]}>
{/* Map Banner with team info and timer */}
<div className={styles["map-banner"]}>
<div className={styles["team-name"]}>
{teamData?.team?.name || "Your Team"}
</div>
<div className={styles["elapsed-time"]}>
<span className={styles["time-value"]}>{elapsedTime}</span>
</div>
<div className={styles["team-code"]}>{teamData?.team?.code || ""}</div>
</div>
{/* Main map content area */}
<div className={styles["map-container"]} ref={mapContainerRef}>
<div className={styles["treasure-map"]}>
{/* Use Image component with fill layout for better SVG handling */}
<Image
src="/images/treasure-map.svg"
alt="Treasure Map"
className={styles["map-svg"]}
width={1000}
height={1000}
priority
onError={() => {
// Fallback to a static image if SVG fails to load
setMapError(true);
}}
/>
</div>
</div>
{/* Navigation bar - now sticky */}
<nav className={styles["nav-bar"]}>
<Link
href={teamData?.teamId ? `/${teamData.teamId}` : "/"}
className={styles["nav-item"]}
>
{/* Map background with a treasure map style */}
<rect width="800" height="500" fill="#f5e6ca" />
<path
d="M0,0 L800,0 L800,500 L0,500 Z"
fill="none"
stroke="#9c6b30"
strokeWidth="10"
/>
{/* Decorative map elements */}
<path
d="M100,100 Q400,50 700,150"
stroke="#9c6b30"
strokeWidth="2"
fill="none"
strokeDasharray="5,5"
/>
<path
d="M150,400 Q400,450 650,350"
stroke="#9c6b30"
strokeWidth="2"
fill="none"
strokeDasharray="5,5"
/>
<path
d="M300,100 Q350,250 300,400"
stroke="#9c6b30"
strokeWidth="2"
fill="none"
strokeDasharray="5,5"
/>
<path
d="M500,100 Q450,250 500,400"
stroke="#9c6b30"
strokeWidth="2"
fill="none"
strokeDasharray="5,5"
/>
{/* Connection lines between clue points */}
{cluePositions.slice(0, -1).map((clue, index) => (
<line
key={`line-${index}`}
x1={clue.x}
y1={clue.y}
x2={cluePositions[index + 1].x}
y2={cluePositions[index + 1].y}
stroke="#9c6b30"
strokeWidth="2"
strokeDasharray="5,5"
/>
))}
{/* Clue points */}
{cluePositions.map((clue, index) => (
<g key={`clue-${index}`} className="clue-point">
<circle
cx={clue.x}
cy={clue.y}
r="15"
fill="#d4a76a"
stroke="#9c6b30"
strokeWidth="2"
onClick={() => router.push(`/clue/${clue.id}`)}
style={{ cursor: "pointer" }}
/>
<text
x={clue.x}
y={clue.y}
textAnchor="middle"
dominantBaseline="central"
fill="#5d4037"
fontSize="12"
fontWeight="bold"
>
{index + 1}
</text>
</g>
))}
</svg>
</div>
{/* Clue list */}
<div className="clue-list">
<h2>Clues</h2>
<ul>
{cluePositions.map((clue, index) => (
<li key={`clue-list-${index}`}>
<Link href={`/clue/${clue.id}`}>
{index + 1}. {clue.title}
</Link>
</li>
))}
</ul>
</div>
<button onClick={() => router.push("/")} className="back-button">
Back to Home
</button>
<style jsx>{`
.map-container {
padding: 20px;
max-width: 1000px;
margin: 0 auto;
text-align: center;
}
h1 {
color: #5d4037;
margin-bottom: 20px;
font-family: "Pirates", cursive, serif;
font-size: 2.5rem;
}
.map-wrapper {
position: relative;
width: 100%;
max-width: 800px;
margin: 0 auto;
border: 5px solid #9c6b30;
border-radius: 10px;
overflow: hidden;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
background: #f5e6ca;
}
.map-svg {
width: 100%;
height: auto;
display: block;
}
.clue-list {
margin-top: 30px;
background: #f5e6ca;
border: 2px solid #9c6b30;
border-radius: 8px;
padding: 15px;
text-align: left;
}
.clue-list h2 {
color: #5d4037;
margin-top: 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
margin: 10px 0;
padding: 8px;
border-bottom: 1px dashed #9c6b30;
}
li:last-child {
border-bottom: none;
}
a {
text-decoration: none;
color: #5d4037;
font-weight: bold;
display: block;
padding: 5px;
transition: all 0.3s ease;
}
a:hover {
background-color: rgba(156, 107, 48, 0.2);
transform: translateX(5px);
}
.back-button {
margin-top: 20px;
padding: 10px 20px;
background-color: #9c6b30;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 1rem;
transition: background-color 0.3s;
}
.back-button:hover {
background-color: #7d562a;
}
.loading,
.error,
.no-clues {
padding: 50px;
border: 2px dashed #9c6b30;
border-radius: 8px;
margin: 30px 0;
color: #5d4037;
background: #f5e6ca;
font-size: 1.2rem;
}
.error {
border-color: #d32f2f;
color: #d32f2f;
}
`}</style>
<div className={styles["nav-icon"]}>🏠</div>
<div className={styles["nav-label"]}>Home</div>
</Link>
<Link href="/leaderboard" className={styles["nav-item"]}>
<div className={styles["nav-icon"]}>📊</div>
<div className={styles["nav-label"]}>Stats</div>
</Link>
<Link href="/team-selection" className={styles["nav-item"]}>
<div className={styles["nav-icon"]}>👥</div>
<div className={styles["nav-label"]}>Team</div>
</Link>
<Link
href="/map"
className={`${styles["nav-item"]} ${styles["active"]}`}
>
<div className={styles["nav-icon"]}>🗺️</div>
<div className={styles["nav-label"]}>Map</div>
</Link>
</nav>
</div>
);
}
+26 -13
View File
@@ -234,27 +234,39 @@ export default function TeamPage({ params }) {
try {
setLoading(true);
// Check hunt status first
// Use try-catch with robust error handling
const response = await fetch("/api/hunt-status", {
method: "GET",
headers: { "Content-Type": "application/json" },
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
credentials: "include",
});
if (response.ok) {
const data = await response.json();
if (data.active) {
// If hunt is active, navigate to map page
router.push("/map");
} else {
// If hunt is not active, show not started page
router.push(`/hunt-not-started?teamId=${teamId}`);
}
if (!response.ok) {
const errorText = await response.text();
console.error("Hunt status error response:", errorText);
throw new Error(
`Failed to check hunt status: ${response.status}`
);
}
const data = await response.json();
console.log("Hunt status response:", data);
// If hunt is active, go directly to the map page using window.location
if (data.active) {
// Use window.location.href for a full page reload to avoid caching issues
window.location.href = "/map";
} else {
throw new Error("Failed to check hunt status");
// If hunt is not active, show the not started page
router.push(`/hunt-not-started?teamId=${teamId}`);
}
} catch (err) {
setError(err.message);
console.error("Error checking hunt status:", err);
setError(`Failed to check hunt status: ${err.message}`);
} finally {
setLoading(false);
}
}}
@@ -483,6 +495,7 @@ export default function TeamPage({ params }) {
.error-icon {
font-size: 48px;
margin-bottom: 20px;
color: #d32f2f;
}
.error-message {
+99 -357
View File
@@ -1,378 +1,83 @@
export const runtime = "nodejs";
import NextAuth from "next-auth"; // <-- Changed from "next-auth/next"
import CredentialsProvider from "next-auth/providers/credentials";
import { validateCredentials } from "@/actions/auth";
import jwt from "jsonwebtoken";
import { cookies } from "next/headers";
import { redirect } from "next/navigation";
// Define hardcoded values for NextAuth
const NEXTAUTH_SECRET = "banana";
const NEXTAUTH_URL = "http://localhost:3000";
// Use a consistent secret for JWT signing and verification
const JWT_SECRET = process.env.NEXTAUTH_SECRET || "banana";
console.log("Using NextAuth Secret:", JWT_SECRET);
// Use hardcoded values instead of environment variables
console.log("Using NextAuth Secret: banana");
console.log(`Using NextAuth URL: ${NEXTAUTH_URL}`);
// Function to create a signed token
function createToken(payload) {
const encodedData = Buffer.from(JSON.stringify(payload)).toString("base64");
const signature = Buffer.from(`${encodedData}.${NEXTAUTH_SECRET}`).toString(
"base64"
);
return `${encodedData}.${signature}`;
}
// Function to verify a token
function verifyToken(token) {
try {
if (!token) return null;
const [encodedData, signature] = token.split(".");
const expectedSignature = Buffer.from(
`${encodedData}.${NEXTAUTH_SECRET}`
).toString("base64");
if (signature !== expectedSignature) return null;
const data = JSON.parse(
Buffer.from(encodedData, "base64").toString("utf-8")
);
// Check if token is expired
if (data.exp && data.exp < Math.floor(Date.now() / 1000)) return null;
return data;
} catch (error) {
console.error("Token verification error:", error);
return null;
}
}
// Create the handler functions directly without calling NextAuth function
export async function GET(request) {
try {
// Safely parse URL with error handling
let pathname = "/";
let searchParams = new URLSearchParams();
try {
if (request && request.url) {
const url = new URL(request.url);
pathname = url.pathname;
searchParams = url.searchParams;
} else {
console.warn("Request or request.url is undefined");
}
} catch (urlError) {
console.error("Failed to parse URL:", urlError);
pathname = request.nextUrl?.pathname || "/api/auth/session";
}
console.log("Auth GET request path:", pathname);
// Handle session requests
if (pathname.includes("/session")) {
try {
const cookieStore = await cookies();
const sessionToken = cookieStore.get("next-auth.session-token")?.value;
if (!sessionToken) {
return Response.json({ user: null });
}
const userData = verifyToken(sessionToken);
return Response.json({
user: userData
? {
id: userData.id,
name: userData.username,
email: `${userData.username}@example.com`, // Next-auth expects an email
image: null,
role: userData.role,
teamId: userData.teamId,
}
: null,
});
} catch (cookieError) {
console.error("Error accessing cookies:", cookieError);
return Response.json({ user: null });
}
}
// For CSRF token requests - IMPORTANT: Return JSON, don't redirect
if (pathname.includes("/csrf")) {
const csrfToken = Buffer.from(
`csrf-${Date.now()}-${NEXTAUTH_SECRET}`
).toString("base64");
return new Response(JSON.stringify({ csrfToken }), {
status: 200,
headers: { "Content-Type": "application/json" },
});
}
// Check if this is a signin request
if (pathname.includes("/signin")) {
// Redirect to the login page with callbackUrl
const callbackUrl = searchParams.get("callbackUrl") || "/";
return Response.redirect(
`${NEXTAUTH_URL}/login?callbackUrl=${encodeURIComponent(callbackUrl)}`
);
}
// Handle providers request
if (pathname.includes("/providers")) {
return Response.json({
credentials: {
id: "credentials",
name: "Credentials",
type: "credentials",
signinUrl: `${NEXTAUTH_URL}/api/auth/signin/credentials`,
callbackUrl: `${NEXTAUTH_URL}/api/auth/callback/credentials`,
},
});
}
// Default: redirect to login
return Response.redirect(`${NEXTAUTH_URL}/login`);
} catch (error) {
console.error("Auth GET error:", error);
return Response.json({ error: "Internal server error" }, { status: 500 });
}
}
export async function POST(request) {
try {
// Debug the actual URL value before trying to parse it
console.log("Raw request URL:", request.url);
// More robust URL parsing
let pathname = "";
let requestUrl = null;
try {
// Add protocol and host if the URL doesn't have them
const urlString = request.url;
// Only try to parse if we have a string
if (typeof urlString === "string" && urlString) {
// Check if URL has proper protocol
const hasProtocol =
urlString.startsWith("http://") || urlString.startsWith("https://");
if (hasProtocol) {
requestUrl = new URL(urlString);
} else {
// Add protocol and host to handle relative URLs
requestUrl = new URL(urlString, "http://localhost:3000");
}
pathname = requestUrl.pathname;
console.log("Successfully parsed URL:", pathname);
} else {
console.log("URL is not valid, using fallback methods");
}
} catch (urlError) {
console.error("Invalid URL in request:", urlError);
}
// Use nextUrl as fallback if available
if (!pathname && request.nextUrl?.pathname) {
pathname = request.nextUrl.pathname;
console.log("Using nextUrl pathname:", pathname);
}
const contentType = request.headers.get("content-type") || "";
console.log("Content-Type:", contentType);
// Check for callback/credentials without relying on URL parsing
const isCallbackRequest =
pathname.includes("/callback/credentials") ||
(request.url && request.url.includes("/callback/credentials"));
if (isCallbackRequest) {
// Extract credentials from the appropriate source based on content type
let username, password, callbackUrl;
if (contentType.includes("application/json")) {
// Handle JSON request
const jsonData = await request.json();
username = jsonData.username;
password = jsonData.password;
callbackUrl = jsonData.callbackUrl || "/team-selection";
console.log("Parsed JSON credentials from callback request");
} else if (
contentType.includes("application/x-www-form-urlencoded") ||
contentType.includes("multipart/form-data")
) {
// Handle form data
const formData = await request.formData();
username = formData.get("username");
password = formData.get("password");
callbackUrl = formData.get("callbackUrl") || "/team-selection";
console.log("Parsed form credentials from callback request");
} else {
return Response.json(
{ error: "Unsupported content type for authentication" },
{ status: 400 }
);
}
console.log(`Credentials callback for user: ${username || "(unknown)"}`);
// Validate credentials
const user = await validateCredentials(username, password);
if (!user) {
return Response.json({ error: "Invalid credentials" }, { status: 401 });
}
// Create token with user data
const token = {
id: user.id,
username: user.username,
role: user.role,
teamId: user.teamId,
iat: Math.floor(Date.now() / 1000),
exp: Math.floor(Date.now() / 1000) + 30 * 24 * 60 * 60, // 30 days
};
// Create JWT-like token
const jwtToken = createToken(token);
// Calculate expiration date for cookie
const expiryDate = new Date();
expiryDate.setDate(expiryDate.getDate() + 30);
// Return success with cookie and redirect URL
return new Response(JSON.stringify({ url: callbackUrl }), {
status: 200,
headers: {
"Content-Type": "application/json",
"Set-Cookie": `next-auth.session-token=${jwtToken}; Path=/; HttpOnly; SameSite=Lax; Expires=${expiryDate.toUTCString()}`,
},
});
}
// Handle regular form submission
let username, password, callbackUrl;
// Handle form data (application/x-www-form-urlencoded)
if (contentType.includes("application/x-www-form-urlencoded")) {
// Clone request to read the body
const clonedRequest = request.clone();
const formText = await clonedRequest.text();
console.log("Form data:", formText);
// Parse form data manually
const params = new URLSearchParams(formText);
username = params.get("username");
password = params.get("password");
callbackUrl = params.get("callbackUrl") || "/team-selection";
console.log("Parsed credentials:", {
username,
password: password ? "[REDACTED]" : undefined,
});
}
// Handle JSON
else if (contentType.includes("application/json")) {
const jsonData = await request.json();
username = jsonData.username;
password = jsonData.password;
callbackUrl = jsonData.callbackUrl || "/team-selection";
}
// Try form data as a last resort
else {
try {
const formData = await request.formData();
username = formData.get("username");
password = formData.get("password");
callbackUrl = formData.get("callbackUrl") || "/team-selection";
} catch (formError) {
console.error("Form data parsing error:", formError);
// Instead of returning an error, log and continue - the request might be something else
}
}
if (!username || !password) {
// If no credentials were found, this might be a different kind of request
// Log it and return an appropriate error
console.error("Missing credentials in request");
return Response.json(
{ error: "Username and password required" },
{ status: 400 }
);
}
// Validate credentials
const user = await validateCredentials(username, password);
if (!user) {
return Response.json({ error: "Invalid credentials" }, { status: 401 });
}
// Create token with user data
const token = {
id: user.id,
username: user.username,
role: user.role,
teamId: user.teamId,
iat: Math.floor(Date.now() / 1000),
exp: Math.floor(Date.now() / 1000) + 30 * 24 * 60 * 60, // 30 days
};
// Create JWT-like token
const jwtToken = createToken(token);
// Calculate expiration date for cookie
const expiryDate = new Date();
expiryDate.setDate(expiryDate.getDate() + 30);
// Return success with cookie and redirect URL
return new Response(
JSON.stringify({
ok: true,
url: callbackUrl,
}),
{
status: 200,
headers: {
"Content-Type": "application/json",
"Set-Cookie": `next-auth.session-token=${jwtToken}; Path=/; HttpOnly; SameSite=Lax; Expires=${expiryDate.toUTCString()}`,
},
}
);
} catch (error) {
console.error("Auth POST error:", error);
return Response.json({ error: "Internal server error" }, { status: 500 });
}
}
// Export authOptions for compatibility with other code using getServerSession
export const authOptions = {
providers: [
// Correct syntax: no function call, just reference the imported object
{
id: "credentials",
name: "Credentials",
type: "credentials",
authorize: async (credentials) => {
if (!credentials?.username || !credentials?.password) return null;
return await validateCredentials(
credentials.username,
credentials.password
);
credentials: {
username: { label: "Username", type: "text" },
password: { label: "Password", type: "password" },
},
async authorize(credentials) {
try {
if (!credentials?.username || !credentials?.password) {
console.log("Missing credentials");
return null;
}
// Validate credentials against our database
const user = await validateCredentials(
credentials.username,
credentials.password
);
if (user) {
console.log("User authenticated:", user.username);
return user;
}
console.log("Invalid credentials for:", credentials.username);
return null;
} catch (error) {
console.error("Authentication error:", error);
return null;
}
},
},
],
session: {
strategy: "jwt",
maxAge: 30 * 24 * 60 * 60, // 30 days
},
jwt: {
secret: JWT_SECRET,
encode: async ({ secret, token }) => {
return jwt.sign(token, secret);
},
decode: async ({ secret, token }) => {
try {
return jwt.verify(token, secret);
} catch (error) {
console.error("JWT decode error:", error);
return null;
}
},
},
callbacks: {
async jwt({ token, user }) {
if (user) {
token.id = user.id;
token.role = user.role;
token.username = user.username;
token.teamId = user.teamId;
token.teamId = user.team_id || user.teamId;
}
return token;
},
async session({ session, token }) {
if (token) {
session.user = session.user || {};
@@ -384,9 +89,46 @@ export const authOptions = {
return session;
},
},
session: { strategy: "jwt", maxAge: 30 * 24 * 60 * 60 },
secret: NEXTAUTH_SECRET,
pages: {
signIn: "/login",
error: "/login?error=true",
},
// Add debugging to help identify issues with API responses
debug: process.env.NODE_ENV === "development",
// Add logger to catch issues
logger: {
error(code, metadata) {
console.error(`NextAuth error: ${code}`, metadata);
},
warn(code) {
console.warn(`NextAuth warning: ${code}`);
},
debug(code, metadata) {
console.log(`NextAuth debug: ${code}`, metadata);
},
},
};
// Export the token functions directly for use in other files
export { createToken, verifyToken };
// Token helpers
export function createToken(payload) {
return jwt.sign(payload, JWT_SECRET, { expiresIn: "30d" });
}
export function verifyToken(token) {
try {
return jwt.verify(token, JWT_SECRET);
} catch (error) {
console.error("Token verification error:", error);
return null;
}
}
// Set session runtime to nodejs (not edge for better compatibility)
export const runtime = "nodejs";
// Create the handler with correct NextAuth instantiation
const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };
+35 -30
View File
@@ -9,38 +9,41 @@ export async function GET(request, { params }) {
const { clueId } = params;
try {
// Verify the user is authenticated
const cookieStore = await cookies();
const sessionToken = cookieStore.get("next-auth.session-token")?.value;
if (!sessionToken) {
return Response.json(
{ error: "Unauthorized", clue: null },
{ status: 401 }
);
}
const userData = verifyToken(sessionToken);
if (!userData) {
return Response.json(
{ error: "Invalid session", clue: null },
{ status: 401 }
);
}
// Check if the hunt is active
// Check if the hunt is active first
const huntActiveSetting = await queryOne(
"SELECT value FROM settings WHERE key = 'hunt_active'"
);
const huntActive = huntActiveSetting && huntActiveSetting.value === "true";
// Only verify authentication when hunt is not active
if (!huntActive) {
// Return a valid JSON response with clue set to null
return Response.json({
error: "Hunt is not active",
clue: null,
});
const cookieStore = await cookies();
const sessionToken =
cookieStore.get("next-auth.session-token")?.value ||
cookieStore.get("__Secure-next-auth.session-token")?.value;
if (!sessionToken) {
return Response.json(
{ error: "Unauthorized", clue: null },
{ status: 401, headers: { "Content-Type": "application/json" } }
);
}
const userData = verifyToken(sessionToken);
if (!userData) {
return Response.json(
{ error: "Invalid session", clue: null },
{ status: 401, headers: { "Content-Type": "application/json" } }
);
}
// Admin can see clues even if hunt is not active
if (userData.role !== "admin") {
return Response.json(
{ error: "Hunt is not active", clue: null },
{ headers: { "Content-Type": "application/json" } }
);
}
}
// Fetch the specific clue
@@ -49,17 +52,19 @@ export async function GET(request, { params }) {
if (!clue) {
return Response.json(
{ error: "Clue not found", clue: null },
{ status: 404 }
{ status: 404, headers: { "Content-Type": "application/json" } }
);
}
return Response.json({ clue });
return Response.json(
{ clue },
{ headers: { "Content-Type": "application/json" } }
);
} catch (error) {
console.error("Error fetching clue details:", error);
// Always return a valid JSON response even on error
return Response.json(
{ error: "Failed to fetch clue details: " + error.message, clue: null },
{ status: 500 }
{ status: 500, headers: { "Content-Type": "application/json" } }
);
}
}
+71 -48
View File
@@ -4,21 +4,18 @@ import { verifyToken } from "@/app/api/auth/[...nextauth]/route";
export const dynamic = "force-dynamic"; // Disable caching
// Helper function to ensure the clues table exists (if not already created elsewhere)
// Helper function to ensure the clues table exists
async function ensureCluesTableExists() {
try {
// Create the clues table if it doesn't exist
await run(`
CREATE TABLE IF NOT EXISTS clues (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
description TEXT NOT NULL,
location TEXT,
order_number INTEGER,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`);
return true;
} catch (error) {
console.error("Error ensuring clues table exists:", error);
@@ -26,79 +23,105 @@ async function ensureCluesTableExists() {
}
}
// Helper function to extract numeric value from clue title
function extractClueNumber(title) {
// Look for patterns like "Clue 1", "Clue 10", etc.
const match = title.match(/Clue\s+(\d+)/i);
// If we find a match, return the number, otherwise return Infinity (to sort to the end)
return match ? parseInt(match[1], 10) : Infinity;
}
// GET endpoint to retrieve all clues
export async function GET(request) {
try {
// Verify the user is authenticated
const cookieStore = await cookies();
const sessionToken = cookieStore.get("next-auth.session-token")?.value;
// First check if the hunt is active
const huntActiveSetting = await queryOne(
"SELECT value FROM settings WHERE key = 'hunt_active'"
);
const huntActive = huntActiveSetting && huntActiveSetting.value === "true";
if (!sessionToken) {
return Response.json(
{ error: "Unauthorized", clues: [] },
{ status: 401 }
);
}
// If hunt is active, allow access without authentication
if (!huntActive) {
// Only verify authentication when hunt is not active
const cookieStore = await cookies();
const sessionToken =
cookieStore.get("next-auth.session-token")?.value ||
cookieStore.get("__Secure-next-auth.session-token")?.value;
const userData = verifyToken(sessionToken);
if (!userData) {
return Response.json(
{ error: "Invalid session", clues: [] },
{ status: 401 }
);
if (!sessionToken) {
return Response.json(
{ error: "Unauthorized", clues: [] },
{ status: 401, headers: { "Content-Type": "application/json" } }
);
}
const userData = verifyToken(sessionToken);
if (!userData) {
return Response.json(
{ error: "Invalid session", clues: [] },
{ status: 401, headers: { "Content-Type": "application/json" } }
);
}
// Admin can see clues even if hunt is not active
if (userData.role !== "admin") {
return Response.json(
{ error: "Hunt is not active", clues: [] },
{ headers: { "Content-Type": "application/json" } }
);
}
}
// Ensure the clues table exists
await ensureCluesTableExists();
// Check if the hunt is active
const huntActiveSetting = await queryOne(
"SELECT value FROM settings WHERE key = 'hunt_active'"
);
const huntActive = huntActiveSetting && huntActiveSetting.value === "true";
if (!huntActive) {
// Return empty clues array instead of error status to avoid redirect issues
return Response.json({
error: "Hunt is not active",
clues: [],
});
}
// Fetch all clues
const clues = await query("SELECT * FROM clues ORDER BY order_number ASC");
// Fetch all clues without sorting in SQL
const clues = await query("SELECT * FROM clues");
// If no clues are found, insert sample clues (for testing purposes)
if (!clues || clues.length === 0) {
// Insert sample clues
await run(
"INSERT INTO clues (title, description, location, order_number) VALUES (?, ?, ?, ?)",
["First Clue", "This is the first clue description", "Location 1", 1]
"INSERT INTO clues (title, description, location) VALUES (?, ?, ?)",
["Clue 1", "This is the first clue description", "Location 1"]
);
await run(
"INSERT INTO clues (title, description, location, order_number) VALUES (?, ?, ?, ?)",
["Second Clue", "This is the second clue description", "Location 2", 2]
"INSERT INTO clues (title, description, location) VALUES (?, ?, ?)",
["Clue 2", "This is the second clue description", "Location 2"]
);
await run(
"INSERT INTO clues (title, description, location, order_number) VALUES (?, ?, ?, ?)",
["Final Clue", "This is the final clue description", "Location 3", 3]
"INSERT INTO clues (title, description, location) VALUES (?, ?, ?)",
["Clue 3", "This is the final clue description", "Location 3"]
);
// Fetch the inserted clues
const sampleClues = await query(
"SELECT * FROM clues ORDER BY order_number ASC"
const sampleClues = await query("SELECT * FROM clues");
// Sort clues based on numbering in title
sampleClues.sort(
(a, b) => extractClueNumber(a.title) - extractClueNumber(b.title)
);
return Response.json(
{ clues: sampleClues },
{ headers: { "Content-Type": "application/json" } }
);
return Response.json({ clues: sampleClues });
}
return Response.json({ clues });
// Sort clues based on numbering in title
clues.sort(
(a, b) => extractClueNumber(a.title) - extractClueNumber(b.title)
);
return Response.json(
{ clues },
{ headers: { "Content-Type": "application/json" } }
);
} catch (error) {
console.error("Error fetching clues:", error);
// Always return a valid JSON response even on error
return Response.json(
{ error: "Failed to fetch clues: " + error.message, clues: [] },
{ status: 500 }
{ status: 500, headers: { "Content-Type": "application/json" } }
);
}
}
+82 -42
View File
@@ -4,59 +4,99 @@ import { verifyToken } from "@/app/api/auth/[...nextauth]/route";
export const dynamic = "force-dynamic"; // Disable caching
// Helper function to ensure the hunt_status table exists
async function ensureHuntStatusTableExists() {
try {
// Create hunt_status table if it doesn't exist
await run(`
CREATE TABLE IF NOT EXISTS hunt_status (
id INTEGER PRIMARY KEY CHECK (id = 1),
is_active BOOLEAN DEFAULT 0,
start_time TEXT,
end_time TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`);
// Check if we need to insert the initial record
const status = await queryOne("SELECT * FROM hunt_status LIMIT 1");
if (!status) {
await run(
"INSERT INTO hunt_status (id, is_active, start_time) VALUES (1, 0, NULL)"
);
console.log("Initialized hunt_status table with default record");
}
return true;
} catch (error) {
console.error("Error ensuring hunt_status table:", error);
return false;
}
}
// GET endpoint to check if the hunt is active
export async function GET(request) {
try {
// Verify the user is authenticated
// First ensure the table exists
await ensureHuntStatusTableExists();
// Get the token from cookies - properly awaited
const cookieStore = await cookies();
const sessionToken = cookieStore.get("next-auth.session-token")?.value;
if (!sessionToken) {
return Response.json({ error: "Unauthorized" }, { status: 401 });
// Check hunt status even if user is not authenticated
// to prevent auth errors from interfering with status checks
// First check the hunt_status table for direct status
const huntStatus = await queryOne(
"SELECT is_active, start_time FROM hunt_status LIMIT 1"
).catch((err) => {
console.warn("Error querying hunt_status:", err.message);
return null;
});
// Then check the settings table as a backup
const huntActiveSetting = await queryOne(
"SELECT value FROM settings WHERE key = 'hunt_active'"
).catch((err) => {
console.warn("Error querying settings:", err.message);
return null;
});
// Also check the hunts table if it exists (for backward compatibility)
const oldHuntRecord = await queryOne(
"SELECT active, start_time FROM hunts ORDER BY id DESC LIMIT 1"
).catch((err) => {
// Ignore errors if table doesn't exist
return null;
});
// Determine active status from all available sources
let isActive = false;
let startTime = null;
// First priority: hunt_status.is_active
if (huntStatus && huntStatus.is_active !== null) {
isActive = Boolean(huntStatus.is_active);
startTime = huntStatus.start_time;
}
// Second priority: settings table
else if (huntActiveSetting) {
isActive = huntActiveSetting.value === "true";
}
// Third priority: old hunts table
else if (oldHuntRecord) {
isActive = Boolean(oldHuntRecord.active);
startTime = oldHuntRecord.start_time;
}
const userData = verifyToken(sessionToken);
if (!userData) {
return Response.json({ error: "Invalid session" }, { status: 401 });
}
console.log("Hunt status check:", { isActive, startTime });
let huntActive = false;
try {
// First try to create the settings table if it doesn't exist
await run(`
CREATE TABLE IF NOT EXISTS settings (
key TEXT PRIMARY KEY,
value TEXT NOT NULL
)
`);
// Check if hunt_active setting exists
const huntSetting = await queryOne(
"SELECT value FROM settings WHERE key = 'hunt_active'"
);
// If the setting exists, use its value
if (huntSetting) {
huntActive = huntSetting.value === "true";
} else {
// If setting doesn't exist, create it with default value "false"
await run(
"INSERT OR IGNORE INTO settings (key, value) VALUES (?, ?)",
["hunt_active", "false"]
);
}
} catch (dbError) {
console.error("Database error in hunt-status:", dbError);
// Continue with default value if there's a DB error
}
// Return the active status
return Response.json({
active: huntActive,
timestamp: new Date().toISOString(),
active: isActive,
startTime: startTime || null,
});
} catch (error) {
console.error("Hunt status check error:", error);
console.error("Error checking hunt status:", error);
return Response.json(
{ error: "Failed to check hunt status", active: false },
{ status: 500 }
+132
View File
@@ -0,0 +1,132 @@
import { getServerSession } from "next-auth/next";
import { authOptions, verifyToken } from "../../auth/[...nextauth]/route";
import { query, queryOne, run } from "../../../../lib/db";
import { cookies } from "next/headers";
export const dynamic = "force-dynamic"; // Disable caching
// Helper function to ensure the hunt_status table exists
async function ensureHuntStatusTableExists() {
try {
// Create hunt_status table if it doesn't exist
await run(`
CREATE TABLE IF NOT EXISTS hunt_status (
id INTEGER PRIMARY KEY CHECK (id = 1),
is_active BOOLEAN DEFAULT 0,
start_time TEXT,
end_time TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`);
// Check if we need to insert the initial record
const status = await queryOne("SELECT * FROM hunt_status LIMIT 1");
if (!status) {
await run(
"INSERT INTO hunt_status (id, is_active, start_time) VALUES (1, 0, NULL)"
);
}
return true;
} catch (error) {
console.error("Error ensuring hunt_status table:", error);
return false;
}
}
// Fallback function to get user data when session fails
async function getUserFromToken() {
try {
const cookieStore = await cookies();
const sessionToken = cookieStore.get("next-auth.session-token")?.value;
if (!sessionToken) return null;
const userData = verifyToken(sessionToken);
if (!userData) return null;
// Verify that the user exists and get their role
const user = await queryOne("SELECT id, role FROM users WHERE id = ?", [
userData.id || userData.sub,
]);
return user;
} catch (error) {
console.error("Error getting user from token:", error);
return null;
}
}
export async function POST(request) {
try {
// First ensure the table exists
await ensureHuntStatusTableExists();
// Try to get session, with fallback to token-based auth
let user = null;
let session = null;
try {
session = await getServerSession(authOptions);
user = session?.user;
} catch (sessionError) {
console.warn(
"Session error, trying fallback auth:",
sessionError.message
);
user = await getUserFromToken();
}
// Verify the user is authenticated
if (!user) {
return Response.json({ error: "Unauthorized" }, { status: 401 });
}
// Check if user is admin
if (user.role !== "admin") {
return Response.json(
{ error: "Only admins can start the hunt" },
{ status: 403 }
);
}
// Check if hunt is already in progress
const huntStatus = await queryOne("SELECT * FROM hunt_status LIMIT 1");
if (huntStatus && huntStatus.is_active) {
return Response.json(
{ error: "Hunt is already in progress" },
{ status: 400 }
);
}
// Start the hunt by updating the status
const now = new Date().toISOString();
// Update the hunt_status table
await run(
`UPDATE hunt_status SET is_active = ?, start_time = ? WHERE id = 1`,
[true, now]
);
// Also update settings table for compatibility
try {
await run("INSERT OR REPLACE INTO settings (key, value) VALUES (?, ?)", [
"hunt_active",
"true",
]);
} catch (err) {
console.log(
"Could not update settings table (might not exist yet):",
err.message
);
}
return Response.json(
{ success: true, message: "Hunt started successfully", startTime: now },
{ status: 200 }
);
} catch (error) {
console.error("Start hunt error:", error);
return Response.json({ error: "Failed to start hunt" }, { status: 500 });
}
}
+94
View File
@@ -0,0 +1,94 @@
import { getServerSession } from "next-auth/next";
import { authOptions } from "../../auth/[...nextauth]/route";
import { query, queryOne } from "../../../../lib/db";
export async function GET(request) {
try {
// Get the user's session with better error handling
let session;
try {
session = await getServerSession(authOptions);
} catch (sessionError) {
console.error("Session fetch error:", sessionError);
return Response.json(
{ error: "Authentication error", details: sessionError.message },
{ status: 401 }
);
}
// Check if user is authenticated
if (!session || !session.user) {
return Response.json({ error: "You must be logged in" }, { status: 401 });
}
// Check if user is part of a team
if (!session.user.teamId) {
return Response.json(
{ error: "You are not part of a team" },
{ status: 404 }
);
}
// Fetch team data
const team = await queryOne("SELECT * FROM teams WHERE id = ?", [
session.user.teamId,
]);
if (!team) {
return Response.json({ error: "Team not found" }, { status: 404 });
}
// Fetch team members
const members = await query(
"SELECT id, username FROM users WHERE team_id = ? ORDER BY username ASC",
[session.user.teamId]
);
// Fetch hunt status to provide start time - safely check multiple places
let huntStartTime = null;
try {
// Try hunt_status table first
const huntStatus = await queryOne("SELECT * FROM hunt_status LIMIT 1");
if (huntStatus) {
huntStartTime = huntStatus.start_time;
} else {
// Fallback to hunts table if it exists
const oldHuntRecord = await queryOne(
"SELECT start_time FROM hunts ORDER BY id DESC LIMIT 1"
);
if (oldHuntRecord) {
huntStartTime = oldHuntRecord.start_time;
}
}
} catch (err) {
console.log("Error fetching hunt status (non-critical):", err.message);
// Continue even if hunt status check fails
}
// Add cache-busting headers
return Response.json(
{
success: true,
team,
members,
huntStartTime: huntStartTime,
refreshed: new Date().toISOString(),
},
{
status: 200,
headers: {
"Cache-Control": "no-store, must-revalidate, max-age=0",
Pragma: "no-cache",
Expires: "0",
},
}
);
} catch (error) {
console.error("Team fetch error:", error);
return Response.json(
{ error: "Failed to fetch team data" },
{ status: 500 }
);
}
}
+11 -3
View File
@@ -1,7 +1,15 @@
'use client';
"use client";
import { SessionProvider } from "next-auth/react";
export function NextAuthProvider({ children }) {
return <SessionProvider>{children}</SessionProvider>;
}
// Add options to help debug the issue
return (
<SessionProvider
refetchInterval={0} // Disable background refetching during debug
refetchOnWindowFocus={false} // Disable refetching when window gets focus
>
{children}
</SessionProvider>
);
}
+87
View File
@@ -0,0 +1,87 @@
"use client";
import { useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import { useSession } from "next-auth/react";
import styles from "./waiting.module.css";
export default function WaitingPage() {
const router = useRouter();
const { status } = useSession();
const [huntActive, setHuntActive] = useState(false);
const [loading, setLoading] = useState(true);
// Check hunt status
useEffect(() => {
// Function to check hunt status
async function checkHuntStatus() {
try {
const response = await fetch("/api/hunt-status", {
method: "GET",
headers: {
"Content-Type": "application/json",
"Cache-Control": "no-store, no-store, must-revalidate",
},
credentials: "include",
});
if (response.ok) {
const data = await response.json();
console.log("Hunt status from waiting page:", data);
// If hunt is active, redirect to map page
if (data.active) {
console.log("Hunt is active! Redirecting to map page");
router.push("/map");
}
// Update local state
setHuntActive(data.active);
}
setLoading(false);
} catch (err) {
console.error("Error checking hunt status:", err);
setLoading(false);
}
}
// Check on load and every 5 seconds
checkHuntStatus();
const intervalId = setInterval(checkHuntStatus, 5000);
return () => clearInterval(intervalId);
}, [router]);
// Redirect to login if not authenticated
useEffect(() => {
if (status === "unauthenticated") {
router.push("/login");
}
}, [status, router]);
if (loading) {
return (
<div className={styles.container}>
<div className={styles.spinner}></div>
<h2>Loading...</h2>
</div>
);
}
return (
<div className={styles.container}>
<h1>Waiting for Hunt to Start</h1>
<p>
The treasure hunt has not started yet. Please wait for the administrator
to start the hunt.
</p>
<div className={styles.waitingAnimation}>⏳</div>
{huntActive && (
<div className={styles.startedMessage}>
<p>The hunt has started!</p>
<button onClick={() => router.push("/map")}>Go to Map</button>
</div>
)}
</div>
);
}
BIN
View File
Binary file not shown.
+58
View File
@@ -0,0 +1,58 @@
"use client";
import { useState, useEffect } from "react";
import { useRouter } from "next/navigation";
export function useHuntStatusCheck(checkIntervalMs = 5000) {
const [huntActive, setHuntActive] = useState(null); // Start with null to indicate unknown status
const router = useRouter();
useEffect(() => {
// Initial check
checkHuntStatus();
// Set up interval for periodic checks
const intervalId = setInterval(checkHuntStatus, checkIntervalMs);
// Clean up on unmount
return () => clearInterval(intervalId);
// Function to check hunt status
async function checkHuntStatus() {
try {
const response = await fetch("/api/hunt-status", {
method: "GET",
headers: {
"Content-Type": "application/json",
"Cache-Control": "no-cache, no-store, must-revalidate",
},
credentials: "include",
});
if (response.ok) {
const data = await response.json();
console.log("Hunt status check:", data); // Debug log
// If hunt was active but is now inactive, redirect to leaderboard
if (huntActive === true && data.active === false) {
console.log("Hunt has ended! Redirecting to leaderboard...");
window.location.href = "/leaderboard?huntEnded=true";
return;
}
// If hunt was not active but is now active, let user know they can go to map page
if (huntActive === false && data.active === true) {
console.log("Hunt has started! Access to map is now available");
// Can show a notification here if desired
}
// Update hunt status state
setHuntActive(data.active);
}
} catch (err) {
console.error("Failed to check hunt status:", err);
}
}
}, [huntActive, checkIntervalMs, router]);
return huntActive;
}
+1
View File
@@ -0,0 +1 @@
// This would be a new image file you need to add to your project
+356
View File
@@ -0,0 +1,356 @@
<svg width="430" height="2155" viewBox="0 0 430 2155" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<mask id="mask0_37_192" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="430" height="2155">
<rect width="430" height="2155" fill="#D9D9D9"/>
</mask>
<g mask="url(#mask0_37_192)">
<path d="M430.503 1L39.3446 1C104.063 63.7386 204.551 197.004 88.7568 228.157C-27.0374 259.31 69.7905 379.595 132.679 435.843C184.586 486.863 272.83 592.473 210.54 606.752C132.679 624.6 11.7469 796.59 32.7097 904.76C32.7097 904.76 75.6357 1088.65 171.962 1195.74C268.289 1302.83 130.075 1334.86 65.6512 1413.16C28.7168 1458.05 -16.374 1862.94 54.5001 1877C111.199 1888.25 47.5001 1973 73.5001 2016C73.5001 2016 142.883 2048.24 163 2056C248.5 2089 270.291 2128.5 307 2128.5C364.212 2128.5 368.788 2157.5 426 2157.5C450.603 2157.5 432 1987 432 1987C428.506 1878.83 430.503 1 430.503 1Z" fill="#D6B23D" stroke="black" stroke-width="3" stroke-linecap="round"/>
<path d="M431.489 1L74.3623 1C142.53 63.7386 248.374 197.004 126.408 228.157C4.44207 259.31 106.431 379.595 172.671 435.843C227.346 486.863 320.292 592.473 254.683 606.752C172.671 624.6 92.6494 729.137 80.1452 775.497C52.2822 878.799 434.854 950.215 434.854 1027.51L431.489 1Z" fill="#614723"/>
<path d="M435.528 1232.93C435.528 1378.95 71.8716 1581.04 55.9623 1625.71C32.0496 1692.85 3.39064 1852.87 78.0423 1866.93C137.764 1878.18 124.305 1951.66 110.111 1987C95.9167 2022.34 170.5 2024.5 231 2032.5C291.5 2040.5 361.985 2162.28 416.5 2106.5C449.643 2072.59 438 1987 438 1987L435.528 1232.93Z" fill="#614723"/>
<path d="M431.489 1L74.3623 1C142.53 63.7386 248.374 197.004 126.408 228.157C4.44207 259.31 106.431 379.595 172.671 435.843C227.346 486.863 320.292 592.473 254.683 606.752C172.671 624.6 92.6494 729.137 80.1452 775.497C52.2822 878.799 434.854 950.215 434.854 1027.51L431.489 1ZM431.489 1L438 1987M438 1987L435.528 1232.93C435.528 1378.95 71.8716 1581.04 55.9623 1625.71C32.0496 1692.85 3.39064 1852.87 78.0423 1866.93C137.764 1878.18 124.305 1951.66 110.111 1987C95.9167 2022.34 170.5 2024.5 231 2032.5C291.5 2040.5 361.985 2162.28 416.5 2106.5C449.643 2072.59 438 1987 438 1987Z" stroke="black" stroke-width="3" stroke-linecap="round"/>
<path d="M92.6168 1H428V964.253V1366.65V1987C428 1987 432.5 2043 410.5 2059.5C388.5 2076 355 1991 318 1982.5C281 1974 197.5 1956.5 197.5 1956.5C138.5 1945 152.986 1878.18 96.1208 1866.93C25.0396 1852.87 46.498 1687.74 81.6042 1627.88C113.641 1573.25 360.923 1487.8 428 1366.65V964.253C332.724 903.678 71.5928 878.799 98.1231 775.497C110.029 729.137 186.224 624.6 264.313 606.752C326.784 592.473 238.283 486.863 186.224 435.843C123.152 379.595 26.0407 259.31 142.173 228.157C258.306 197.004 157.524 63.7386 92.6168 1Z" fill="#519D48"/>
<path d="M428 964.253C332.724 903.678 71.5928 878.799 98.1231 775.497C110.029 729.137 186.224 624.6 264.313 606.752C326.784 592.473 238.283 486.863 186.224 435.843C123.152 379.595 26.0407 259.31 142.173 228.157C258.306 197.004 157.524 63.7386 92.6168 1H428V1987C428 1987 432.5 2043 410.5 2059.5C388.5 2076 355 1991 318 1982.5C281 1974 197.5 1956.5 197.5 1956.5C138.5 1945 152.986 1878.18 96.1208 1866.93C25.0396 1852.87 46.498 1687.74 81.6042 1627.88C113.641 1573.25 360.923 1487.8 428 1366.65" stroke="black" stroke-width="3" stroke-linecap="round"/>
<path d="M232 212C259.667 248 347.7 280.3 322.5 291.5C291 305.5 248.5 388 265 400C281.5 412 360 514 342.5 522C325 530 326.5 647.5 315.5 654C304.5 660.5 301.47 760.917 294.5 777C281.5 807 231.5 852.5 231.5 880.5C231.5 894.037 380.326 961.248 361.5 966C310 979 269.5 1017.5 259.5 1042C236.116 1099.29 300.5 1163 281 1174C261.5 1185 322 1286.5 338.5 1305C346.591 1314.07 299.759 1348.96 252 1388C202.369 1428.57 151.539 1473.46 149.5 1489C145.62 1518.59 304.498 1509.34 313.5 1534C325 1565.5 349.095 1642.86 345 1649C317 1691 282 1702.5 228 1725.5C203.98 1735.73 204.261 1818.88 238.5 1860.5C273.981 1903.63 334.805 1912.57 365 1923C395.195 1933.43 304 2045 304 2045" stroke="white" stroke-width="3" stroke-linecap="round" stroke-dasharray="10 10"/>
<rect x="329" y="767" width="88" height="88" fill="url(#pattern0_37_192)"/>
<rect x="45" y="934" width="88" height="88" fill="url(#pattern1_37_192)"/>
<rect x="147" y="1949" width="88" height="88" fill="url(#pattern2_37_192)"/>
<rect x="153" y="334" width="88" height="88" fill="url(#pattern3_37_192)"/>
<rect width="85.7722" height="88" transform="matrix(-1 0 0 1 417 1189)" fill="url(#pattern4_37_192)"/>
<rect x="49" y="1520" width="88" height="88" fill="url(#pattern5_37_192)"/>
<rect x="57" y="1778" width="88" height="88" fill="url(#pattern6_37_192)"/>
<rect x="137" y="1115" width="88" height="88" fill="url(#pattern7_37_192)"/>
<rect x="362" y="284" width="88" height="88" fill="url(#pattern8_37_192)"/>
<rect x="5" y="1245" width="88" height="88" fill="url(#pattern9_37_192)"/>
<rect x="181" y="1974" width="88" height="88" fill="url(#pattern10_37_192)"/>
<rect x="373" y="1512" width="88" height="88" fill="url(#pattern11_37_192)"/>
<g filter="url(#filter0_d_37_192)">
<circle cx="230" cy="211" r="25" fill="#A5D6A7"/>
<circle cx="230" cy="211" r="25" stroke="black" stroke-width="2"/>
</g>
<g filter="url(#filter1_d_37_192)">
<circle cx="320" cy="284" r="25" fill="#A5D6A7"/>
<circle cx="320" cy="284" r="25" stroke="black" stroke-width="2"/>
</g>
<g filter="url(#filter2_d_37_192)">
<circle cx="264" cy="397" r="25" fill="#A5D6A7"/>
<circle cx="264" cy="397" r="25" stroke="black" stroke-width="2"/>
</g>
<g filter="url(#filter3_d_37_192)">
<circle cx="342" cy="517" r="25" fill="#A5D6A7"/>
<circle cx="342" cy="517" r="25" stroke="black" stroke-width="2"/>
</g>
<g filter="url(#filter4_d_37_192)">
<circle cx="320" cy="645" r="25" fill="#A5D6A7"/>
<circle cx="320" cy="645" r="25" stroke="black" stroke-width="2"/>
</g>
<g filter="url(#filter5_d_37_192)">
<circle cx="295" cy="773" r="25" fill="#E57373"/>
<circle cx="295" cy="773" r="25" stroke="black" stroke-width="2"/>
</g>
<g filter="url(#filter6_d_37_192)">
<circle cx="239" cy="880" r="25" fill="#38809E"/>
<circle cx="239" cy="880" r="25" stroke="black" stroke-width="2"/>
</g>
<g filter="url(#filter7_d_37_192)">
<circle cx="354" cy="959" r="25" fill="#D9D9D9"/>
<circle cx="354" cy="959" r="25" stroke="black" stroke-width="2"/>
</g>
<g filter="url(#filter8_d_37_192)">
<circle cx="270" cy="1036" r="25" fill="#D9D9D9"/>
<circle cx="270" cy="1036" r="25" stroke="black" stroke-width="2"/>
</g>
<g filter="url(#filter9_d_37_192)">
<circle cx="279" cy="1174" r="25" fill="#D9D9D9"/>
<circle cx="279" cy="1174" r="25" stroke="black" stroke-width="2"/>
</g>
<g filter="url(#filter10_d_37_192)">
<circle cx="337" cy="1302" r="25" fill="#D9D9D9"/>
<circle cx="337" cy="1302" r="25" stroke="black" stroke-width="2"/>
</g>
<g filter="url(#filter11_d_37_192)">
<circle cx="250" cy="1388" r="25" fill="#D9D9D9"/>
<circle cx="250" cy="1388" r="25" stroke="black" stroke-width="2"/>
</g>
<g filter="url(#filter12_d_37_192)">
<circle cx="162" cy="1487" r="25" fill="#D9D9D9"/>
<circle cx="162" cy="1487" r="25" stroke="black" stroke-width="2"/>
</g>
<g filter="url(#filter13_d_37_192)">
<circle cx="306" cy="1531" r="25" fill="#D9D9D9"/>
<circle cx="306" cy="1531" r="25" stroke="black" stroke-width="2"/>
</g>
<g filter="url(#filter14_d_37_192)">
<circle cx="342" cy="1649" r="25" fill="#D9D9D9"/>
<circle cx="342" cy="1649" r="25" stroke="black" stroke-width="2"/>
</g>
<g filter="url(#filter15_d_37_192)">
<circle cx="225" cy="1724" r="25" fill="#D9D9D9"/>
<circle cx="225" cy="1724" r="25" stroke="black" stroke-width="2"/>
</g>
<g filter="url(#filter16_d_37_192)">
<circle cx="216" cy="1822" r="25" fill="#D9D9D9"/>
<circle cx="216" cy="1822" r="25" stroke="black" stroke-width="2"/>
</g>
<g filter="url(#filter17_d_37_192)">
<circle cx="275" cy="1883" r="25" fill="#D9D9D9"/>
<circle cx="275" cy="1883" r="25" stroke="black" stroke-width="2"/>
</g>
<g filter="url(#filter18_d_37_192)">
<circle cx="362" cy="1917" r="25" fill="#D9D9D9"/>
<circle cx="362" cy="1917" r="25" stroke="black" stroke-width="2"/>
</g>
<g filter="url(#filter19_d_37_192)">
<circle cx="300" cy="2037" r="25" fill="#D9D9D9"/>
<circle cx="300" cy="2037" r="25" stroke="black" stroke-width="2"/>
</g>
</g>
<defs>
<pattern id="pattern0_37_192" patternContentUnits="objectBoundingBox" width="1" height="1">
<use xlink:href="#image0_37_192" transform="scale(0.00195312)"/>
</pattern>
<pattern id="pattern1_37_192" patternContentUnits="objectBoundingBox" width="1" height="1">
<use xlink:href="#image1_37_192" transform="scale(0.00195312)"/>
</pattern>
<pattern id="pattern2_37_192" patternContentUnits="objectBoundingBox" width="1" height="1">
<use xlink:href="#image2_37_192" transform="scale(0.00195312)"/>
</pattern>
<pattern id="pattern3_37_192" patternContentUnits="objectBoundingBox" width="1" height="1">
<use xlink:href="#image3_37_192" transform="scale(0.00195312)"/>
</pattern>
<pattern id="pattern4_37_192" patternContentUnits="objectBoundingBox" width="1" height="1">
<use xlink:href="#image4_37_192" transform="scale(0.00177557 0.00173062)"/>
</pattern>
<pattern id="pattern5_37_192" patternContentUnits="objectBoundingBox" width="1" height="1">
<use xlink:href="#image5_37_192" transform="scale(0.00195312)"/>
</pattern>
<pattern id="pattern6_37_192" patternContentUnits="objectBoundingBox" width="1" height="1">
<use xlink:href="#image6_37_192" transform="scale(0.00195312)"/>
</pattern>
<pattern id="pattern7_37_192" patternContentUnits="objectBoundingBox" width="1" height="1">
<use xlink:href="#image7_37_192" transform="scale(0.00195312)"/>
</pattern>
<pattern id="pattern8_37_192" patternContentUnits="objectBoundingBox" width="1" height="1">
<use xlink:href="#image8_37_192" transform="scale(0.00195312)"/>
</pattern>
<pattern id="pattern9_37_192" patternContentUnits="objectBoundingBox" width="1" height="1">
<use xlink:href="#image9_37_192" transform="scale(0.00195312)"/>
</pattern>
<pattern id="pattern10_37_192" patternContentUnits="objectBoundingBox" width="1" height="1">
<use xlink:href="#image10_37_192" transform="scale(0.00195312)"/>
</pattern>
<pattern id="pattern11_37_192" patternContentUnits="objectBoundingBox" width="1" height="1">
<use xlink:href="#image11_37_192" transform="scale(0.00195312)"/>
</pattern>
<filter id="filter0_d_37_192" x="200" y="185" width="60" height="60" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_37_192"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_37_192" result="shape"/>
</filter>
<filter id="filter1_d_37_192" x="290" y="258" width="60" height="60" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_37_192"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_37_192" result="shape"/>
</filter>
<filter id="filter2_d_37_192" x="234" y="371" width="60" height="60" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_37_192"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_37_192" result="shape"/>
</filter>
<filter id="filter3_d_37_192" x="312" y="491" width="60" height="60" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_37_192"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_37_192" result="shape"/>
</filter>
<filter id="filter4_d_37_192" x="290" y="619" width="60" height="60" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_37_192"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_37_192" result="shape"/>
</filter>
<filter id="filter5_d_37_192" x="265" y="747" width="60" height="60" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_37_192"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_37_192" result="shape"/>
</filter>
<filter id="filter6_d_37_192" x="209" y="854" width="60" height="60" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_37_192"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_37_192" result="shape"/>
</filter>
<filter id="filter7_d_37_192" x="324" y="933" width="60" height="60" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_37_192"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_37_192" result="shape"/>
</filter>
<filter id="filter8_d_37_192" x="240" y="1010" width="60" height="60" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_37_192"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_37_192" result="shape"/>
</filter>
<filter id="filter9_d_37_192" x="249" y="1148" width="60" height="60" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_37_192"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_37_192" result="shape"/>
</filter>
<filter id="filter10_d_37_192" x="307" y="1276" width="60" height="60" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_37_192"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_37_192" result="shape"/>
</filter>
<filter id="filter11_d_37_192" x="220" y="1362" width="60" height="60" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_37_192"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_37_192" result="shape"/>
</filter>
<filter id="filter12_d_37_192" x="132" y="1461" width="60" height="60" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_37_192"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_37_192" result="shape"/>
</filter>
<filter id="filter13_d_37_192" x="276" y="1505" width="60" height="60" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_37_192"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_37_192" result="shape"/>
</filter>
<filter id="filter14_d_37_192" x="312" y="1623" width="60" height="60" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_37_192"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_37_192" result="shape"/>
</filter>
<filter id="filter15_d_37_192" x="195" y="1698" width="60" height="60" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_37_192"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_37_192" result="shape"/>
</filter>
<filter id="filter16_d_37_192" x="186" y="1796" width="60" height="60" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_37_192"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_37_192" result="shape"/>
</filter>
<filter id="filter17_d_37_192" x="245" y="1857" width="60" height="60" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_37_192"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_37_192" result="shape"/>
</filter>
<filter id="filter18_d_37_192" x="332" y="1891" width="60" height="60" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_37_192"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_37_192" result="shape"/>
</filter>
<filter id="filter19_d_37_192" x="270" y="2011" width="60" height="60" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_37_192"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_37_192" result="shape"/>
</filter>
<image id="image0_37_192" width="512" height="512" preserveAspectRatio="none" xlink:href="data:image/png;base64,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 truncated
<image id="image1_37_192" width="512" height="512" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAIABJREFUeJzs3Xd4VFX+P/D3nZbeQ0ISEkLovUnvgrpgw766FrCX1dXdVVd3XeuuFRsqKqBiRbEAdmog1NBrQggQAiGF9J4p9/7+GPmuP0RybjJ37szc9+t55tln5Zx7PklmzvnMvacARERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERGpNA7ACQO0vrxUApuoaEREREWnqCQDK77we1y8sIiIi0sot+P3B/9Trbt2iIyIiIo87H4ADrScATgAX6RQjEREReVBvAFVoffA/9aoF0F+XSImIiMgj4gHkQ3zwP/U6AiBRh3iJiIionYIBbID6wf/UawuAUK9HTURERG0mAfgEbR/8T70WATB5OXYiIiJqo/+g/YP/qdczXo6diIiI2uAmeG7wP/W63as/AREREakyDkAzPJ8A2AGc68Wfg4iIiAR1BVAGzw/+p14VAHp67achIiKiVsUByIOKAT0xLqwsMS5MbcKQ90tbREREpDMrgFVQMZAH2SxNuV/9eU/e1/ftDwmyNqipCyALQJDXfjoi0gSX9xD5NwnAPACThCtIUJa9cf32yLCgfuGh1t4r5ty42yRJsoo2xwL44Je2ichPmfUOgIja5TEA96up8OFT09cM65My7tT/j4kI7tSvW8KaxZm56Sou0w/ucwPWqmmbiHwHEwAi/3UVgDeh4pv4X68bue76aQPHn/7fu3aKTbdZzVnrdhZ2VtH+JLi3Gd6jog4R+QgmAET+aRiAxQBsohUmD8/Y/dL95w8AYDnTv4/o1yk550j57oPHKpMELykBmAZgNYBjonEQkW/gMzwi/5MOYBNUHNbTrVNsYebcGeEmSYo9WzlFQdXkuz6szi042UVFPOUARsF9N4CI/AQnARL5l0gAS6Fi8I+NCq1c8faNcmuDPwBIEmJ+nn29pUN0aIWKmOJ/iSlGRR0i0hkTACL/YQHw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 truncated
<image id="image2_37_192" width="512" height="512" preserveAspectRatio="none" xlink:href="data:image/png;base64,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 truncated
<image id="image3_37_192" width="512" height="512" preserveAspectRatio="none" xlink:href="data:image/png;base64,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 truncated
<image id="image4_37_192" width="512" height="512" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAIABJREFUeJzs3Xd4VNX2N/DvmUmZ9IQkhBRSSQIEAoReEwQEBAVEsQBSrNgQFBFRVMSLiigoIB0RFAURBVHAQicQWoDQS0InlPSezJz3j9Hf6/Ui2TOZM5k58/08T557H13nZBnC7HX22XttgIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiCxAqu0EiIioVmgBBAMIAuANwAmA75//WwWgGEApgAIAeQAuAKislUxJESwAiIjUzRlAYwBJf34lAogEEALjYC9KD+AygCwAZwGkA0j783/LLJYtERERmS0OwAsA1sP4JC8r+FUBYB+AaQBSYFpRQURERDUUAeBNACeh7IBf3VcugG8APADAVdH/YiIiIgflBOBhAJthnKKvzYH/dl83AMyA8bUDERER1ZA7gOcAnEPtD/KiXzsA3AOuPSMiIjKZM4AXAVxH7Q/o5n4dgPH1gMbCPxsiIiJV6gbgCGp/ALfU134AnSz6EyIiIlKREABrUfsDthJfBgDLAYRa7KdFRESkAgMB3ETtD9RKfxUAeNJCPzMSxMUYRES2xxvApwCGKfUNPD09i8IjIq81iIvPDQ4JLXd1dZX9AwIMWietrK/SS4WF+SgpLdVkX73qnHnunHdW5rm6OTdvBiiVz5/WAXgCxjUOpDAWAEREtiUSwE8AEix1w6B69bKTU7plJnfrVp7QtJmvt693hATJ14xblRQXFWWeOXXqVuqO7dLmzb+FnDp+PMZSef7pOoDHAGy08H3pH1gAEBHZjvYAfgBQt6Y3SmiSeHrIyJGXu6TcVc/d3b1hzVO7Pb2+6vLxjIyzq7/9RvfzT2ubVVRUWKL5jx7AOACfWOBe9C9YABAR2YaHASwBoDP3Bm5ubsVPjnr+wCOPDQvW6XQNLJeaGFmWc9MPHjg8+5PpAfv3plliBmMRgGdhbDdMFsYCgIio9g0F8AXM3Bvv6+d3670Pp2e079S5uSRJPhbNzEzFRUVHP/1oWuF3K1e0MRgMNdnz/zuAfjCeaUAWxAKAiKh2DQawFMbjeU2i07mVTHx7clqffv2TJEnytnxqNVdRUZE5e8bHV5YtWdRBlmVzx5ytAPoCKLJgag6PBQARUe15GMZ98CYP/n37D9j79nvvh2m12mDLp2V5xUVFGWNfGIW01NQmZt7ir1bChRZMy6GxACAiqh0pADbB2N5XmKeXV+GCpcvTGzZO6KxIVsqSjx45suOZEUNbFBUVeZpx/WYAvcA1ARbBAoCIyPoiAewFYNK++sTmzU8uWv6Nh5OTU5giWVlJVZX+4isvjMrZuvmPZmZcvgTASEvn5IhMnnYiIqIa8QDwK4BoUy4a9OiQ3dM/+zxWo9Eo3YxHcRqNxqdX33vrRkZGbf3j100RMO1htAWMMwA7lMnOcXAGgIjIulYCeNCUC959f9qWvv0HJEOFn9kXL1zY/VC/Pk1LS0s9TLhMBnAvgPUKpeUQVPfLRERkwx6DccW/sPc/+XRLz973pCiTjm0oKSk50bd7St3cnJw6Jlx2HUAigGyF0lI9nsdMRGQdIQBmmHLBpHf/s1Xtgz8AuLu7N9yweXteUL16pgzmdWHsncAHWTOxACAiso6FAPxEg8eOf23bgAcHJSuYj01xcXWNXrvpj5KAwMCbJlzWC8DTSuWkdqyciIiUNwLAYtHg7r16H5g247NEAE7KpWSbSoqLj3fv1C6itLTUXfCSXACxAG4pmJYqsQAgIlKWJ4DTAOqJBEdGRZ37/udNPpIk+Sublu26du3K3j7duiYZ9HrRnWpzADynZE5qxG2ARETKmgigj0igs7Nz+c+/b8lxcnaur3BONs3T0ys0PDxi2++/bowUvCQJxlMUuSDQBFwDQESknHoAxooGf/zZnFRXnVu8gvnYjd733tepbYeORwXDtQCmKJmPGrEAICJSziQYXwFUq32nzkc6pXS1x/a+SnH6bN4ib3d3d9FTAPsAaKhkQmrDVwBERMoIh3GbWrWfs1qttmrV2vUlWicnh33vfztarcYnLr7hrl9+WhcpEC4BcAWwTtms1IMzAEREyngOggf9jBk/YZeLq2uMwvnYpc4pXTtExzS4IBg+FECQkvmoCQsAIiLLcwfwhEigj49v3uChw8w9ItcRuMycO/+KYKwOwGAlk1ETFgBERJY3BIBQW9v3P5mRDkkypQWuwwmrH94mNi4+UzB8kKLJqAgLACIiy3teJMjX1y+3bfuOrZVORgU0k96bekkwti0Avk4RwAKAiMiyOgJoKhI4/o1JhyRJMuUUPIfVtGlia19fv1zB8IGKJqMSLACIiCxLaAraxdW1pGefPo2VTkYtZED36PDhGYLhvRVNRiUcrs80EZGCJAD3iwSOfPLp/ZKksdt9/7k5OelrVq0sPHn8uEfd4KCy/gMflGMaxLaFguPKwEEPuc+Z8YlIaDsAbgBKlcpFDXgWABGR5XQAsFMkcMvu/Yd8fH2aKZyPEgzz58za+fmnM/6neGnTvv3RuYuWBksajVKLGqu6tm+dn5ebK9IvoRuAPxTKQxX4CoCIyHIeEAmKjI6+4OPrk6h0Mkr4fdOGbbcb/AEgLTU14bWxY7IU/PZOPXrdc1IwtqOCeagCCwAiIssRWnz24phXzsE+Z2BL3hw/7o67FjZtWJ9UkJ9/WKkEeva+p1wwtKVSOagFCwAiIsuIgbH9b7U6JScLxdma/Ly8M6WlpdXuWti/Ny1HqRwaN00UOlYZQA8AHwIYA2NfhvYA2Gr5b7gIkIjIMoQW9EVGRV10dnGNVjoZJVRVVVWKxJWUiJ7fYzo3N7c4d3f3kpKSEvdqQt0BjLvNP78F4OSfX6f+/DoE4KxFE7UDLACIiCyji0jQgw8PPgegvsK5KMLXzy9YkiRZluU7vr5olNDERcE0tI2bJp7dt2e3UK+F2/CHcbFmh3/885sA9gLYA2AzgN0AKszO0g7wFQARkWV0Egnq0au33Tb+0Wq1IX37D9h3p5i6QfWyo2NiFd3d0Kx5CyWmGAJg7B/wNoCtAHIA/AzgBQChCny/WscCgIio5oIBxFYXpNVqKwODguy6+c9bU6bWD6sffvl2/85VpytdsWbtFUBWtMiJiY31UvL+f/KAsSD4FMAFGLd3vgRjoaAKLACIiGquvUhQYrPmZ2F8N223tFptvR83/qZ7fszY7Z5eXoV//rOqvv0H7N2SmnaxTp06LZTOITIqWqf09/gHDYyvDD4BcAnAcgiu+bBl9rgNhYjI1kwC8E51QWNfm7B16PDHk62Qj7XoDQZDnkaj8QTgaq1vmpubc+qu9m3irPX97mA3gMkAfqntRMzBGQAiopqLFwnq0KGz2hZeazUajT+sOPgDgKenl7M1v98dtINxnUAqBBeB2hIWAERENddQJKh+RESw0ok4AicnJ+/azuEf2gHYAmAJ7GiNAAsAIqKakQBUOx2t1WqrXFxd7XL7n62RJMlXkiS5tvP4BwnAcAAnINgSurapbTqKiMja6gPwrC4oIjL6EoBIxbNxDFoPT8/KosLCO74K0Lk45aya+9Dh9KNXNfsOX/U+fOJavfOX8+oZDIrWDv4AVsG4YHA8AKHmSbWBBQARUc0Ivf9PaNr0JlgAWIyT1qkSwB0LAFdXp6q+d8Wn9L3rv/6IyktLKy9kXsy9unlPluGXzaf9d6RlNcgvKnezcIpjALQG0B/G7oM2hwUAEVHNxIgENW3eTLn+uA6oSl99W2KNRrrd4kRXNzfn2MZxdWMbx9XFc0PbAIBcVFJ5Ku3gxYuLvt3v/cOvJ5qWlFZaYqthJwC/w3guwQ0L3M+iWAAQEdVMhEhQbGxDbru2IH2VXqAAEB7jJE9357i7OkbH3dUxGgDKL13NPzhn2d6iWV/ublpYVOFbg1SbAfgDQHcA2TW4j8VxESARUc1EigQFh4ZaeorZoVVWVlTbbdBJqzV31sU1LNinxX9e7d65IOMN56O/Pp96V/vo02beCwCawNgrwKZ+B1gAEBHVTKRIkG8dPz+F83Aoer2+2sHU1VVbZIFv5dE4tm7731cMj72ZPuHAoL5NDph5nxYwthW2GSwAiIhqJlIkyMXZhT0ALMQgG/JlufqV/EEBniWW/L7+vm5J384alHR177jDjRoEXDDjFk/8+WUTWAAQEZnPDUBQdUEBgYE3JUmy21MAbY2+slJoVX1IXa9yJb5/vUCvxGO/vRj45ccDN2u1GlP3FE6HwO+MNbAAICIyXwQEzlSJim5gU4u/7F1pWVmeSFxoPe8qBdNwG3p/s64XUsem+3rrCky4zhvA+0olZQoWAERE5hPaARDXsKEpAwRVIy83r1QkLiTIS/EmPCF1vVtcSXv1WmSY3xUTLhsGY/vgWsVtgERE5osSCYqNj1dkKtpRZV+7IjTt/u1PGXWOn7mx/0ZOiV9+QZlrbkGpISevzMtgkOHp4SzpXJ0KvT1codM5F/n56GRfL11h/VCfyohQX314iK82pK6XJsDfTefn7e6hc3XykSQEAND+8/u46ZziTvzx4pmQ1h9ez8kvrSuQmgRgAoB+pv2XWxYLACIi8wnNAMTLine truncated
<image id="image5_37_192" width="512" height="512" preserveAspectRatio="none" xlink:href="data:image/png;base64,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 truncated
<image id="image6_37_192" width="512" height="512" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAIABJREFUeJzs3Xd4VNW6BvB3TzLpvZIESAghEELvHVQQFRQ5iHpU5ACCKKIoCiIdBWygYkFBARF7FxQQ6V2Q3jvSCUlII2WSmfvHgnuQA8zaM7Nn9k7e3/Pkuffo2rNXxsysb6/yfQAREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREZUPtwJYAODs5Z8FAG7xaI+IiIhIU8MAWAHYrvmxXv53REREVM7cj+sP/lcHAb081jsiIiJyuVYAinDjwf/KTzGA9h7qIxEREblQAoBzsD/4X/k5CyDeIz0lIiIilzAB+APyg/+VnxUAvNzfXSIiInKF8VA/+F/5GeuB/hIREZGTWgMog+MBQCmAlm7vNRERETnMF8AeOD74X/nZB8DfzX0nIiIiB70J5wf/Kz+T3dx3IiIickBjiOl7VwUAFgAN3PobEBERkSoKgFVw3eB/5WfN5dcmIiIiHeoNyUFdURSroig3ywx47c8jbv1NiIiISEoIgDOQHNCfePHBVQOHPaBmtuA0gGA3/j5EREQkYQIkB/OEqjEn1xz/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 truncated
<image id="image7_37_192" width="512" height="512" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAIABJREFUeJzs3Wd4HOW5N/D/7Kr3Xm1JVi+2mi13y3LFdEINBAghtCTUQCBvzkmi5Jzk5ByKaaGkQCABUgihG7DBvduSLNmyrG7L6r233Z33w9AD2meknd3Z1f93Xfsh5N57bsmS5t55GkBERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERENFOSowsgsjE/AKsBFAFYBCAFQBQAI4BeAE0AKgDsAPA2gDZHFElEREQz4wZgGYCfAtgJYAKALPiaBPAalEaBiIiIdC4VwA8A/AtAH8Rv+F/3sgB4CUC4Pb8IIiIimloYgCsAPAugATO/4X/dqwPAWjt9TURERPQl3gDWA/gNgCMAzNDupv/l1ziAS7X/EomIiMgAZRz+xwC2ARiF/W74X/WagNKAEBERkY3NA3ALgL8D6IJjb/hf9eoFEKfZV09ERDRLhAC4DMAzAGrh+Bu8yGubJt8JIiIiF+YJYA2AXwE4BMAEx9/Qp/O6xNbfGCIiIlciAcgGcC+ALQCG4fibtwxA9vJwG40K8+uc5vsP2/bbRESkD9wJkGZiDpTJchsArAMQ6dhyFBHBvj3XnJt96tpzs00LUiISPNyMcwFAhjx07FRb2beLX48pr2lPVJGyAMpqBCIil8EGgNQIgLLF7ic3/XSHVvMxb0/30QtWppz8zsX5g6vy4iL9vD1Soaws+Dqjdz+8peyxVw4uE7zEbwD8v5lXSkSkH2wAaCpuAJZCueGvB7Dk4//mUAaDZFm2YG71dy/Obz9/VYp/RLBvJgAvlWkm133vxeqPDtdnCcQeA5CrvlIiIv1iA0BflgHl0/16KJ/2/R1azceS54ac/fYFuQ1XbchyS5oTkmYwSCEzzdk7OFoRsuZ/FwiEygCiAbTP9JpERHrh8E9z5HBRUMbvP7npxzq2HEVIoE/fVRuzqq47L3tiYXpMvIe7MR7KnAObCfb3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 truncated
<image id="image8_37_192" width="512" height="512" preserveAspectRatio="none" xlink:href="data:image/png;base64,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 truncated
<image id="image9_37_192" width="512" height="512" preserveAspectRatio="none" xlink:href="data:image/png;base64,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 truncated
<image id="image10_37_192" width="512" height="512" preserveAspectRatio="none" xlink:href="data:image/png;base64,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 truncated
<image id="image11_37_192" width="512" height="512" preserveAspectRatio="none" xlink:href="data:image/png;base64,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 truncated
</defs>
</svg>

After

Width:  |  Height:  |  Size: 493 KiB