-
{{ exercise.question }}
-
-
-
+
+
Exercise {{ forloop.counter }}
+
{{ exercise.question }}
+
+
+
+
+
{% endfor %}
+{% endblock %}
{% block extra_js %}
{% endblock %}
-
-{% endblock %}
diff --git a/core/templates/core/index.html b/core/templates/core/index.html
index 7a5d234..464e0ab 100644
--- a/core/templates/core/index.html
+++ b/core/templates/core/index.html
@@ -13,7 +13,7 @@
Welcome to CodeCraft
The ultimate platform for coding challenges and assignments. Sharpen your skills, compete with peers, and get feedback from instructors.
diff --git a/core/templates/core/login.html b/core/templates/core/login.html
new file mode 100644
index 0000000..15a0c35
--- /dev/null
+++ b/core/templates/core/login.html
@@ -0,0 +1,93 @@
+{% extends "base.html" %}
+{% load static %}
+
+{% block content %}
+
+
+
+{% endblock %}
diff --git a/core/templates/core/student_dashboard.html b/core/templates/core/student_dashboard.html
index dc1d234..b41021b 100644
--- a/core/templates/core/student_dashboard.html
+++ b/core/templates/core/student_dashboard.html
@@ -1,17 +1,104 @@
-{% extends 'base.html' %}
+{% extends "base.html" %}
+{% load static %}
{% block content %}
-
-
Student Dashboard
-
+
+
+
+
+
diff --git a/core/urls.py b/core/urls.py
index ee00cbc..95f9a1b 100644
--- a/core/urls.py
+++ b/core/urls.py
@@ -1,11 +1,21 @@
from django.urls import path
-from .views import home, student_dashboard, assignment_detail, get_hint, call_teacher
+from .views import (
+ home,
+ student_dashboard,
+ assignment_detail,
+ get_hint,
+ call_teacher,
+ login_view,
+ logout_view,
+)
app_name = "core"
urlpatterns = [
path("", home, name="home"),
+ path("login/", login_view, name="login"),
+ path("logout/", logout_view, name="logout"),
path("dashboard/", student_dashboard, name="student_dashboard"),
path("assignment/
/", assignment_detail, name="assignment_detail"),
path("hint//", get_hint, name="get_hint"),
diff --git a/core/views.py b/core/views.py
index 9a8f107..37783e1 100644
--- a/core/views.py
+++ b/core/views.py
@@ -3,14 +3,18 @@ import platform
import random
from django import get_version as django_version
+from django.contrib.auth import authenticate, login, logout
+from django.contrib.auth.decorators import login_required
+from django.contrib.auth.forms import AuthenticationForm
from django.http import JsonResponse
-from django.shortcuts import render, get_object_or_404
+from django.shortcuts import render, get_object_or_404, redirect
from django.utils import timezone
from .models import Assignment, Exercise, Hint, Submission
+
def home(request):
- """Render the landing screen with loader and environment details."""
+ """Render the landing screen with loader and environment details."""
host_name = request.get_host().lower()
agent_brand = "AppWizzy" if host_name == "appwizzy.com" else "Flatlogic"
now = timezone.now()
@@ -27,10 +31,34 @@ def home(request):
}
return render(request, "core/index.html", context)
+
+def login_view(request):
+ if request.method == 'POST':
+ form = AuthenticationForm(request, data=request.POST)
+ if form.is_valid():
+ username = form.cleaned_data.get('username')
+ password = form.cleaned_data.get('password')
+ user = authenticate(username=username, password=password)
+ if user is not None:
+ login(request, user)
+ return redirect('core:student_dashboard')
+ else:
+ form = AuthenticationForm()
+ return render(request, 'core/login.html', {'form': form})
+
+
+def logout_view(request):
+ logout(request)
+ return redirect('core:login')
+
+
+@login_required
def student_dashboard(request):
assignments = Assignment.objects.all()
return render(request, "core/student_dashboard.html", {"assignments": assignments})
+
+@login_required
def assignment_detail(request, assignment_id):
assignment = get_object_or_404(Assignment, pk=assignment_id)
if request.method == 'POST':
@@ -56,6 +84,8 @@ def assignment_detail(request, assignment_id):
return render(request, "core/assignment_detail.html", {"assignment": assignment})
+
+@login_required
def get_hint(request, exercise_id):
exercise = get_object_or_404(Exercise, pk=exercise_id)
hints = exercise.hints.all()
@@ -64,6 +94,9 @@ def get_hint(request, exercise_id):
return JsonResponse({'hint': hint.hint_text})
return JsonResponse({'hint': 'No hints available for this exercise.'})
+
+@login_required
def call_teacher(request):
# In a real application, this would trigger a notification to the teacher
return JsonResponse({'message': 'A teacher has been called to help you.'})
+
diff --git a/create_dummy_data.py b/create_dummy_data.py
new file mode 100644
index 0000000..bd61aa0
--- /dev/null
+++ b/create_dummy_data.py
@@ -0,0 +1,62 @@
+from django.contrib.auth.models import User
+from core.models import Assignment, Exercise, Hint
+from datetime import datetime, timedelta
+
+# Create a student user
+student, created = User.objects.get_or_create(username='student', defaults={'first_name': 'John', 'last_name': 'Doe'})
+if created:
+ student.set_password('password')
+ student.save()
+ print("Student user created.")
+else:
+ print("Student user already exists.")
+
+# Create an assignment
+assignment, created = Assignment.objects.get_or_create(
+ title='Math Homework 1',
+ defaults={
+ 'description': 'Complete the following exercises.',
+ 'due_date': datetime.now() + timedelta(days=7)
+ }
+)
+if created:
+ print("Assignment created.")
+else:
+ print("Assignment already exists.")
+
+
+# Create exercises
+exercise1, created = Exercise.objects.get_or_create(
+ assignment=assignment,
+ question='What is 2 + 2?',
+ defaults={'answer': '4'}
+)
+if created:
+ print("Exercise 1 created.")
+else:
+ print("Exercise 1 already exists.")
+
+
+exercise2, created = Exercise.objects.get_or_create(
+ assignment=assignment,
+ question='What is 5 * 5?',
+ defaults={'answer': '25'}
+)
+if created:
+ print("Exercise 2 created.")
+else:
+ print("Exercise 2 already exists.")
+
+
+# Create a hint
+hint, created = Hint.objects.get_or_create(
+ exercise=exercise1,
+ defaults={'hint_text': 'The answer is a single digit number.'}
+)
+
+if created:
+ print("Hint created.")
+else:
+ print("Hint already exists.")
+
+print("Dummy data creation complete.")
diff --git a/static/css/custom.css b/static/css/custom.css
index 14aa7b7..aec0ec4 100644
--- a/static/css/custom.css
+++ b/static/css/custom.css
@@ -3,6 +3,7 @@
--primary-color: #4285F4;
--secondary-color: #FBBC05;
--accent-color: #34A853;
+ --tertiary-color: #EA4335;
--neutral-light-gray: #F8F9FA;
--neutral-dark-text: #202124;
--font-headings: 'Poppins', sans-serif;
@@ -12,7 +13,7 @@
body {
font-family: var(--font-body);
color: var(--neutral-dark-text);
- background-color: #fff;
+ background-color: var(--neutral-light-gray);
line-height: 1.6;
}
@@ -53,47 +54,347 @@ h1, h2, h3, h4, h5, h6 {
border-color: #F9A825;
}
-.hero {
- padding: 100px 0;
- background: linear-gradient(135deg, #E3F2FD, #FFFFFF);
- text-align: center;
- position: relative;
- overflow: hidden;
+.btn-tertiary {
+ background-color: var(--tertiary-color);
+ border-color: var(--tertiary-color);
+ color: #fff;
}
-.hero h1 {
- font-size: 3.5rem;
+.btn-tertiary:hover {
+ background-color: #D93025;
+ border-color: #D93025;
+}
+
+.login-container {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ min-height: 100vh;
+ width: 100%;
+}
+
+.login-branding {
+ background: linear-gradient(135deg, var(--primary-color), var(--accent-color));
+ color: #fff;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 40px;
+ text-align: center;
+}
+
+.login-branding-content h1 {
+ font-size: 2.8rem;
font-weight: 700;
margin-bottom: 20px;
+}
+
+.login-branding-content p {
+ font-size: 1.1rem;
+ max-width: 400px;
+ margin: 0 auto;
+}
+
+.login-form-wrapper {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 40px;
+ background-color: #fff;
+}
+
+.login-form-container {
+ max-width: 400px;
+ width: 100%;
+}
+
+.login-form-container h2 {
+ font-size: 2rem;
+ font-weight: 700;
+ margin-bottom: 10px;
color: var(--neutral-dark-text);
}
-.hero .lead {
- font-size: 1.25rem;
- margin-bottom: 40px;
- color: #5f6368;
+.login-form {
+ margin-top: 30px;
}
-.features-section {
- padding: 80px 0;
+.form-group {
+ margin-bottom: 20px;
}
-.feature-card {
- background-color: var(--neutral-light-gray);
- border: none;
- border-radius: 12px;
- padding: 30px;
+.form-group label {
+ display: block;
+ font-weight: 600;
+ margin-bottom: 8px;
+ color: var(--neutral-dark-text);
+}
+
+.form-group input, .form-group textarea {
+ width: 100%;
+ padding: 12px 15px;
+ border: 1px solid #ccc;
+ border-radius: 8px;
+ font-size: 1rem;
+ transition: border-color 0.3s ease;
+}
+
+.form-group input:focus, .form-group textarea:focus {
+ outline: none;
+ border-color: var(--primary-color);
+ box-shadow: 0 0 0 3px rgba(66, 133, 244, 0.1);
+}
+
+.btn-block {
+ width: 100%;
+ padding: 15px;
+ font-size: 1rem;
+}
+
+.login-form-footer {
text-align: center;
+ margin-top: 20px;
+ font-size: 0.9rem;
+}
+
+/* Student Dashboard */
+.dashboard-container {
+ display: flex;
+ min-height: 100vh;
+}
+
+.sidebar {
+ width: 260px;
+ background-color: var(--neutral-dark-text);
+ color: #fff;
+ display: flex;
+ flex-direction: column;
+ position: fixed;
+ height: 100%;
+}
+
+.sidebar-header {
+ padding: 25px 20px;
+ border-bottom: 1px solid rgba(255,255,255,0.1);
+}
+
+.sidebar-header h3 {
+ color: #fff;
+ font-weight: 600;
+}
+
+.sidebar-nav {
+ flex-grow: 1;
+}
+
+.sidebar-nav a {
+ display: block;
+ padding: 15px 20px;
+ color: #fff;
+ text-decoration: none;
+ font-weight: 500;
+ transition: background-color 0.3s ease;
+}
+
+.sidebar-nav a:hover, .sidebar-nav a.active {
+ background-color: rgba(255,255,255,0.1);
+}
+
+.sidebar-nav a i {
+ margin-right: 15px;
+ width: 20px;
+ text-align: center;
+}
+
+.sidebar-footer {
+ padding: 20px;
+ border-top: 1px solid rgba(255,255,255,0.1);
+}
+
+.logout-btn {
+ display: block;
+ text-align: center;
+ background-color: var(--primary-color);
+ color: #fff;
+ padding: 10px;
+ border-radius: 8px;
+ text-decoration: none;
+ font-weight: 600;
+ transition: background-color 0.3s ease;
+}
+
+.logout-btn:hover {
+ background-color: #3367D6;
+}
+
+.main-content {
+ margin-left: 260px;
+ flex-grow: 1;
+ background-color: var(--neutral-light-gray);
+ padding: 30px;
+}
+
+.header {
+ background-color: #fff;
+ padding: 30px;
+ border-radius: 12px;
+ margin-bottom: 30px;
+ box-shadow: 0 4px 10px rgba(0,0,0,0.05);
+}
+
+.header h2 {
+ font-size: 2.2rem;
+ margin-bottom: 5px;
+}
+
+.assignments-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
+ gap: 25px;
+}
+
+.assignment-card {
+ background-color: #fff;
+ border-radius: 12px;
+ box-shadow: 0 4px 10px rgba(0,0,0,0.05);
+ display: flex;
+ flex-direction: column;
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
-.feature-card:hover {
- transform: translateY(-10px);
- box-shadow: 0 10px 20px rgba(0,0,0,0.05);
+.assignment-card:hover {
+ transform: translateY(-5px);
+ box-shadow: 0 8px 20px rgba(0,0,0,0.08);
}
-.feature-card .icon {
- font-size: 3rem;
- color: var(--primary-color);
+.assignment-card-header {
+ padding: 20px;
+ border-bottom: 1px solid #eee;
+}
+
+.assignment-title {
+ font-size: 1.2rem;
+ font-weight: 600;
+ margin-bottom: 0;
+}
+
+.assignment-due-date {
+ font-size: 0.85rem;
+ color: #5f6368;
+}
+
+.assignment-card-body {
+ padding: 20px;
+ flex-grow: 1;
+}
+
+.assignment-card-footer {
+ padding: 0 20px 20px;
+}
+
+.empty-state {
+ grid-column: 1 / -1;
+ text-align: center;
+ padding: 60px 20px;
+ background-color: #fff;
+ border-radius: 12px;
+}
+
+.empty-state i {
+ font-size: 4rem;
+ color: var(--accent-color);
margin-bottom: 20px;
+}
+
+.empty-state h4 {
+ font-size: 1.5rem;
+ margin-bottom: 10px;
+}
+
+/* Assignment Detail */
+.exercises-section {
+ max-width: 900px;
+}
+
+.exercise-list {
+ display: flex;
+ flex-direction: column;
+ gap: 30px;
+}
+
+.exercise-card {
+ background-color: #fff;
+ border-radius: 12px;
+ box-shadow: 0 4px 10px rgba(0,0,0,0.05);
+}
+
+.exercise-card-header {
+ padding: 20px;
+ border-bottom: 1px solid #eee;
+ background-color: #fafafa;
+}
+
+.exercise-card-header h4 {
+ margin: 0;
+ font-size: 1.3rem;
+}
+
+.exercise-card-body {
+ padding: 25px;
+}
+
+.exercise-question {
+ font-size: 1.1rem;
+ margin-bottom: 25px;
+}
+
+.exercise-actions {
+ margin-top: 20px;
+ display: flex;
+ gap: 15px;
+ flex-wrap: wrap;
+}
+
+.hint-container .alert {
+ margin-top: 20px;
+}
+
+/* Responsive adjustments */
+@media (max-width: 992px) {
+ .login-container {
+ grid-template-columns: 1fr;
+ }
+
+ .login-branding {
+ display: none;
+ }
+
+ .login-form-wrapper {
+ padding: 20px;
+ }
+
+ .sidebar {
+ position: static;
+ width: 100%;
+ height: auto;
+ flex-direction: row;
+ align-items: center;
+ }
+
+ .main-content {
+ margin-left: 0;
+ }
+
+ .sidebar-header {
+ display: none;
+ }
+
+ .sidebar-nav {
+ display: flex;
+ flex-grow: 1;
+ justify-content: space-around;
+ }
+
+ .sidebar-footer {
+ display: none; /* Or adjust to a dropdown menu */
+ }
}
\ No newline at end of file
diff --git a/staticfiles/css/custom.css b/staticfiles/css/custom.css
index 14aa7b7..aec0ec4 100644
--- a/staticfiles/css/custom.css
+++ b/staticfiles/css/custom.css
@@ -3,6 +3,7 @@
--primary-color: #4285F4;
--secondary-color: #FBBC05;
--accent-color: #34A853;
+ --tertiary-color: #EA4335;
--neutral-light-gray: #F8F9FA;
--neutral-dark-text: #202124;
--font-headings: 'Poppins', sans-serif;
@@ -12,7 +13,7 @@
body {
font-family: var(--font-body);
color: var(--neutral-dark-text);
- background-color: #fff;
+ background-color: var(--neutral-light-gray);
line-height: 1.6;
}
@@ -53,47 +54,347 @@ h1, h2, h3, h4, h5, h6 {
border-color: #F9A825;
}
-.hero {
- padding: 100px 0;
- background: linear-gradient(135deg, #E3F2FD, #FFFFFF);
- text-align: center;
- position: relative;
- overflow: hidden;
+.btn-tertiary {
+ background-color: var(--tertiary-color);
+ border-color: var(--tertiary-color);
+ color: #fff;
}
-.hero h1 {
- font-size: 3.5rem;
+.btn-tertiary:hover {
+ background-color: #D93025;
+ border-color: #D93025;
+}
+
+.login-container {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ min-height: 100vh;
+ width: 100%;
+}
+
+.login-branding {
+ background: linear-gradient(135deg, var(--primary-color), var(--accent-color));
+ color: #fff;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 40px;
+ text-align: center;
+}
+
+.login-branding-content h1 {
+ font-size: 2.8rem;
font-weight: 700;
margin-bottom: 20px;
+}
+
+.login-branding-content p {
+ font-size: 1.1rem;
+ max-width: 400px;
+ margin: 0 auto;
+}
+
+.login-form-wrapper {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 40px;
+ background-color: #fff;
+}
+
+.login-form-container {
+ max-width: 400px;
+ width: 100%;
+}
+
+.login-form-container h2 {
+ font-size: 2rem;
+ font-weight: 700;
+ margin-bottom: 10px;
color: var(--neutral-dark-text);
}
-.hero .lead {
- font-size: 1.25rem;
- margin-bottom: 40px;
- color: #5f6368;
+.login-form {
+ margin-top: 30px;
}
-.features-section {
- padding: 80px 0;
+.form-group {
+ margin-bottom: 20px;
}
-.feature-card {
- background-color: var(--neutral-light-gray);
- border: none;
- border-radius: 12px;
- padding: 30px;
+.form-group label {
+ display: block;
+ font-weight: 600;
+ margin-bottom: 8px;
+ color: var(--neutral-dark-text);
+}
+
+.form-group input, .form-group textarea {
+ width: 100%;
+ padding: 12px 15px;
+ border: 1px solid #ccc;
+ border-radius: 8px;
+ font-size: 1rem;
+ transition: border-color 0.3s ease;
+}
+
+.form-group input:focus, .form-group textarea:focus {
+ outline: none;
+ border-color: var(--primary-color);
+ box-shadow: 0 0 0 3px rgba(66, 133, 244, 0.1);
+}
+
+.btn-block {
+ width: 100%;
+ padding: 15px;
+ font-size: 1rem;
+}
+
+.login-form-footer {
text-align: center;
+ margin-top: 20px;
+ font-size: 0.9rem;
+}
+
+/* Student Dashboard */
+.dashboard-container {
+ display: flex;
+ min-height: 100vh;
+}
+
+.sidebar {
+ width: 260px;
+ background-color: var(--neutral-dark-text);
+ color: #fff;
+ display: flex;
+ flex-direction: column;
+ position: fixed;
+ height: 100%;
+}
+
+.sidebar-header {
+ padding: 25px 20px;
+ border-bottom: 1px solid rgba(255,255,255,0.1);
+}
+
+.sidebar-header h3 {
+ color: #fff;
+ font-weight: 600;
+}
+
+.sidebar-nav {
+ flex-grow: 1;
+}
+
+.sidebar-nav a {
+ display: block;
+ padding: 15px 20px;
+ color: #fff;
+ text-decoration: none;
+ font-weight: 500;
+ transition: background-color 0.3s ease;
+}
+
+.sidebar-nav a:hover, .sidebar-nav a.active {
+ background-color: rgba(255,255,255,0.1);
+}
+
+.sidebar-nav a i {
+ margin-right: 15px;
+ width: 20px;
+ text-align: center;
+}
+
+.sidebar-footer {
+ padding: 20px;
+ border-top: 1px solid rgba(255,255,255,0.1);
+}
+
+.logout-btn {
+ display: block;
+ text-align: center;
+ background-color: var(--primary-color);
+ color: #fff;
+ padding: 10px;
+ border-radius: 8px;
+ text-decoration: none;
+ font-weight: 600;
+ transition: background-color 0.3s ease;
+}
+
+.logout-btn:hover {
+ background-color: #3367D6;
+}
+
+.main-content {
+ margin-left: 260px;
+ flex-grow: 1;
+ background-color: var(--neutral-light-gray);
+ padding: 30px;
+}
+
+.header {
+ background-color: #fff;
+ padding: 30px;
+ border-radius: 12px;
+ margin-bottom: 30px;
+ box-shadow: 0 4px 10px rgba(0,0,0,0.05);
+}
+
+.header h2 {
+ font-size: 2.2rem;
+ margin-bottom: 5px;
+}
+
+.assignments-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
+ gap: 25px;
+}
+
+.assignment-card {
+ background-color: #fff;
+ border-radius: 12px;
+ box-shadow: 0 4px 10px rgba(0,0,0,0.05);
+ display: flex;
+ flex-direction: column;
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
-.feature-card:hover {
- transform: translateY(-10px);
- box-shadow: 0 10px 20px rgba(0,0,0,0.05);
+.assignment-card:hover {
+ transform: translateY(-5px);
+ box-shadow: 0 8px 20px rgba(0,0,0,0.08);
}
-.feature-card .icon {
- font-size: 3rem;
- color: var(--primary-color);
+.assignment-card-header {
+ padding: 20px;
+ border-bottom: 1px solid #eee;
+}
+
+.assignment-title {
+ font-size: 1.2rem;
+ font-weight: 600;
+ margin-bottom: 0;
+}
+
+.assignment-due-date {
+ font-size: 0.85rem;
+ color: #5f6368;
+}
+
+.assignment-card-body {
+ padding: 20px;
+ flex-grow: 1;
+}
+
+.assignment-card-footer {
+ padding: 0 20px 20px;
+}
+
+.empty-state {
+ grid-column: 1 / -1;
+ text-align: center;
+ padding: 60px 20px;
+ background-color: #fff;
+ border-radius: 12px;
+}
+
+.empty-state i {
+ font-size: 4rem;
+ color: var(--accent-color);
margin-bottom: 20px;
+}
+
+.empty-state h4 {
+ font-size: 1.5rem;
+ margin-bottom: 10px;
+}
+
+/* Assignment Detail */
+.exercises-section {
+ max-width: 900px;
+}
+
+.exercise-list {
+ display: flex;
+ flex-direction: column;
+ gap: 30px;
+}
+
+.exercise-card {
+ background-color: #fff;
+ border-radius: 12px;
+ box-shadow: 0 4px 10px rgba(0,0,0,0.05);
+}
+
+.exercise-card-header {
+ padding: 20px;
+ border-bottom: 1px solid #eee;
+ background-color: #fafafa;
+}
+
+.exercise-card-header h4 {
+ margin: 0;
+ font-size: 1.3rem;
+}
+
+.exercise-card-body {
+ padding: 25px;
+}
+
+.exercise-question {
+ font-size: 1.1rem;
+ margin-bottom: 25px;
+}
+
+.exercise-actions {
+ margin-top: 20px;
+ display: flex;
+ gap: 15px;
+ flex-wrap: wrap;
+}
+
+.hint-container .alert {
+ margin-top: 20px;
+}
+
+/* Responsive adjustments */
+@media (max-width: 992px) {
+ .login-container {
+ grid-template-columns: 1fr;
+ }
+
+ .login-branding {
+ display: none;
+ }
+
+ .login-form-wrapper {
+ padding: 20px;
+ }
+
+ .sidebar {
+ position: static;
+ width: 100%;
+ height: auto;
+ flex-direction: row;
+ align-items: center;
+ }
+
+ .main-content {
+ margin-left: 0;
+ }
+
+ .sidebar-header {
+ display: none;
+ }
+
+ .sidebar-nav {
+ display: flex;
+ flex-grow: 1;
+ justify-content: space-around;
+ }
+
+ .sidebar-footer {
+ display: none; /* Or adjust to a dropdown menu */
+ }
}
\ No newline at end of file
diff --git a/staticfiles/pasted-20251210-161034-71c4025f.jpg b/staticfiles/pasted-20251210-161034-71c4025f.jpg
new file mode 100644
index 0000000..9827864
Binary files /dev/null and b/staticfiles/pasted-20251210-161034-71c4025f.jpg differ
diff --git a/staticfiles/vm-shot-2025-12-10T16-08-25-291Z.jpg b/staticfiles/vm-shot-2025-12-10T16-08-25-291Z.jpg
new file mode 100644
index 0000000..9827864
Binary files /dev/null and b/staticfiles/vm-shot-2025-12-10T16-08-25-291Z.jpg differ