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
+1594 -978

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 */
+47 -94
View File
@@ -1,4 +1,5 @@
"use client"; "use client";
import { useState } from "react"; import { useState } from "react";
import { signIn } from "next-auth/react"; import { signIn } from "next-auth/react";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
@@ -19,84 +20,39 @@ export default function Login() {
try { try {
console.log("Attempting to sign in with:", username); console.log("Attempting to sign in with:", username);
// First try using the NextAuth signIn method
try {
const result = await signIn("credentials", { const result = await signIn("credentials", {
redirect: false, redirect: false,
username, username,
password, password,
callbackUrl: "/team-selection", callbackUrl: `${window.location.origin}/team-selection`,
}); });
console.log("Sign in result:", result);
if (result?.error) { if (result?.error) {
throw new Error(result.error); throw new Error(result.error);
} }
// If the user has a team, redirect directly to the team page if (result?.ok) {
if (result?.url) { console.log("Sign in successful, redirecting...");
// Extract the teamId from the URL or session data if available // Use router.push with { replace: true } to avoid history issues
// This part depends on how your auth system returns the result router.push("/team-selection", { replace: true });
router.push(`/${session?.user?.teamId || ""}`);
} else {
// Otherwise go to team selection
router.push("/team-selection");
}
return; 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}`
);
} }
} catch (error) {
// On successful login console.error("Login error:", error);
const userData = await loginResponse setError(error.message || "Failed to login. Please try again.");
.json() } finally {
.catch(() => ({ url: "/team-selection" }));
// Allow time for cookie to be set
setTimeout(() => {
router.push(userData.url || "/team-selection");
}, 100);
}
} catch (err) {
setError(err.message || "An unexpected error occurred");
console.error("Login error:", err);
setIsLoading(false); setIsLoading(false);
} }
}; };
return ( return (
<div className="auth-page"> <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-container">
<div className="auth-card"> <div className="auth-card">
<form onSubmit={handleLogin}> <h2>Login to Treasure Hunt</h2>
<form onSubmit={handleLogin} className="loginForm">
<div className="input-container"> <div className="input-container">
<input <input
type="text" type="text"
@@ -119,64 +75,61 @@ export default function Login() {
</div> </div>
{error && <div className="error-message">{error}</div>} {error && <div className="error-message">{error}</div>}
<button type="submit" className="auth-button" disabled={isLoading}> <button type="submit" className="auth-button" disabled={isLoading}>
{isLoading ? "Logging in..." : "Log In"} {isLoading ? "Logging in..." : "Login"}
</button> </button>
</form> </form>
{/* Add separate div for register button with margin-top */}
<div className="register-button-container">
<Link href="/register"> <Link href="/register">
<button className="auth-button">Register</button> <button className="auth-button register-button">Register</button>
</Link> </Link>
</div> </div>
</div> </div>
</div>
{/* Update styles to include spacing between buttons */}
<style jsx>{` <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 { .auth-card {
width: 100%;
padding: 20px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
border-radius: 8px;
background-color: #fff; 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 { .input-container {
margin-bottom: 10px; margin-bottom: 10px; /* Add consistent spacing between input fields */
} }
.auth-input { .register-button-container {
width: 100%; margin-top: 5px; /* Reduced margin above register button (was 10px) */
padding: 10px;
border: 1px solid #ccc;
border-radius: 4px;
} }
.auth-button { .auth-button {
width: 100%;
padding: 10px; padding: 10px;
margin-top: 10px;
background-color: #68543c; /* Updated brown color */
color: white;
border: none; border: none;
border-radius: 4px; border-radius: 4px;
background-color: #68543c; /* Dark brown */
color: white;
font-size: 16px;
cursor: pointer; 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 { .error-message {
color: red; color: #e53935;
margin-top: 10px; margin-top: 10px;
margin-bottom: 10px;
font-size: 0.875rem;
} }
`}</style> `}</style>
</div> </div>
+25 -69
View File
@@ -194,8 +194,6 @@ export default function TeamPage({ params }) {
) : ( ) : (
<div className="empty-state">No team members found</div> <div className="empty-state">No team members found</div>
)} )}
{/* Remove the add member button - it was here before */}
</div> </div>
<div className="team-actions"> <div className="team-actions">
@@ -243,61 +241,31 @@ export default function TeamPage({ params }) {
try { try {
setLoading(true); setLoading(true);
if (!huntActive) { // Use the dedicated start hunt API endpoint
// If hunt is not active, redirect to the "not started" page 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}`); router.push(`/hunt-not-started?teamId=${teamId}`);
} else { } else {
// If hunt is active, try to start the hunt // Some other error
const response = await fetch( throw new Error(data.error || "Failed to start hunt journey");
`/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) { } catch (err) {
setError(err.message); console.error("Error starting hunt:", err);
setLoading(false); setError(`Failed to start hunt: ${err.message}`);
}
}}
>
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);
setLoading(false); setLoading(false);
} }
}} }}
@@ -352,7 +320,7 @@ export default function TeamPage({ params }) {
.team-info { .team-info {
flex: 1; flex: 1;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between; /* This spreads items to opposite ends */
align-items: center; align-items: center;
} }
@@ -360,13 +328,14 @@ export default function TeamPage({ params }) {
margin: 0; margin: 0;
font-size: 24px; font-size: 24px;
font-weight: bold; font-weight: bold;
color: white; color: white; /* Explicitly setting color to white */
} }
.team-code { .team-code {
font-size: 24px; font-size: 24px;
font-weight: bold; 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 { .members-container {
@@ -411,19 +380,6 @@ export default function TeamPage({ params }) {
color: #888; 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 { .team-actions {
display: flex; display: flex;
gap: 10px; gap: 10px;
+49 -43
View File
@@ -1,68 +1,74 @@
"use client"; "use client";
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { useSession } from "next-auth/react";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { useHuntStatusCheck } from "@/hooks/useHuntStatusCheck";
import Link from "next/link"; import Link from "next/link";
import { use } from "react"; // Add this import for React.use()
export default function CluePage({ params }) { 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 [clue, setClue] = useState(null);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [error, setError] = useState(null); const [error, setError] = useState(null);
const router = useRouter(); const router = useRouter();
// Add this line to use the hunt status hook
const huntActive = useHuntStatusCheck();
useEffect(() => { 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() { async function fetchClueDetails() {
try { try {
// First verify the hunt is active // Try to check hunt status first with robust error handling
const huntIsActive = await checkHuntStatus(); try {
if (!huntIsActive) return; const statusResponse = await fetch("/api/hunt-status", {
// Fetch the specific clue from the API with improved error handling
const response = await fetch(`/api/clues/${clueId}`, {
credentials: "include", credentials: "include",
headers: { Accept: "application/json" },
}); });
// Better error handling for non-JSON responses // Read as text first
if (!response.ok) { const statusText = await statusResponse.text();
const contentType = response.headers.get("content-type");
if (contentType && contentType.includes("application/json")) { try {
const errorData = await response.json(); const statusData = JSON.parse(statusText);
throw new Error(errorData.error || "Failed to fetch clue details"); if (!statusData.active && statusData.authenticated) {
} else { router.push("/");
throw new Error( return;
`Failed to fetch clue details: ${response.status} ${response.statusText}`
);
} }
} 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) { if (data.error) {
throw new Error(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;
}
}
+174 -309
View File
@@ -1,358 +1,223 @@
"use client"; "use client";
import { useState, useEffect, useRef } from "react";
import { useState, useEffect } from "react"; import { useSession } from "next-auth/react";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import Link from "next/link"; 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() { export default function MapPage() {
const [clues, setClues] = useState([]); const { data: session, status } = useSession();
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [mapError, setMapError] = useState(false);
const [error, setError] = useState(null); 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(); const router = useRouter();
// Use the custom hook to check if hunt is still active
const huntActive = useHuntStatusCheck();
// Debug log for hunt status
useEffect(() => { useEffect(() => {
async function checkHuntStatus() { console.log("Hunt active status in map page:", huntActive);
}, [huntActive]);
useEffect(() => {
// Only redirect if explicitly not authenticated
if (status === "unauthenticated") {
router.push("/login");
return;
}
// 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;
}
// Only fetch team data if authenticated and hunt is active or status unknown
if (status === "authenticated" && huntActive !== false) {
fetchTeamData();
}
}, [status, huntActive, router]);
// Update elapsed time every second
useEffect(() => {
if (!teamData?.team) return;
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 { try {
const response = await fetch("/api/hunt-status", { 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", credentials: "include",
}); });
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;
}
}
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) { if (!response.ok) {
const contentType = response.headers.get("content-type"); // Handle specific error cases without immediate redirect
if (contentType && contentType.includes("application/json")) { const errorData = await response.json().catch(() => ({}));
// If it's JSON, parse it for the error message
const errorData = await response.json(); if (response.status === 401) {
throw new Error(errorData.error || "Failed to fetch clues"); // Set error but don't redirect immediately - let the session handling take care of it
} else { setError(
// If it's not JSON, use the status text "Authentication error: " + (errorData.error || "Not logged in")
throw new Error(
`Failed to fetch clues: ${response.status} ${response.statusText}`
); );
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");
} }
} }
// Parse the JSON response
const data = await response.json(); const data = await response.json();
setTeamData(data);
// If we got back an error field, show it as an error setLoading(false);
if (data.error) {
throw new Error(data.error);
}
setClues(data.clues || []);
} catch (err) { } catch (err) {
console.error("Error fetching clues:", err); console.error("Error fetching team data:", err);
setError(err.message); setError(err.message);
} finally {
setLoading(false); setLoading(false);
} }
}
fetchClues();
}, [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;
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)),
});
}
return positions;
}; };
const cluePositions = clues.length > 0 ? generatePositions(clues) : []; if (status === "loading" || loading) {
if (loading) {
return ( return (
<div className="map-container"> <div className={styles["loading-container"]}>
<div className="loading">Loading clues...</div> <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> </div>
); );
} }
if (error) { if (error) {
return ( return (
<div className="map-container"> <div className={styles["map-error"]}>
<div className="error">Error: {error}</div> <h2>Error</h2>
<button onClick={() => router.push("/")} className="back-button"> <p>{error}</p>
Back to Home <button onClick={fetchTeamData}>Retry</button>
</button>
</div> </div>
); );
} }
if (clues.length === 0) { if (mapError) {
return ( return (
<div className="map-container"> <div className={styles["map-error"]}>
<div className="no-clues">No clues available yet.</div> <h2>Error Loading Map</h2>
<button onClick={() => router.push("/")} className="back-button"> <p>We couldn't load the treasure map. Please try again.</p>
Back to Home <button onClick={fetchTeamData}>Retry</button>
</button>
</div> </div>
); );
} }
return ( return (
<div className="map-container"> <div className={styles["map-page"]}>
<h1>Treasure Map</h1> {/* Map Banner with team info and timer */}
<div className="map-wrapper"> <div className={styles["map-banner"]}>
<svg <div className={styles["team-name"]}>
className="map-svg" {teamData?.team?.name || "Your Team"}
viewBox="0 0 800 500" </div>
xmlns="http://www.w3.org/2000/svg" <div className={styles["elapsed-time"]}>
> <span className={styles["time-value"]}>{elapsedTime}</span>
{/* Map background with a treasure map style */} </div>
<rect width="800" height="500" fill="#f5e6ca" /> <div className={styles["team-code"]}>{teamData?.team?.code || ""}</div>
<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> </div>
{/* Clue list */} {/* Main map content area */}
<div className="clue-list"> <div className={styles["map-container"]} ref={mapContainerRef}>
<h2>Clues</h2> <div className={styles["treasure-map"]}>
<ul> {/* Use Image component with fill layout for better SVG handling */}
{cluePositions.map((clue, index) => ( <Image
<li key={`clue-list-${index}`}> src="/images/treasure-map.svg"
<Link href={`/clue/${clue.id}`}> alt="Treasure Map"
{index + 1}. {clue.title} 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"]}
>
<div className={styles["nav-icon"]}>🏠</div>
<div className={styles["nav-label"]}>Home</div>
</Link> </Link>
</li> <Link href="/leaderboard" className={styles["nav-item"]}>
))} <div className={styles["nav-icon"]}>📊</div>
</ul> <div className={styles["nav-label"]}>Stats</div>
</div> </Link>
<Link href="/team-selection" className={styles["nav-item"]}>
<button onClick={() => router.push("/")} className="back-button"> <div className={styles["nav-icon"]}>👥</div>
Back to Home <div className={styles["nav-label"]}>Team</div>
</button> </Link>
<Link
<style jsx>{` href="/map"
.map-container { className={`${styles["nav-item"]} ${styles["active"]}`}
padding: 20px; >
max-width: 1000px; <div className={styles["nav-icon"]}>🗺️</div>
margin: 0 auto; <div className={styles["nav-label"]}>Map</div>
text-align: center; </Link>
} </nav>
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> </div>
); );
} }
+23 -10
View File
@@ -234,27 +234,39 @@ export default function TeamPage({ params }) {
try { try {
setLoading(true); setLoading(true);
// Check hunt status first // Use try-catch with robust error handling
const response = await fetch("/api/hunt-status", { const response = await fetch("/api/hunt-status", {
method: "GET", method: "GET",
headers: { "Content-Type": "application/json" }, headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
credentials: "include", credentials: "include",
}); });
if (response.ok) { 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(); 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) { if (data.active) {
// If hunt is active, navigate to map page // Use window.location.href for a full page reload to avoid caching issues
router.push("/map"); window.location.href = "/map";
} else { } else {
// If hunt is not active, show not started page // If hunt is not active, show the not started page
router.push(`/hunt-not-started?teamId=${teamId}`); router.push(`/hunt-not-started?teamId=${teamId}`);
} }
} else {
throw new Error("Failed to check hunt status");
}
} catch (err) { } catch (err) {
setError(err.message); console.error("Error checking hunt status:", err);
setError(`Failed to check hunt status: ${err.message}`);
} finally {
setLoading(false); setLoading(false);
} }
}} }}
@@ -483,6 +495,7 @@ export default function TeamPage({ params }) {
.error-icon { .error-icon {
font-size: 48px; font-size: 48px;
margin-bottom: 20px; margin-bottom: 20px;
color: #d32f2f;
} }
.error-message { .error-message {
+96 -354
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 { validateCredentials } from "@/actions/auth";
import jwt from "jsonwebtoken";
import { cookies } from "next/headers"; import { cookies } from "next/headers";
import { redirect } from "next/navigation";
// Define hardcoded values for NextAuth // Use a consistent secret for JWT signing and verification
const NEXTAUTH_SECRET = "banana"; const JWT_SECRET = process.env.NEXTAUTH_SECRET || "banana";
const NEXTAUTH_URL = "http://localhost:3000"; 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 = { export const authOptions = {
providers: [ providers: [
// Correct syntax: no function call, just reference the imported object
{ {
id: "credentials", id: "credentials",
name: "Credentials", name: "Credentials",
type: "credentials", type: "credentials",
authorize: async (credentials) => { credentials: {
if (!credentials?.username || !credentials?.password) return null; username: { label: "Username", type: "text" },
return await validateCredentials( 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.username,
credentials.password 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: { callbacks: {
async jwt({ token, user }) { async jwt({ token, user }) {
if (user) { if (user) {
token.id = user.id; token.id = user.id;
token.role = user.role; token.role = user.role;
token.username = user.username; token.username = user.username;
token.teamId = user.teamId; token.teamId = user.team_id || user.teamId;
} }
return token; return token;
}, },
async session({ session, token }) { async session({ session, token }) {
if (token) { if (token) {
session.user = session.user || {}; session.user = session.user || {};
@@ -384,9 +89,46 @@ export const authOptions = {
return session; 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 // Token helpers
export { createToken, verifyToken }; 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 };
+25 -20
View File
@@ -9,14 +9,23 @@ export async function GET(request, { params }) {
const { clueId } = params; const { clueId } = params;
try { try {
// Verify the user is authenticated // 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) {
const cookieStore = await cookies(); const cookieStore = await cookies();
const sessionToken = cookieStore.get("next-auth.session-token")?.value; const sessionToken =
cookieStore.get("next-auth.session-token")?.value ||
cookieStore.get("__Secure-next-auth.session-token")?.value;
if (!sessionToken) { if (!sessionToken) {
return Response.json( return Response.json(
{ error: "Unauthorized", clue: null }, { error: "Unauthorized", clue: null },
{ status: 401 } { status: 401, headers: { "Content-Type": "application/json" } }
); );
} }
@@ -24,23 +33,17 @@ export async function GET(request, { params }) {
if (!userData) { if (!userData) {
return Response.json( return Response.json(
{ error: "Invalid session", clue: null }, { error: "Invalid session", clue: null },
{ status: 401 } { status: 401, headers: { "Content-Type": "application/json" } }
); );
} }
// Check if the hunt is active // Admin can see clues even if hunt is not active
const huntActiveSetting = await queryOne( if (userData.role !== "admin") {
"SELECT value FROM settings WHERE key = 'hunt_active'" return Response.json(
{ error: "Hunt is not active", clue: null },
{ headers: { "Content-Type": "application/json" } }
); );
}
const huntActive = huntActiveSetting && huntActiveSetting.value === "true";
if (!huntActive) {
// Return a valid JSON response with clue set to null
return Response.json({
error: "Hunt is not active",
clue: null,
});
} }
// Fetch the specific clue // Fetch the specific clue
@@ -49,17 +52,19 @@ export async function GET(request, { params }) {
if (!clue) { if (!clue) {
return Response.json( return Response.json(
{ error: "Clue not found", clue: null }, { 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) { } catch (error) {
console.error("Error fetching clue details:", error); console.error("Error fetching clue details:", error);
// Always return a valid JSON response even on error
return Response.json( return Response.json(
{ error: "Failed to fetch clue details: " + error.message, clue: null }, { error: "Failed to fetch clue details: " + error.message, clue: null },
{ status: 500 } { status: 500, headers: { "Content-Type": "application/json" } }
); );
} }
} }
+60 -37
View File
@@ -4,21 +4,18 @@ import { verifyToken } from "@/app/api/auth/[...nextauth]/route";
export const dynamic = "force-dynamic"; // Disable caching 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() { async function ensureCluesTableExists() {
try { try {
// Create the clues table if it doesn't exist
await run(` await run(`
CREATE TABLE IF NOT EXISTS clues ( CREATE TABLE IF NOT EXISTS clues (
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL, title TEXT NOT NULL,
description TEXT NOT NULL, description TEXT NOT NULL,
location TEXT, location TEXT,
order_number INTEGER,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) )
`); `);
return true; return true;
} catch (error) { } catch (error) {
console.error("Error ensuring clues table exists:", error); console.error("Error ensuring clues table exists:", error);
@@ -26,17 +23,35 @@ 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 // GET endpoint to retrieve all clues
export async function GET(request) { export async function GET(request) {
try { try {
// Verify the user is authenticated // 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 hunt is active, allow access without authentication
if (!huntActive) {
// Only verify authentication when hunt is not active
const cookieStore = await cookies(); const cookieStore = await cookies();
const sessionToken = cookieStore.get("next-auth.session-token")?.value; const sessionToken =
cookieStore.get("next-auth.session-token")?.value ||
cookieStore.get("__Secure-next-auth.session-token")?.value;
if (!sessionToken) { if (!sessionToken) {
return Response.json( return Response.json(
{ error: "Unauthorized", clues: [] }, { error: "Unauthorized", clues: [] },
{ status: 401 } { status: 401, headers: { "Content-Type": "application/json" } }
); );
} }
@@ -44,61 +59,69 @@ export async function GET(request) {
if (!userData) { if (!userData) {
return Response.json( return Response.json(
{ error: "Invalid session", clues: [] }, { error: "Invalid session", clues: [] },
{ status: 401 } { 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 // Ensure the clues table exists
await ensureCluesTableExists(); await ensureCluesTableExists();
// Check if the hunt is active // Fetch all clues without sorting in SQL
const huntActiveSetting = await queryOne( const clues = await query("SELECT * FROM clues");
"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");
// If no clues are found, insert sample clues (for testing purposes) // If no clues are found, insert sample clues (for testing purposes)
if (!clues || clues.length === 0) { if (!clues || clues.length === 0) {
// Insert sample clues // Insert sample clues
await run( await run(
"INSERT INTO clues (title, description, location, order_number) VALUES (?, ?, ?, ?)", "INSERT INTO clues (title, description, location) VALUES (?, ?, ?)",
["First Clue", "This is the first clue description", "Location 1", 1] ["Clue 1", "This is the first clue description", "Location 1"]
); );
await run( await run(
"INSERT INTO clues (title, description, location, order_number) VALUES (?, ?, ?, ?)", "INSERT INTO clues (title, description, location) VALUES (?, ?, ?)",
["Second Clue", "This is the second clue description", "Location 2", 2] ["Clue 2", "This is the second clue description", "Location 2"]
); );
await run( await run(
"INSERT INTO clues (title, description, location, order_number) VALUES (?, ?, ?, ?)", "INSERT INTO clues (title, description, location) VALUES (?, ?, ?)",
["Final Clue", "This is the final clue description", "Location 3", 3] ["Clue 3", "This is the final clue description", "Location 3"]
); );
// Fetch the inserted clues // Fetch the inserted clues
const sampleClues = await query( const sampleClues = await query("SELECT * FROM clues");
"SELECT * FROM clues ORDER BY order_number ASC"
// 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) { } catch (error) {
console.error("Error fetching clues:", error); console.error("Error fetching clues:", error);
// Always return a valid JSON response even on error
return Response.json( return Response.json(
{ error: "Failed to fetch clues: " + error.message, clues: [] }, { error: "Failed to fetch clues: " + error.message, clues: [] },
{ status: 500 } { status: 500, headers: { "Content-Type": "application/json" } }
); );
} }
} }
+80 -40
View File
@@ -4,59 +4,99 @@ import { verifyToken } from "@/app/api/auth/[...nextauth]/route";
export const dynamic = "force-dynamic"; // Disable caching export const dynamic = "force-dynamic"; // Disable caching
export async function GET(request) { // Helper function to ensure the hunt_status table exists
async function ensureHuntStatusTableExists() {
try { try {
// Verify the user is authenticated // Create hunt_status table if it doesn't exist
const cookieStore = await cookies();
const sessionToken = cookieStore.get("next-auth.session-token")?.value;
if (!sessionToken) {
return Response.json({ error: "Unauthorized" }, { status: 401 });
}
const userData = verifyToken(sessionToken);
if (!userData) {
return Response.json({ error: "Invalid session" }, { status: 401 });
}
let huntActive = false;
try {
// First try to create the settings table if it doesn't exist
await run(` await run(`
CREATE TABLE IF NOT EXISTS settings ( CREATE TABLE IF NOT EXISTS hunt_status (
key TEXT PRIMARY KEY, id INTEGER PRIMARY KEY CHECK (id = 1),
value TEXT NOT NULL is_active BOOLEAN DEFAULT 0,
start_time TEXT,
end_time TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) )
`); `);
// Check if hunt_active setting exists // Check if we need to insert the initial record
const huntSetting = await queryOne( const status = await queryOne("SELECT * FROM hunt_status LIMIT 1");
"SELECT value FROM settings WHERE key = 'hunt_active'" if (!status) {
);
// 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( await run(
"INSERT OR IGNORE INTO settings (key, value) VALUES (?, ?)", "INSERT INTO hunt_status (id, is_active, start_time) VALUES (1, 0, NULL)"
["hunt_active", "false"]
); );
console.log("Initialized hunt_status table with default record");
} }
} catch (dbError) { return true;
console.error("Database error in hunt-status:", dbError); } catch (error) {
// Continue with default value if there's a DB 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 {
// 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;
// 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;
} }
// Return the active status console.log("Hunt status check:", { isActive, startTime });
return Response.json({ return Response.json({
active: huntActive, active: isActive,
timestamp: new Date().toISOString(), startTime: startTime || null,
}); });
} catch (error) { } catch (error) {
console.error("Hunt status check error:", error); console.error("Error checking hunt status:", error);
return Response.json( return Response.json(
{ error: "Failed to check hunt status", active: false }, { error: "Failed to check hunt status", active: false },
{ status: 500 } { 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 }
);
}
}
+10 -2
View File
@@ -1,7 +1,15 @@
'use client'; "use client";
import { SessionProvider } from "next-auth/react"; import { SessionProvider } from "next-auth/react";
export function NextAuthProvider({ children }) { 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,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAIABJREFUeJzs3Xd8W9X5P/DPvdqShzzkGTtOnGk7iZ29CEkggTBS9gwFwmgLBQot/fXblpbSQTezUCgQZqAQRgKFkL0dx4kdxyvO8B7ylmRrS/f+/jimhRbiI1tX0pXP+/XSK0059+qJLd373DOeAzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzBywoU7ACbiaACkATABSABgHPozAUA8AH6ojf4c53AAsAMYAGAb+nsfgG4AnQC6hv47wzCEAUDq0CsZQCLIdyxu6KXH8N85NwABgBVA/9DLMvRnNwDzUBuGAcASgLEoCUAugIlDr1wAWQAyQG78SSGKwwGgFUADgMahVwOAUwBqAbhCFAfDhIIWwHQAUwHkDL0mDP05Due+uQdTL0gi0A6gGUD90Ovs0J+9IYqDiQAsAYhecQAKAeQDKACQB2AGQneDHw0/yMWoEkANgKMASkAuXAwT6dIBzAcwF//5/k0EoAhnUJR68J/vXRWAagAVID15TJRhCUB0UAOYA2AeyEVnHoApIN310aQJJBE4DGA3gBMgXZ4MEy48gFkAlgNYOPTKDmdAEhAA1IEk4qVDfx4D4AlnUMzosQRAnmIALAJwHoBlIE8burBGFB49IInALgDbQHoNGEZquQBWA1gJYAXk0asWbE6QZHwfgP0AisHm9cgOSwDkYyKAywFcBnLj14Q3nIhUD+ATAO8BOAhADG84TBTJB3AtyPdvTphjiUQ+kKGCTwB8DKAM7PvHMCOmA7AWwCsgY98iewX0agHwVwBFgf7gGWbIbABPgExWDffnWW6vDgAvgzy0aAP9wTPMWBQHYB2ATQAGEf4vcbS8qgD8P5DZ1gxzLlkAfgIy+S3cn9toeQ2A9MrdBCCW/lfBMNFPAeBCAK+D3fSlfvkBbAd5KmHDX8yXLQXwLgAvwv85jeaXE2SI4FqQycsMMyYVAngWZCJbuL+UY/FVA+AekAmVzNgUA+BekLoT4f48jsVXD8g1sHC4XxQjDfYUFFqxAG4EcBfIcr2IpOA4v8lg6BkXF9c/ISFhIEGn8yZptX4ASNbrBY7nYdRoRCXPcwaVChqVind4PILL54PN4xE9fj/X53BwfkHguhwOpd/v55ptNn2jxZLQarOlePz+SJrA2AvgSZALkSXMsTChYQRwH4AHEFkz+N0qnu8yqFT9Rr3ewQGiUaPxKThOjNNqRbVCIcZptZxeqUSMWs07vF5h0OuF1+cTrW43JwKwOJ08ANg8HoXd61VZXa44t89nFEQxGZFdh6AUwD8AvAMyZMCEAEsAQmMyyMXmVkTAE6dBpbIXpKQ0z83I6JuTkeHNio9XJup02niNJk6jVBp5jkuGhDUEBFHsdvl8vRaXa6BzcNDZbLUK1V1dqqPt7YmVXV3ZDq/XINV7n4MVJAl4EuTJhIk+JgA/APB9kPk2IcUBdoNa3ZwRF9eXazR6JyYk8JOSknS5CQlx44zGxFS93iTVewuiKHTb7T3tAwOW+v5+a7PN5j7T2+ur6elRtdlsiQ6PJ1sk5YjDbQDAawCeAnAmzLFEPZYASOsCkAvOJQhDUZ5YtXpwcXb2mXkZGbai9HTkJiTEJGi1aUqFIiPUsQRA9AlCW4/d3lHW0WHf2dCg39PYON48OJgaovcfAPAHkNnfjhC9JyMtPYCHQCaChiQB5zmuMz02tmluerrjgokTDXMzMzOy4+MzuAi+5jZZLO0nOjvNR9raBk6YzdxZiyXO4nROEsPz0CKALCl8CqTOByOBiP0wyhgP4FsAfg6yjCgkOECcbjI1rM7Nbb8gN1fMS05O0yqVcik/Oiy/IHSc7e+v33bmjLC5ri6zprt7osRv2QrgEZDJmazaoDzxIL1uvwaQKeUbaRSK+ryUlLZLJ09WrJ06dUJmXFy6lO8XKn5R9FeazWf/deZM556GBu5MX1+mx++fEOIwjgL4LYDNIHMHmCBhCUDwKABcD+CnIEVDJMVznLAoK6v2xhkzuhdlZhpSY2MncWTHvjFBFMXOqq6uU+9UVqo+qK3Nt3k8Ui0vOg7geyDlhxn5WATgeZAyvUHHAbbxCQk1V02f7ls3Y8aU1JiYFCneJxL1ORx9Oxsazn525oz9YHOzadDjmY7Q9HBWAvgdyJJCfwjeL+qxBGD0OABXgmSo06R8o0S9vu/6/PyT1+Xni5MSE6fzHJco5fvJBQd4u+32yrerquz/KCvL73U4gv1zEQD8HSS5swb53ExwGUFuEt9BkG9KHMf1FaalVd8zb17M6tzcAiXPq4J5frnqcTh636mqOvledTV3tr9/miiKUl+XagH8DMBHYD0Co8ISgNFZDuD3ABZI9QYLMjNrbyks7Lxw4sTkWLV6OqKkS19Cvm67veLl8nLXS2VlRU6vN5jbrLaDTObcFMRzMsFzLciYcTC73x15JlPZ/QsW6NdMnjxTyfPKIJ476vhF0X+gubnmtePHew80N6fZPR4pH4oOgxRt2ivhe0Q1lgCMzBSQMrOXSnHySYmJTT9avLjh4kmTclQKRY4U7zEmiKLtmNl8/Ld795pK2tqmB/HM74AMC7Blg5HBCNLdf0OwThijVtd+u7Cw574FCwrj1GpWvW6E6np6Gv9y6FDjtrNnJ3oFQapdEj8BmeR5WqLzRy2WAATGAOBhkKwzqGvZjTqd5ZaZM6vvLCrSJRsMRWC/m6Cye721z5SU9D1fWrrAJwjBeIprBvBtsKePcFsI4C2QzbJGS8iMjT32h9WrtStycmYE4XzMl5S0tdX+6eDB7pLW1ryhugTB5AVJAh8BYAvyuaMWu8nQuwnAnxHE7kUlz/vWzZhx9N4FCxSZsbGFIsDGFCXmE4TWtyorz/567955QRge8IMMAf0CbKVAqPEAHgNJxkc7LOZYOn586R9XrZo0Pj5e0tUCDOATBO/7NTXlTx0+LDRZrfMQ3GHNdgA/BOmlY4bBEoDhZYFklkHr7o9Tqy3/d955ZTfNnDlFyfNsg5owEIDef1ZV1T6ya9ccp9erG+XpXgKp7siEzksA7hjlOZwLMzMPPnf55QWpBkNaMIJiAtNksXQ+snv32V319fkiEB/EU38CMkzXGsRzRh2WAHwzDuQD9HsEaQerPJOp/verVrXOSU+fg8ioujWW+Qfd7pMbKyt7H9u79zxx9N+FiwBsC0ZgzLAuBvDZKM8hzsvI2P/wkiVJC7Oypik4jk2uDaNBr9f+10OHjm0oL88KYp0BG0gP0d/BVgt8LZYAfL1MAK+C7NI3at+aNu3YL5cvF1MNhjlgP/Ow8fh8DRVdXS2bqqs1H9fVTbO63cF84ngbZJiIkd7bCOKEPw6wjouPP7lm8mT3dXl5WdNNplAXumGGiID4QU3N0cf27lX0OBzBKqS2HcBtIMMDzJewm9H/ugrAiwjCJiGrJk6seGrNGj5eq2UTisLD1W6znXinutrzblXVxBabTcoSyMcQwRs8RZkyAEVSnVzBce35JtPZ22fP1l4xbdpMtUIRSZtXjRk76utPPPDpp7C43TODcLoeAHcD+DAI54oaLAH4Dy2ApxGEsdzCtLTqFy6/vG9cXNx5ow+LCZCz1WareaOiwvv68eMFNo8nVHXMdyJIPUbMsHaA7LMRCgM5RmP5bUVFuKmgYLZBrQ77Zl5jzUe1teU/3rFDF6SaAi+C1PJwBeFcsscSAGI8gPcBzBnNSQpSUs6+sHZtd058/AKwn20ouU739pa9VFam2FRTM9Pl8412Ut9IPASygRAjvYcA/CUM7+vMio8/cXthof+2wsLZGqVSG4YYxiQREDeUlx/+zd69qW6/f7RLPo8BuBpAUxBCkzV2kwJWA9iIUXT5pxoM3W9cdVVdfkrKIrBKfSHj9HpPvVlZaX7y8OGZFqfTGMZQToN0/7P1x6ERB7JBzORwBcBxnGV+ZuaJXyxbllaYnj4lXHGMNX5R9D9RXHzoqcOHp4+ylkAvgJsBfB6k0GRprCcA94NU9BvRTVvJ875fLV9+8LbCwiJwXMj3Fx+LRFEcrOnpqfprcXHC1tOnp4Y7HgAVICVoWRWy0JoM4F0AheEOJEatrl5fVNR7z7x5s2M1GjZEEAI2l8u6fvPmiuLW1sUARlrYyw/Sm/R08CKTl7GaAPAgXYg/GOkJFmdlVb9x1VVqrVIZtqeQsUQQxe53q6pqHt2zZ85A6Mb1v44HZFeyYwD+BWDr0P/HhJ4KwBoAl4Hsx5GHkd8MRo0DBlZMmFD2l4suyk8xGIJd6Y75GuUdHadu2LTJP7Qj4Ug9AeBHGIPFvMZiAqADKR165UgO1iiVzpfXrj28YsKEZWDd/ZLzi2LPP6uqTv1i9+6iIBTsCZQP5Am/BGTmeRmAKpCyo0zkUQGYCWApyHyeOQCmI/TXOXdRWtqR5y+7LDcrPl7KlScMAJ8g+H65Z8+hV8vLR1Nf5SOQIQFH8CKLfGMtAUgA8ClI/fCALc7Kqt549dUGtkGP9Hx+f/vfSkvPPnH48AKv368Line 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