0% found this document useful (0 votes)
4 views24 pages

General File Structure

The document outlines a project structure for a task management application using Node.js, Express, and React, detailing backend and frontend components. It includes instructions for creating a task model, API endpoints for managing tasks, and a React component for the user interface. Additionally, it provides a recipe book application structure with models, routes, and frontend code for adding and filtering recipes, as well as a user authentication system for managing favorite items.

Uploaded by

boppana200312
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views24 pages

General File Structure

The document outlines a project structure for a task management application using Node.js, Express, and React, detailing backend and frontend components. It includes instructions for creating a task model, API endpoints for managing tasks, and a React component for the user interface. Additionally, it provides a recipe book application structure with models, routes, and frontend code for adding and filtering recipes, as well as a user authentication system for managing favorite items.

Uploaded by

boppana200312
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 24

General File Structure

Since the ByteXL environment already has packages installed, you can focus on where to write the code.
Here’s a suggestion for the project structure:

1. Backend (Node.js and Express):

o server.js: Entry point for the backend.

o routes/taskRoutes.js: Contains API endpoints.

o models/taskModel.js: Defines the MongoDB schema for tasks.

2. Frontend (React):

o App.js: Main React component.

o components/TaskManager.js: Contains the UI for adding, viewing, and deleting tasks.

o services/taskService.js: Handles API calls to the backend.

Task (a): Create a Task Model with Required Fields

Backend File: models/taskModel.js

This file defines the MongoDB schema for tasks, including fields for name, description, due date, and
priority.

const mongoose = require('mongoose');

const taskSchema = new mongoose.Schema({

name: { type: String, required: true },

description: { type: String, required: true },

dueDate: { type: Date, required: true },

priority: {

type: String,

required: true,

enum: ['high', 'medium', 'low']

});

const Task = mongoose.model('Task', taskSchema);


module.exports = Task;

Task (b): Sort Tasks by Priority and Due Date

Backend File: routes/taskRoutes.js

Create an endpoint to fetch tasks sorted by priority and due date.

const express = require('express');

const router = express.Router();

const Task = require('../models/taskModel');

// Get all tasks sorted by priority and due date

router.get('/tasks', async (req, res) => {

try {

const tasks = await Task.find().sort({

priority: 1, // Ascending order (high first)

dueDate: 1 // Earlier dates first

});

res.json(tasks);

} catch (err) {

res.status(500).json({ message: err.message });

});

module.exports = router;

Task (c): Add, View, and Delete Tasks

Backend File: routes/taskRoutes.js

Add API endpoints to create, view, and delete tasks.

// Add a new task

router.post('/tasks', async (req, res) => {

const { name, description, dueDate, priority } = req.body;

try {
const task = new Task({ name, description, dueDate, priority });

await task.save();

res.status(201).json(task);

} catch (err) {

res.status(400).json({ message: err.message });

});

// Delete a task

router.delete('/tasks/:id', async (req, res) => {

try {

const task = await Task.findByIdAndDelete(req.params.id);

if (!task) {

return res.status(404).json({ message: 'Task not found' });

res.json({ message: 'Task deleted successfully' });

} catch (err) {

res.status(500).json({ message: err.message });

});

Frontend File: components/TaskManager.js


Create a React component to handle the task manager
UI.
import React, { useState, useEffect } from 'react';

import axios from '../services/taskService';

const TaskManager = () => {


const [tasks, setTasks] = useState([]);

const [task, setTask] = useState({ name: '', description: '', dueDate: '', priority: 'medium' });

// Fetch tasks from backend

useEffect(() => {

const fetchTasks = async () => {

const response = await axios.get('/tasks');

setTasks(response.data);

};

fetchTasks();

}, []);

// Handle input changes

const handleChange = (e) => {

setTask({ ...task, [e.target.name]: e.target.value });

};

// Add a new task

const addTask = async (e) => {

e.preventDefault();

const response = await axios.post('/tasks', task);

setTasks([...tasks, response.data]);

};

// Delete a task

const deleteTask = async (id) => {

await axios.delete(`/tasks/${id}`);

setTasks(tasks.filter(task => task._id !== id));

};
return (

<div>

<h1>Task Manager</h1>

<form onSubmit={addTask}>

<input name="name" placeholder="Task Name" onChange={handleChange} required />

<input name="description" placeholder="Description" onChange={handleChange}


required />

<input type="date" name="dueDate" onChange={handleChange} required />

<select name="priority" onChange={handleChange}>

<option value="high">High</option>

<option value="medium" selected>Medium</option>

<option value="low">Low</option>

</select>

<button type="submit">Add Task</button>

</form>

<ul>

{tasks.map(task => (

<li key={task._id}>

{task.name} - {task.priority} - {task.dueDate}

<button onClick={() => deleteTask(task._id)}>Delete</button>

</li>

))}

</ul>

</div>

);

};
export default TaskManager;

project-folder/

├── models/

│ └── taskModel.js <-- This file

├── routes/ <-- For your API routes (e.g., taskRoutes.js)

├── app.js <-- Your main backend file (where you connect MongoDB)

├── package.json <-- Lists your dependencies

└── node_modules/ <-- Installed packages

2 Got it! I'll provide the step-by-step codes for your Recipe Book with Category Filter project in a clear
and simple way so you can write them down before execution. Here's how to proceed:

Task (a): Build a Recipe Book App

Backend Code: Recipe Model

 File: models/recipeModel.js

javascript

Copy code

const mongoose = require('mongoose');

const recipeSchema = new mongoose.Schema({

name: { type: String, required: true },

ingredients: { type: String, required: true },

category: { type: String, required: true },

});
module.exports = mongoose.model('Recipe', recipeSchema);

Task (b): Implement API Endpoints

Backend Code: Recipe Routes

 File: routes/recipeRoutes.js

const express = require('express');

const Recipe = require('../models/recipeModel');

const router = express.Router();

// Add a new recipe

router.post('/recipes', async (req, res) => {

try {

const { name, ingredients, category } = req.body;

const recipe = new Recipe({ name, ingredients, category });

await recipe.save();

res.status(201).json(recipe);

} catch (error) {

res.status(400).json({ error: error.message });

});

// Get all recipes

router.get('/recipes', async (req, res) => {

try {

const recipes = await Recipe.find();

res.status(200).json(recipes);

} catch (error) {

res.status(400).json({ error: error.message });

}
});

// Get recipes by category

router.get('/recipes/:category', async (req, res) => {

try {

const { category } = req.params;

const recipes = await Recipe.find({ category });

res.status(200).json(recipes);

} catch (error) {

res.status(400).json({ error: error.message });

});

module.exports = router;

Backend Code: Main App

 File: app.js

const express = require('express');

const mongoose = require('mongoose');

const recipeRoutes = require('./routes/recipeRoutes');

require('dotenv').config();

const app = express();

app.use(express.json());

// Connect to MongoDB

mongoose.connect(process.env.MONGO_URI, {

useNewUrlParser: true,

useUnifiedTopology: true,

}).then(() => console.log("MongoDB Connected"))


.catch((error) => console.log(error));

// Use Routes

app.use('/api', recipeRoutes);

const PORT = process.env.PORT || 5000;

app.listen(PORT, () => console.log(`Server running on port ${PORT}`));

Task (c): Frontend for Recipe Book

Frontend Code: HTML Structure

 File: frontend/index.html

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>Recipe Book</title>

<link rel="stylesheet" href="styles.css">

</head>

<body>

<h1>Recipe Book</h1>

<form id="recipeForm">

<input type="text" id="name" placeholder="Recipe Name" required>

<textarea id="ingredients" placeholder="Ingredients" required></textarea>

<select id="category" required>

<option value="">Select Category</option>

<option value="Dessert">Dessert</option>

<option value="Main Course">Main Course</option>

<option value="Appetizer">Appetizer</option>
</select>

<button type="submit">Add Recipe</button>

</form>

<div>

<label for="filter">Filter by Category:</label>

<select id="filter">

<option value="">All</option>

<option value="Dessert">Dessert</option>

<option value="Main Course">Main Course</option>

<option value="Appetizer">Appetizer</option>

</select>

</div>

<div id="recipes"></div>

<script src="script.js"></script>

</body>

</html>

Frontend Code: CSS Styling

 File: frontend/styles.css

body {

font-family: Arial, sans-serif;

margin: 20px;

h1 {

text-align: center;

form, #filter {

margin: 20px auto;


max-width: 400px;

form input, form textarea, form select, form button, #filter select {

display: block;

width: 100%;

margin: 10px 0;

padding: 10px;

#recipes {

margin: 20px auto;

max-width: 600px;

.recipe {

border: 1px solid #ccc;

padding: 10px;

margin: 10px 0;

Frontend Code: JavaScript Logic

 File: frontend/script.js

const recipeForm = document.getElementById('recipeForm');

const filter = document.getElementById('filter');

const recipesDiv = document.getElementById('recipes');

const API_URL = 'http://localhost:5000/api/recipes';

// Fetch and display recipes

const fetchRecipes = async (category = '') => {


const url = category ? `${API_URL}/${category}` : API_URL;

const response = await fetch(url);

const recipes = await response.json();

recipesDiv.innerHTML = recipes.map(recipe => `

<div class="recipe">

<h3>${recipe.name}</h3>

<p><strong>Ingredients:</strong> ${recipe.ingredients}</p>

<p><strong>Category:</strong> ${recipe.category}</p>

</div>

`).join('');

};

// Add a new recipe

recipeForm.addEventListener('submit', async (e) => {

e.preventDefault();

const name = document.getElementById('name').value;

const ingredients = document.getElementById('ingredients').value;

const category = document.getElementById('category').value;

await fetch(API_URL, {

method: 'POST',

headers: { 'Content-Type': 'application/json' },

body: JSON.stringify({ name, ingredients, category }),

});

recipeForm.reset();

fetchRecipes();

});
// Filter recipes by category

filter.addEventListener('change', (e) => {

const category = e.target.value;

fetchRecipes(category);

});

// Initial fetch

fetchRecipes();

Write Down the Codes

 Backend:

o Write recipeModel.js, recipeRoutes.js, and app.js.

 Frontend:

o Write index.html, styles.css, and script.js.

recipe-book/

├── backend/

│ ├── models/

│ │ └── recipeModel.js

│ ├── routes/

│ │ └── recipeRoutes.js

│ └── app.js

├── frontend/

│ ├── index.html

│ ├── styles.css

│ └── script.js

Task (a): Develop an app where users can add items to their favorites list after logging in.
1. Create a User model and a Favorite model.
 User model will contain fields for username and password.
 Favorite model will contain fields for name, category, and a reference to the user.

User Model (userModel.js):


const mongoose = require('mongoose');

const userSchema = new mongoose.Schema({


username: { type: String, required: true },
password: { type: String, required: true },
});

module.exports = mongoose.model('User', userSchema);

Favorite Model (favoriteModel.js):

const mongoose = require('mongoose');

const favoriteSchema = new mongoose.Schema({


name: { type: String, required: true },
category: { type: String, required: true },
user: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
});

module.exports = mongoose.model('Favorite', favoriteSchema);

Task (b): Use JWT for authentication, allowing access to the favorites list only after login.
2. Implement user authentication (login and registration) with JWT:
 Register a new user with username and password.
 Login the user and issue a JWT token for subsequent requests.
User Authentication Routes (userRoutes.js):
 User Registration Route:

const express = require('express');
const bcrypt = require('bcryptjs');
const User = require('../models/userModel');
const router = express.Router();

router.post('/register', async (req, res) => {


const { username, password } = req.body;
const hashedPassword = await bcrypt.hash(password, 10);
const newUser = new User({ username, password: hashedPassword });
await newUser.save();
res.status(201).json({ message: 'User created successfully' });
});
module.exports = router;

 User Login Route (with JWT):


javascript
Copy code
const jwt = require('jsonwebtoken');

router.post('/login', async (req, res) => {


const { username, password } = req.body;
const user = await User.findOne({ username });
if (!user) return res.status(400).json({ message: 'User not found' });

const isPasswordValid = await bcrypt.compare(password, user.password);


if (!isPasswordValid) return res.status(400).json({ message: 'Invalid credentials' });

const token = jwt.sign({ userId: user._id }, 'secretKey', { expiresIn: '1h' });


res.json({ token });
});

module.exports = router;

Task (c): Save favorite items in MongoDB, associated with the user account.
3. Create routes to add, view, and delete favorite items.
 Add Favorite Route (Authenticated):
 const Favorite = require('../models/favoriteModel');

 router.post('/add', authenticateToken, async (req, res) => {
 const { name, category } = req.body;
 const newFavorite = new Favorite({ name, category, user: req.userId });
 await newFavorite.save();
 res.status(201).json(newFavorite);
 });

 View Favorites Route (Authenticated):

javascript
Copy code
 router.get('/favorites', authenticateToken, async (req, res) => {
 const favorites = await Favorite.find({ user: req.userId });
 res.json(favorites);
 });

 Delete Favorite Route (Authenticated):

javascript
Copy code
 router.delete('/delete/:id', authenticateToken, async (req, res) => {
 await Favorite.findByIdAndDelete(req.params.id);
 res.json({ message: 'Favorite deleted' });
 });
 Authentication Middleware:
 const authenticateToken = (req, res, next) => {
 const token = req.header('Authorization')?.replace('Bearer ', '');
 if (!token) return res.status(403).json({ message: 'Access denied' });

 jwt.verify(token, 'secretKey', (err, decoded) => {
 if (err) return res.status(403).json({ message: 'Invalid token' });
 req.userId = decoded.userId;
 next();
 });
 };

Frontend (Client-Side) Code

1. Login Component (Login.js):

 A form that allows users to log in and stores the JWT token for future requests.
 import { useState } from 'react';
 import axios from 'axios';

 const Login = ({ onLogin }) => {
 const [username, setUsername] = useState('');
 const [password, setPassword] = useState('');

 const handleSubmit = async (e) => {
 e.preventDefault();
 try {
 const { data } = await axios.post('http://localhost:5000/api/users/login', { username,
password });
 localStorage.setItem('token', data.token);
 onLogin();
 } catch (error) {
 console.error('Login error:', error.response?.data?.message);
 }
 };

 return (
 <form onSubmit={handleSubmit}>
 <input type="text" placeholder="Username" value={username} onChange={(e) =>
setUsername(e.target.value)} />
 <input type="password" placeholder="Password" value={password} onChange={(e) =>
setPassword(e.target.value)} />
 <button type="submit">Login</button>
 </form>
 );
 };

 export default Login;
 2. Favorites Component (Favorites.js):
 Allows users to add, view, and delete favorite items, with authentication.
 javascript
 Copy code
 import { useState, useEffect } from 'react';
 import axios from 'axios';

 const Favorites = () => {
 const [name, setName] = useState('');
 const [category, setCategory] = useState('');
 const [favorites, setFavorites] = useState([]);

 useEffect(() => {
 const fetchFavorites = async () => {
 const token = localStorage.getItem('token');
 const { data } = await axios.get('http://localhost:5000/api/favorites/favorites', {
 headers: { Authorization: `Bearer ${token}` }
 });
 setFavorites(data);
 };

 fetchFavorites();
 }, []);

 const handleAddFavorite = async () => {
 const token = localStorage.getItem('token');
 await axios.post('http://localhost:5000/api/favorites/add', { name, category }, {
 headers: { Authorization: `Bearer ${token}` }
 });
 setName('');
 setCategory('');
 const { data } = await axios.get('http://localhost:5000/api/favorites/favorites', {
 headers: { Authorization: `Bearer ${token}` }
 });
 setFavorites(data);
 };

 const handleDeleteFavorite = async (id) => {
 const token = localStorage.getItem('token');
 await axios.delete(`http://localhost:5000/api/favorites/delete/${id}`, {
 headers: { Authorization: `Bearer ${token}` }
 });
 const { data } = await axios.get('http://localhost:5000/api/favorites/favorites', {
 headers: { Authorization: `Bearer ${token}` }
 });
 setFavorites(data);
 };

 return (
 <div>
 <h1>Your Favorites</h1>
 <input type="text" placeholder="Item Name" value={name} onChange={(e) =>
setName(e.target.value)} />
 <input type="text" placeholder="Category" value={category} onChange={(e) =>
setCategory(e.target.value)} />
 <button onClick={handleAddFavorite}>Add Favorite</button>

 <ul>
 {favorites.map((favorite) => (
 <li key={favorite._id}>
 {favorite.name} - {favorite.category}
 <button onClick={() => handleDeleteFavorite(favorite._id)}>Delete</button>
 </li>
 ))}
 </ul>
 </div>
 );
 };

 export default Favorites;
 Summary:
 1. Backend:
 Create User and Favorite models.
 Implement JWT authentication for secure login.
 Set up routes for user registration, login, and managing favorite items (add, view, delete).
 2. Frontend:
 Login Component handles user login and stores the JWT token.
 Favorites Component displays the favorites list and allows users to add or delete items.
3. Expense Tracker with Monthly View a. Set up an expense tracker where users can add
expenses with a description, amount, and date. b. Display expenses for the current month,
grouped by day. c. Store expenses in MongoDB and show a summary of total expenses for the
month.
Here’s how you can write the code on paper for the Expense Tracker with Monthly View task:

Task (a): Set up an expense tracker where users can add expenses with a description, amount,
and date.
1. Create an Expense Model to store the expenses in MongoDB:

const mongoose = require('mongoose');

const expenseSchema = new mongoose.Schema({


description: { type: String, required: true },
amount: { type: Number, required: true },
date: { type: Date, required: true },
});

module.exports = mongoose.model('Expense', expenseSchema);

2. Create an API route to add expenses:


const express = require('express');
const Expense = require('../models/expenseModel');
const router = express.Router();

router.post('/add', async (req, res) => {


const { description, amount, date } = req.body;
const newExpense = new Expense({ description, amount, date });
await newExpense.save();
res.status(201).json(newExpense);
});

module.exports = router;

Task (b): Display expenses for the current month, grouped by day.
3. Create an API route to fetch expenses for the current month, grouped by day:
const moment = require('moment');

router.get('/monthly-expenses', async (req, res) => {


const startOfMonth = moment().startOf('month').toDate();
const endOfMonth = moment().endOf('month').toDate();

const expenses = await Expense.aggregate([


{ $match: { date: { $gte: startOfMonth, $lte: endOfMonth } } },
{
$group: {
_id: { $dayOfMonth: '$date' },
totalAmount: { $sum: '$amount' },
expenses: { $push: { description: '$description', amount: '$amount', date:
'$date' } },
},
},
{ $sort: { _id: 1 } },
]);

res.json(expenses);
});
Here’s how you can write the code on paper for the Expense Tracker with Monthly
View task:

Task (c): Store expenses in MongoDB and show a summary of total expenses for the
month.
4. Create an API route to fetch the total expenses for the current month:
router.get('/monthly-summary', async (req, res) => {
const startOfMonth = moment().startOf('month').toDate();
const endOfMonth = moment().endOf('month').toDate();

const totalExpenses = await Expense.aggregate([


{ $match: { date: { $gte: startOfMonth, $lte: endOfMonth } } },
{ $group: { _id: null, totalAmount: { $sum: '$amount' } } },
]);

res.json(totalExpenses[0] || { totalAmount: 0 });


});
Frontend Example (React):
 Expenses List (Monthly View) Component:
import { useEffect, useState } from 'react';
import axios from 'axios';

const MonthlyExpenses = () => {


const [expenses, setExpenses] = useState([]);
const [totalAmount, setTotalAmount] = useState(0);

useEffect(() => {
// Fetch monthly expenses grouped by day
axios.get('http://localhost:5000/api/expenses/monthly-expenses')
.then(response => setExpenses(response.data));
// Fetch total expenses for the month
axios.get('http://localhost:5000/api/expenses/monthly-summary')
.then(response => setTotalAmount(response.data.totalAmount));
}, []);

return (
<div>
<h1>Monthly Expenses</h1>
<h2>Total Expenses: ${totalAmount}</h2>

{expenses.map((dayExpense) => (
<div key={dayExpense._id}>
<h3>Day {dayExpense._id}</h3>
<ul>
{dayExpense.expenses.map((expense, index) => (
<li key={index}>
{expense.description}: ${expense.amount}
</li>
))}
</ul>
<p>Total for the day: ${dayExpense.totalAmount}</p>
</div>
))}
</div>
);
};

export default MonthlyExpenses;


Summary:
1. Backend (Express):
o Expense Model: Create a schema for expenses with description, amount, and date.
o Add Expense Route: API to add expenses.
o Monthly Expenses Route: API to fetch expenses for the current month, grouped by
day.
o Monthly Summary Route: API to fetch the total expenses for the current month.
2. Frontend (React):
o Monthly Expenses Component: Display a list of expenses for the current month,
grouped by day, and show the total expenses for the month.
Let me simplify the code further for better understanding and easier memorization. I’ll focus
only on the essential logic for your lab requirements.

a. Adding Items to Favorites List


Backend: models/userModel.js
This defines the structure of a user with their favorites.
javascript
Copy code
const mongoose = require('mongoose');

const userSchema = new mongoose.Schema({


username: String,
password: String,
favorites: [String] // Stores favorite items
});

module.exports = mongoose.model('User', userSchema);


Backend: routes/favorites.js
Handles adding items to the favorites list.
javascript
Copy code
const express = require('express');
const router = express.Router();
const User = require('../models/userModel');

// Add item to favorites


router.post('/add-favorite', async (req, res) => {
const { username, item } = req.body;
try {
const user = await User.findOne({ username });
if (!user) return res.status(404).json({ message: "User not found" });

user.favorites.push(item);
await user.save();
res.json({ message: "Item added to favorites", favorites: user.favorites });
} catch (err) {
res.status(500).json({ message: "Error adding favorite" });
}
});

module.exports = router;

b. JWT for Authentication


Backend: middleware/authMiddleware.js
A middleware to check if the user is authenticated.
javascript
Copy code
const jwt = require('jsonwebtoken');

module.exports = (req, res, next) => {


const token = req.headers.authorization?.split(' ')[1]; // "Bearer <token>"
if (!token) return res.status(401).json({ message: "Unauthorized" });

try {
const decoded = jwt.verify(token, "secret"); // Use a secret key
req.user = decoded;
next();
} catch (err) {
res.status(403).json({ message: "Invalid token" });
}
};
Backend: routes/auth.js
Handles login and returns a JWT token.
javascript
Copy code
const express = require('express');
const router = express.Router();
const User = require('../models/userModel');
const jwt = require('jsonwebtoken');

// Login and return JWT


router.post('/login', async (req, res) => {
const { username, password } = req.body;

const user = await User.findOne({ username });


if (!user || user.password !== password) {
return res.status(400).json({ message: "Invalid credentials" });
}

const token = jwt.sign({ username }, "secret", { expiresIn: '1h' }); // Secret key
res.json({ token });
});

module.exports = router;

c. Saving Favorites in MongoDB


This is covered in a. The favorites array in the user schema ensures that items are saved and
retrieved from MongoDB.
Simplified Server File
Backend: app.js
Connects everything together.
javascript
Copy code
const express = require('express');
const mongoose = require('mongoose');
const authRoutes = require('./routes/auth');
const favoritesRoutes = require('./routes/favorites');

const app = express();


app.use(express.json());

// Connect to MongoDB
mongoose.connect('mongodb://localhost:27017/favoritesApp', { useNewUrlParser: true,
useUnifiedTopology: true })
.then(() => console.log("MongoDB Connected"))
.catch(err => console.error(err));

// Routes
app.use('/api/auth', authRoutes);
app.use('/api/favorites', favoritesRoutes);

const PORT = 5000;


app.listen(PORT, () => console.log(`Server running on port ${PORT}`));

Front-End Workflow (Optional):


You don’t need to memorize front-end code. Just understand the flow:
1. User logs in using /api/auth/login and gets a token.
2. Add favorites by sending the token in the request header to /api/favorites/add-favorite.

What to Focus On Writing:


1. Model Code (userSchema is very small and simple).
2. JWT Authentication (focus on authMiddleware and login route).
3. Favorites Addition Route (only 10 lines of logic).

This is the most simplified structure possible for your task. Focus on understanding these small
blocks to write and remember them for your exam. 😊
4o

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy