diff --git a/joke-generator/README.md b/joke-generator/README.md
new file mode 100644
index 0000000..c105083
--- /dev/null
+++ b/joke-generator/README.md
@@ -0,0 +1,227 @@
+# š Random Joke Generator
+
+A complete, production-ready joke generator that fetches random jokes from an external API (JokeAPI). Includes implementations in Python and JavaScript with a beautiful web UI.
+
+## š Features
+
+⨠**Multiple Implementations**
+- Python CLI with interactive menu
+- JavaScript with async/await
+- Responsive HTML5 web interface
+
+ā
**Joke Categories**
+- Any (random joke)
+- General
+- Programming
+- Knock-Knock
+
+š”ļø **Robust Error Handling**
+- Network timeout handling
+- Connection error recovery
+- Graceful failure messages
+
+šØ **Beautiful UI**
+- Gradient design
+- Smooth animations
+- Mobile responsive
+- Punchline reveal functionality
+
+š” **External API Integration**
+- Uses [JokeAPI](https://jokeapi.dev/)
+- Free, no authentication required
+- Fast and reliable
+
+## š Quick Start
+
+### Python CLI
+
+**Requirements:**
+```bash
+pip install requests
+```
+
+**Usage:**
+```bash
+python joke_generator.py
+```
+
+**Features:**
+- Interactive menu system
+- Press Enter to reveal punchlines
+- Safe mode enabled by default
+- Session management with connection pooling
+
+### Web UI
+
+**Usage:**
+Simply open `joke_generator.html` in any modern web browser!
+
+**Features:**
+- Click "Get a Joke" to fetch a random joke
+- Select joke type from dropdown
+- Press Enter key as shortcut
+- Automatic punchline reveal button for two-part jokes
+
+### JavaScript Module
+
+**Usage:**
+```javascript
+const generator = new JokeGeneratorUI();
+generator.init(); // Initialize event listeners
+
+// Or fetch directly
+const joke = await generator.fetchJoke("programming", true);
+generator.displayJoke(joke);
+```
+
+## š API Reference
+
+### JokeAPI Endpoints
+
+**Get Any Joke:**
+```
+GET https://v2.jokeapi.dev/joke/any?safe-mode=true
+```
+
+**Get Programming Joke:**
+```
+GET https://v2.jokeapi.dev/joke/programming?safe-mode=true
+```
+
+**Response Format (Single-part):**
+```json
+{
+ "type": "single",
+ "joke": "Why do Java developers wear glasses? Because they don't C#",
+ "id": 1
+}
+```
+
+**Response Format (Two-part):**
+```json
+{
+ "type": "twopart",
+ "setup": "Why did the scarecrow win an award?",
+ "delivery": "He was outstanding in his field!",
+ "id": 2
+}
+```
+
+## š» Code Examples
+
+### Python - Simple Usage
+
+```python
+from joke_generator import JokeGenerator
+
+# Create instance
+gen = JokeGenerator()
+
+# Fetch and display a joke
+joke = gen.get_joke("programming", safe_mode=True)
+if joke:
+ gen.display_joke(joke)
+```
+
+### Python - Custom Implementation
+
+```python
+from joke_generator import JokeGenerator
+
+gen = JokeGenerator(timeout=15)
+joke_data = gen.get_joke("knock-knock")
+
+if joke_data["type"] == "twopart":
+ print(joke_data["setup"])
+ input("Press Enter for the punchline...")
+ print(joke_data["delivery"])
+```
+
+### JavaScript - Fetch Joke
+
+```javascript
+const ui = new JokeGeneratorUI();
+
+// Fetch a programming joke
+const joke = await ui.fetchJoke("programming", true);
+
+// Display it
+ui.displayJoke(joke);
+```
+
+## š§ Customization
+
+### Change API Endpoint
+
+**Python:**
+```python
+generator.BASE_URL = "https://custom-api.com/jokes"
+```
+
+**JavaScript:**
+```javascript
+generator.baseUrl = "https://custom-api.com/jokes";
+```
+
+### Disable Safe Mode
+
+**Python:**
+```python
+joke = generator.get_joke("any", safe_mode=False)
+```
+
+**JavaScript:**
+```javascript
+const joke = await generator.fetchJoke("any", false);
+```
+
+### Adjust Timeout
+
+**Python:**
+```python
+generator = JokeGenerator(timeout=20)
+```
+
+**JavaScript:**
+```javascript
+generator.timeout = 20000; // milliseconds
+```
+
+## š Future Enhancements
+
+- [ ] Save favorite jokes to local storage
+- [ ] Share jokes on social media
+- [ ] Rate jokes (like/dislike)
+- [ ] Search by keyword
+- [ ] Multiple language support
+- [ ] Daily joke email notifications
+- [ ] Dark mode toggle
+- [ ] Accessibility improvements (WCAG 2.1)
+
+## š File Structure
+
+```
+joke-generator/
+āāā joke_generator.py # Python CLI implementation
+āāā joke_generator.js # JavaScript module
+āāā joke_generator.html # Web UI
+āāā README.md # Documentation
+```
+
+## š Resources
+
+- [JokeAPI Documentation](https://jokeapi.dev/)
+- [Python Requests Library](https://requests.readthedocs.io/)
+- [MDN Web Docs - Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)
+
+## š License
+
+This project is open source and available under the MIT License.
+
+## š¤ Contributing
+
+Feel free to fork, modify, and use this project as you wish. Suggestions for improvements are always welcome!
+
+---
+
+**Made with ā¤ļø for the developer community**
diff --git a/joke-generator/joke_generator.html b/joke-generator/joke_generator.html
new file mode 100644
index 0000000..ba5b296
--- /dev/null
+++ b/joke-generator/joke_generator.html
@@ -0,0 +1,220 @@
+
+
+
+
+
+ Random Joke Generator
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/joke-generator/joke_generator.js b/joke-generator/joke_generator.js
new file mode 100644
index 0000000..23a2ce8
--- /dev/null
+++ b/joke-generator/joke_generator.js
@@ -0,0 +1,192 @@
+/**
+ * Random Joke Generator - JavaScript Implementation
+ * Fetches jokes from JokeAPI and displays them with smooth animations
+ * Includes XSS protection and comprehensive error handling
+ */
+
+class JokeGeneratorUI {
+ constructor() {
+ this.baseUrl = "https://v2.jokeapi.dev/joke";
+ this.timeout = 10000; // milliseconds
+ this.jokeTypes = ["any", "general", "programming", "knock-knock"];
+ this.currentJoke = null;
+ this.isLoading = false;
+ }
+
+ /**
+ * Initialize event listeners
+ */
+ init() {
+ const getJokeBtn = document.getElementById("get-joke-btn");
+ const punchlineBtn = document.getElementById("punchline-btn");
+ const jokeTypeSelect = document.getElementById("joke-type");
+
+ if (getJokeBtn) {
+ getJokeBtn.addEventListener("click", () => this.handleGetJoke());
+ if (jokeTypeSelect) {
+ jokeTypeSelect.addEventListener("keypress", (e) => {
+ if (e.key === "Enter") this.handleGetJoke();
+ });
+ }
+ }
+
+ if (punchlineBtn) {
+ punchlineBtn.addEventListener("click", () => this.showPunchline());
+ }
+ }
+
+ /**
+ * Escape HTML to prevent XSS attacks
+ */
+ escapeHtml(text) {
+ const map = {
+ "&": "&",
+ "<": "<",
+ ">": ">",
+ '"': """,
+ "'": "'",
+ };
+ return text.replace(/[&<>"']/g, (m) => map[m]);
+ }
+
+ /**
+ * Fetch a joke from the API
+ */
+ async fetchJoke(jokeType = "any", safeMode = true) {
+ try {
+ if (!this.jokeTypes.includes(jokeType.toLowerCase())) {
+ console.error(`Invalid joke type: ${jokeType}`);
+ return null;
+ }
+
+ const url = new URL(`${this.baseUrl}/${jokeType}`);
+ url.searchParams.append("safe-mode", safeMode.toString().toLowerCase());
+
+ const controller = new AbortController();
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
+
+ const response = await fetch(url.toString(), {
+ signal: controller.signal,
+ });
+
+ clearTimeout(timeoutId);
+
+ if (!response.ok) {
+ throw new Error(
+ `HTTP Error: ${response.status} ${response.statusText}`
+ );
+ }
+
+ const data = await response.json();
+ return data;
+ } catch (error) {
+ if (error.name === "AbortError") {
+ this.showError("Request timed out. Please try again.");
+ } else if (error instanceof TypeError) {
+ this.showError(
+ "Network error. Please check your internet connection."
+ );
+ } else {
+ this.showError("Failed to fetch joke. Please try again.");
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Display the joke in the UI
+ */
+ displayJoke(jokeData) {
+ if (!jokeData || jokeData.error) {
+ this.showError("No joke received. Please try again.");
+ return;
+ }
+
+ this.currentJoke = jokeData;
+ const jokeContainer = document.getElementById("joke-container");
+ const jokeText = document.getElementById("joke-text");
+ const punchlineBtn = document.getElementById("punchline-btn");
+
+ jokeContainer.style.display = "block";
+
+ if (jokeData.type === "single") {
+ jokeText.textContent = this.escapeHtml(jokeData.joke);
+ punchlineBtn.style.display = "none";
+ } else if (jokeData.type === "twopart") {
+ jokeText.textContent = this.escapeHtml(jokeData.setup);
+ punchlineBtn.style.display = "block";
+ punchlineBtn.textContent = "Show Punchline š";
+ punchlineBtn.dataset.punchline = this.escapeHtml(
+ jokeData.delivery
+ );
+ }
+
+ this.isLoading = false;
+ this.updateButtonState();
+ }
+
+ /**
+ * Show the punchline for two-part jokes
+ */
+ showPunchline() {
+ const jokeText = document.getElementById("joke-text");
+ const punchlineBtn = document.getElementById("punchline-btn");
+
+ if (punchlineBtn.dataset.punchline) {
+ jokeText.textContent = punchlineBtn.dataset.punchline;
+ punchlineBtn.style.display = "none";
+ }
+ }
+
+ /**
+ * Show error message in the joke container
+ */
+ showError(message) {
+ const jokeContainer = document.getElementById("joke-container");
+ const jokeText = document.getElementById("joke-text");
+ const punchlineBtn = document.getElementById("punchline-btn");
+
+ jokeContainer.style.display = "block";
+ jokeText.textContent = `Error: ${message}`;
+ punchlineBtn.style.display = "none";
+
+ this.isLoading = false;
+ this.updateButtonState();
+ }
+
+ /**
+ * Update button state based on loading status
+ */
+ updateButtonState() {
+ const getJokeBtn = document.getElementById("get-joke-btn");
+ if (getJokeBtn) {
+ getJokeBtn.disabled = this.isLoading;
+ getJokeBtn.textContent = this.isLoading ? "Loading..." : "Get a Joke!";
+ }
+ }
+
+ /**
+ * Handle the Get Joke button click
+ */
+ async handleGetJoke() {
+ if (this.isLoading) return;
+
+ this.isLoading = true;
+ this.updateButtonState();
+
+ const jokeTypeSelect = document.getElementById("joke-type");
+ const selectedType = jokeTypeSelect.value;
+
+ const jokeData = await this.fetchJoke(selectedType, true);
+
+ if (jokeData) {
+ this.displayJoke(jokeData);
+ }
+ }
+}
+
+// Initialize when DOM is ready
+document.addEventListener("DOMContentLoaded", () => {
+ const generator = new JokeGeneratorUI();
+ generator.init();
+});
diff --git a/joke-generator/joke_generator.py b/joke-generator/joke_generator.py
new file mode 100644
index 0000000..fe8a596
--- /dev/null
+++ b/joke-generator/joke_generator.py
@@ -0,0 +1,165 @@
+"""
+Random Joke Generator using JokeAPI
+A simple yet powerful joke generator that fetches jokes from an external API.
+Supports multiple joke types and provides a clean, interactive CLI experience.
+"""
+
+import requests
+import json
+from typing import Dict, Optional
+import sys
+
+
+class JokeGenerator:
+ """
+ A class to generate random jokes using the JokeAPI.
+ Provides methods to fetch and display jokes in various formats.
+ """
+
+ BASE_URL = "https://v2.jokeapi.dev/joke"
+ JOKE_TYPES = {
+ "any": "Any",
+ "general": "General",
+ "programming": "Programming",
+ "knock-knock": "Knock-Knock"
+ }
+
+ def __init__(self, timeout: int = 10):
+ """
+ Initialize the JokeGenerator.
+
+ Args:
+ timeout (int): Request timeout in seconds. Default is 10.
+ """
+ self.timeout = timeout
+ self.session = requests.Session()
+
+ def get_joke(self, joke_type: str = "any", safe_mode: bool = True) -> Optional[Dict]:
+ """
+ Fetch a random joke from JokeAPI.
+
+ Args:
+ joke_type (str): Type of joke ('any', 'general', 'programming', 'knock-knock')
+ safe_mode (bool): If True, filters out offensive jokes
+
+ Returns:
+ Optional[Dict]: Joke data dictionary or None if request fails
+ """
+ try:
+ # Validate joke type
+ if joke_type.lower() not in self.JOKE_TYPES:
+ print(f"Invalid joke type: {joke_type}")
+ print(f"Available types: {', '.join(self.JOKE_TYPES.keys())}")
+ return None
+
+ # Build API URL
+ url = f"{self.BASE_URL}/{joke_type}"
+ params = {"safe-mode": str(safe_mode).lower()}
+
+ # Make request
+ response = self.session.get(url, params=params, timeout=self.timeout)
+ response.raise_for_status()
+
+ return response.json()
+
+ except requests.exceptions.Timeout:
+ print("Error: Request timed out. Please try again.")
+ return None
+ except requests.exceptions.ConnectionError:
+ print("Error: Failed to connect to JokeAPI. Check your internet connection.")
+ return None
+ except requests.exceptions.HTTPError as e:
+ print(f"Error: HTTP {e.response.status_code} - {e.response.reason}")
+ return None
+ except Exception as e:
+ print(f"Error: An unexpected error occurred - {str(e)}")
+ return None
+
+ def display_joke(self, joke_data: Dict) -> None:
+ """
+ Display a joke in a formatted manner.
+
+ Args:
+ joke_data (Dict): Joke data from the API
+ """
+ if not joke_data or joke_data.get("error"):
+ print("No joke received. Please try again.")
+ return
+
+ print("\n" + "=" * 60)
+ print("š JOKE TIME! š")
+ print("=" * 60)
+
+ if joke_data["type"] == "single":
+ # Single-part joke
+ print(f"\n{joke_data['joke']}\n")
+ else:
+ # Two-part joke
+ print(f"\n{joke_data['setup']}\n")
+ input("Press Enter to reveal the punchline...\n")
+ print(f"{joke_data['delivery']}\n")
+
+ print("=" * 60 + "\n")
+
+ def interactive_menu(self) -> None:
+ """Display an interactive menu for selecting and fetching jokes."""
+ while True:
+ print("\nšŖ RANDOM JOKE GENERATOR šŖ")
+ print("-" * 40)
+ print("Select a joke type:")
+ print()
+
+ for idx, (key, display_name) in enumerate(self.JOKE_TYPES.items(), 1):
+ print(f" {idx}. {display_name}")
+
+ print(f" {len(self.JOKE_TYPES) + 1}. Exit")
+ print()
+
+ try:
+ choice = input("Enter your choice (1-5): ").strip()
+
+ if choice == str(len(self.JOKE_TYPES) + 1):
+ print("\nš Thanks for laughing with us! Goodbye!\n")
+ break
+
+ if choice not in ["1", "2", "3", "4"]:
+ print("Invalid choice. Please try again.")
+ continue
+
+ joke_type_list = list(self.JOKE_TYPES.keys())
+ selected_type = joke_type_list[int(choice) - 1]
+
+ print("\nš” Fetching your joke...")
+ joke_data = self.get_joke(selected_type, safe_mode=True)
+
+ if joke_data:
+ self.display_joke(joke_data)
+
+ another = (
+ input("Would you like another joke? (y/n): ")
+ .strip()
+ .lower()
+ )
+ if another != "y":
+ print("\nš Thanks for laughing with us! Goodbye!\n")
+ break
+
+ except KeyboardInterrupt:
+ print("\n\nš Goodbye!\n")
+ break
+ except Exception as e:
+ print(f"An error occurred: {e}")
+
+
+def main():
+ """Main entry point for the joke generator."""
+ try:
+ generator = JokeGenerator()
+ generator.interactive_menu()
+ except KeyboardInterrupt:
+ print("\n\nGoodbye!")
+ sys.exit(0)
+
+
+if __name__ == "__main__":
+ main()