diff --git a/Exercise 0/FavouriteThings.txt b/Exercise 0/FavouriteThings.txt new file mode 100644 index 00000000..8df0b258 --- /dev/null +++ b/Exercise 0/FavouriteThings.txt @@ -0,0 +1,2 @@ +Ahmad Yama Mohammad +Oppenheimer \ No newline at end of file diff --git a/Exercise 1/index.html b/Exercise 1/index.html new file mode 100644 index 00000000..a3f2ae66 --- /dev/null +++ b/Exercise 1/index.html @@ -0,0 +1,69 @@ + + + + + + Document + + +
+

Exercise 1

+

29/6/2026

+
+
+ + + + + + + + + + + + + + + + +
First NameLast NameFavourite FilmImageAudio SampleVideo Sample
JohnDoeOppenheimerOppenheimer Poster
+
+
+
+

Full Name:

+
+

Email:

+
+

Password:

+
+

Available Days:

+ + + + + + + + + +
+

Working on a new Website?

+ + + +
+

Comments:


+
+ + +
+
+ + \ No newline at end of file diff --git a/Exercise 2/index.html b/Exercise 2/index.html new file mode 100644 index 00000000..cf86d0c7 --- /dev/null +++ b/Exercise 2/index.html @@ -0,0 +1,60 @@ + + + + + + Graduation Party + + + +
+

Graduation Party

+

Welcome to the graduation party! We are excited to celebrate this special occasion with you. Please enjoy the festivities and have a great time!

+ +
+
+

Party Schedule

+ +
+
+

Meet the Hosts

+ + + + + + + + + + + + + +
NameRole
John DoeParty Host
Jane SmithEvent Coordinator
+

We are thrilled to host this graduation party and celebrate this milestone with you. Our team has worked hard to ensure that you have a memorable experience. Enjoy the party!

+
+
+

Register for the Party

+
+ +

+ + +

+ + +

+ + +
+
+ + + + diff --git a/Exercise 2/style.css b/Exercise 2/style.css new file mode 100644 index 00000000..70da9822 --- /dev/null +++ b/Exercise 2/style.css @@ -0,0 +1,57 @@ +.container { + border: 1px solid #ccc; + max-width: 800px; + margin: 0 auto; + padding: 20px; + background-image: url('https://upload.wikimedia.org/wikipedia/commons/5/56/Avicenna_birthday_anniversary_14.jpg'); + background-size: cover; + background-position: center; + background-repeat: no-repeat; + text-align: center; + +} +.container h1 { + margin-top: 0; + color: #fff; +} +.container p { + color: #fff; +} +.schedule { + background-color: rgba(192, 204, 19, 0.8); + padding: 20px; + border-radius: 10px; + border: 1px solid #ccc; +} +.schedule h2 { + margin-top: 0; +} +.host { + background-color: rgba(19, 204, 192, 0.8); + padding: 20px; + border-radius: 10px; + border: 1px solid #ccc; +} +.host h2 { + margin-top: 0; +} +.host table{ + border-collapse: collapse; + width: 100%; +} +.host table th, +.host table td { + border: 1px solid #ccc; + padding: 10px; + text-align: left; +} +.host p{ + color: #fff; +} + +.register { + background-color: rgba(71, 223, 134, 0.8); + padding: 20px; + border-radius: 10px; + border: 1px solid #ccc; +} \ No newline at end of file diff --git a/Exercise 3/Assets/background-desktop.jpg b/Exercise 3/Assets/background-desktop.jpg new file mode 100644 index 00000000..22ffcf85 Binary files /dev/null and b/Exercise 3/Assets/background-desktop.jpg differ diff --git a/Exercise 3/Assets/background-mobile.jpg b/Exercise 3/Assets/background-mobile.jpg new file mode 100644 index 00000000..e2c914f9 Binary files /dev/null and b/Exercise 3/Assets/background-mobile.jpg differ diff --git a/Exercise 3/index.html b/Exercise 3/index.html new file mode 100644 index 00000000..27c84225 --- /dev/null +++ b/Exercise 3/index.html @@ -0,0 +1,83 @@ + + + + + + Document + + + +
+

Exercise 3

+

30/6/2026

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
First NameJohn
Last NameDoe
Favourite FilmOppenheimer
ImageOppenheimer Poster
Audio Sample
Video Sample
+
+
+
+

Full Name:

+
+

Email:

+
+

Password:

+
+

Available Days:

+ + + + + + + + + +
+

Working on a new Website?

+ + + +
+

Comments:


+
+ + +
+
+ + \ No newline at end of file diff --git a/Exercise 3/style.css b/Exercise 3/style.css new file mode 100644 index 00000000..70637b46 --- /dev/null +++ b/Exercise 3/style.css @@ -0,0 +1,106 @@ +body{ + background-image: url("Assets/Background-desktop.jpg"); + align-items: center; + margin: auto; +} +.header{ + background-color: rgba(19, 204, 192, 0.8); + padding: 20px; + border-radius: 10px; + border: 1px solid #ccc; +} +.header h1{ + text-align: center; +} +.header h2{ + text-align: center; +} + +.about{ + background-color: rgba(229, 154, 231, 0.8); + padding: 20px; + border-radius: 10px; + border: 1px solid #ccc; +} + +.about table{ + border-collapse: collapse; + width: 100%; + border: 1px solid #ccc; +} +.about table th, +.about table td { + border: 1px solid #ccc; + padding: 10px; + text-align: left; + color:#320aa0 +} +.form{ + background-color: rgba(227, 235, 230, 0.2); + padding: 20px; + border-radius: 10px; + border: 1px solid #ccc; + margin:auto; +} +.form *{ + color: #fff; +} +.form input[type="submit"]{ + background-color: rgba(71, 223, 134, 0.8); + padding: 10px; + border-radius: 5px; + border: 1px solid #ccc; +} +.form input[type="submit"]:hover{ + background-color: rgba(71, 223, 134, 1); + cursor: pointer; +} +.form input[type="reset"]{ + background-color: rgba(223, 71, 134, 0.8); + padding: 10px; + border-radius: 5px; + border: 1px solid #ccc; +} +@media screen and (max-width: 600px) { + body{ + background-image: url("Assets/Background-mobile.jpg"); + } + .header{ + background-color: rgba(124, 204, 19, 0.8); + padding: 20px; + border-radius: 10px; + border: 1px solid #ccc; + } + .about table{ + background-color: rgba(124, 204, 19, 0.8); + padding: 20px; + width: 100%; + margin: auto; + position: relative; + } + .form{ + padding: 20px; + border-radius: 10px; + border: 1px solid #ccc; + margin:auto; + } + .form *{ + color: #062197; + } + .form input[type="submit"]{ + background-color: rgba(71, 223, 134, 0.8); + padding: 10px; + border-radius: 5px; + border: 1px solid #ccc; + } + .form input[type="submit"]:hover{ + background-color: rgba(71, 223, 134, 1); + cursor: pointer; + } + .form input[type="reset"]{ + background-color: rgba(223, 71, 134, 0.8); + padding: 10px; + border-radius: 5px; + border: 1px solid #ccc; + } +} \ No newline at end of file diff --git a/Exercise 4/Assets/background.jpg b/Exercise 4/Assets/background.jpg new file mode 100644 index 00000000..22ffcf85 Binary files /dev/null and b/Exercise 4/Assets/background.jpg differ diff --git a/Exercise 4/index.html b/Exercise 4/index.html new file mode 100644 index 00000000..496b8cb5 --- /dev/null +++ b/Exercise 4/index.html @@ -0,0 +1,99 @@ + + + + + + + Exercise 4 + + + + + +
+

Welcome to My Portfolio

+

This is a simple portfolio page created using Bootstrap.

+
+ +
+
+
+

About Me

+ +

I am a passionate computer scientist with a deep interest in software development, artificial intelligence, and web technologies. My journey in computer science began in my early teens when I wrote my first program in Python, and since then, I have been driven by the desire to solve complex problems through innovative coding solutions. Throughout my academic career, I have developed strong foundational knowledge in data structures, algorithms, and software engineering principles. I have worked on various projects ranging from simple console applications to sophisticated full-stack web applications using modern frameworks like React and Node.js. My expertise spans multiple programming languages including Python, JavaScript, Java, and C++, allowing me to adapt to different project requirements seamlessly. I am particularly interested in machine learning and have completed several projects involving neural networks and natural language processing. Beyond technical skills, I believe in the importance of clean code, proper documentation, and collaborative development practices. I actively participate in open-source projects and contribute to the developer community through sharing knowledge and best practices. My goal is to continue growing as a technologist while helping organizations build scalable and efficient software solutions that make a positive impact on society.

+
+
+ Oppenheimer Poster + + +
+
+ + +
+
+

Expertise languages

+
+
+
+ python logo +
+
Python
+

Python is a versatile language ideal for web development, data science, and automation, praised for its clean syntax and powerful standard library.

+
+
+
+
+
+ C logo +
+
C
+

C is a foundational systems language known for efficiency and control, commonly used for embedded systems, operating systems, and performance-critical applications.

+
+
+
+
+
+ + + + diff --git a/Exercise 5/index.html b/Exercise 5/index.html new file mode 100644 index 00000000..44b3230d --- /dev/null +++ b/Exercise 5/index.html @@ -0,0 +1,34 @@ + + + + + + Exercise 5 + + + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+ + + \ No newline at end of file diff --git a/Exercise 5/script.js b/Exercise 5/script.js new file mode 100644 index 00000000..03209477 --- /dev/null +++ b/Exercise 5/script.js @@ -0,0 +1,40 @@ +const firstName = document.getElementById('first_name'); +const lastName = document.getElementById('last_name'); +const age = document.getElementById('age'); +const phone = document.getElementById('phone'); + +const btn = document.getElementById('btn'); + +btn.addEventListener('click', function(event) { + const firstNameValue = firstName.value.trim(); + const lastNameValue = lastName.value.trim(); + const ageValue = Number(age.value.trim()); + const phoneValue = phone.value.trim(); + const isNumericName = /^\d+$/.test(firstNameValue) || /^\d+$/.test(lastNameValue); + + if (firstNameValue === '') { + alert('Please enter your first name.'); + event.preventDefault(); + } else if (lastNameValue === '') { + alert('Please enter your last name.'); + event.preventDefault(); + } else if (age.value.trim() === '') { + alert('Please enter your age.'); + event.preventDefault(); + } else if (phoneValue === '') { + alert('Please enter your phone number.'); + event.preventDefault(); + } else if (isNumericName) { + alert('First name and last name must not be numbers.'); + event.preventDefault(); + } else if (Number.isNaN(ageValue)) { + alert('Age should be a number'); + event.preventDefault(); + } else if (ageValue < 18) { + alert('Sorry not old enough for our program'); + event.preventDefault(); + } else { + alert('Welcome to our ADOS app'); + event.preventDefault(); + } +}); \ No newline at end of file diff --git a/Exercise 6/crud.html b/Exercise 6/crud.html new file mode 100644 index 00000000..d9efd29d --- /dev/null +++ b/Exercise 6/crud.html @@ -0,0 +1,59 @@ + + + + + + Document + + + + + +
+

CRUD app

+
+
+
+
+ + + + + +
+
+
+ + + diff --git a/Exercise 6/index.html b/Exercise 6/index.html new file mode 100644 index 00000000..f6b28ccf --- /dev/null +++ b/Exercise 6/index.html @@ -0,0 +1,48 @@ + + + + + + Document + + + + + +
+

Welcome to My Web Application

+

Click on any app you want to try on navbar to continue

+
+ + + diff --git a/Exercise 6/scripts/crud.js b/Exercise 6/scripts/crud.js new file mode 100644 index 00000000..7ee7365f --- /dev/null +++ b/Exercise 6/scripts/crud.js @@ -0,0 +1,162 @@ +// CRUD app + +counter = 0; +// Insertion of data +btn = document.getElementById("Insert"); +const alertPlaceholder = document.getElementById('alert') +const appendAlert = (message, type) => { + alertPlaceholder.innerHTML = ''; // Clear previous alerts + const wrapper = document.createElement('div'); + wrapper.innerHTML = [ + `' + ].join(''); + + alertPlaceholder.append(wrapper); + } + +const dataPlaceholder = document.getElementById('data-center') +const appendData = (firstName, lastName, age, phone) => { + const wrapper = document.createElement('div'); + wrapper.innerHTML = [ + `
`, + ` `, + `
`, + ` `, + ` `, + `
`, + `
` + ].join(''); + + dataPlaceholder.append(wrapper); +} + + +btn.addEventListener("click", function(event) { + + + First_Name = document.getElementById("First-Name").value; + Last_Name = document.getElementById("Last-Name").value; + Age = document.getElementById("Age").value; + Phone = document.getElementById("Phone").value; + + // Check if we're in edit mode - if so, skip insertion + const editButtons = document.querySelectorAll("[id^=edit-][data-is-updating='true']"); + if (editButtons.length > 0) { + return; + } + + if (First_Name === "") { + appendAlert('Full Name is required.', 'danger'); + event.preventDefault(); + } + else if (Last_Name === "") { + appendAlert ('Last Name is required.', 'danger'); + event.preventDefault(); + } + else if (Age === "") { + appendAlert('Age is required.', 'danger'); + event.preventDefault(); + } + else if (Phone === "") { + appendAlert('Phone is required.', 'danger'); + event.preventDefault(); + } + else if (Phone === "") { + appendAlert('Phone is required.', 'danger'); + event.preventDefault(); + } + else { + appendAlert('Inserted successfully!', 'success'); + appendData(First_Name, Last_Name, Age, Phone); + counter++; + document.querySelector("#First-Name").value = ""; + document.querySelector("#Last-Name").value = ""; + document.querySelector("#Age").value = ""; + document.querySelector("#Phone").value = ""; + event.preventDefault(); + } + + +}); + +// Edit button +dataPlaceholder.addEventListener("click", function(event) { + if (event.target.id.startsWith("edit-")) { + event.preventDefault(); + id = event.target.id.split("-")[1]; + const firstName = document.getElementById(`firstName-${id}`).innerText.split(": ")[1]; + const lastName = document.getElementById(`lastName-${id}`).innerText.split(": ")[1]; + const age = document.getElementById(`age-${id}`).innerText.split(": ")[1]; + const phone = document.getElementById(`phone-${id}`).innerText.split(": ")[1]; + + const firstnameplaceholder = document.querySelector("#First-Name"); + const lastnameplaceholder = document.querySelector("#Last-Name"); + const ageplaceholder = document.querySelector("#Age"); + const phoneplaceholder = document.querySelector("#Phone"); + + firstnameplaceholder.value = firstName; + lastnameplaceholder.value = lastName; + ageplaceholder.value = age; + phoneplaceholder.value = phone; + + event.target.textContent = "Update"; + event.target.dataset.isUpdating = "true"; + document.getElementById("Insert").textContent = "Update Record"; + } +}); + +// Update +const insertBtn = document.getElementById("Insert"); +insertBtn.addEventListener("click", function(event) { + const editButtons = document.querySelectorAll("[id^=edit-][data-is-updating='true']"); + if (editButtons.length > 0) { + const editBtn = editButtons[0]; + const id = editBtn.id.split("-")[1]; + + const updatedFirstName = document.querySelector("#First-Name").value; + const updatedLastName = document.querySelector("#Last-Name").value; + const updatedAge = document.querySelector("#Age").value; + const updatedPhone = document.querySelector("#Phone").value; + + document.getElementById(`firstName-${id}`).innerText = `First Name: ${updatedFirstName}`; + document.getElementById(`lastName-${id}`).innerText = `Last Name: ${updatedLastName}`; + document.getElementById(`age-${id}`).innerText = `Age: ${updatedAge}`; + document.getElementById(`phone-${id}`).innerText = `Phone: ${updatedPhone}`; + + appendAlert('Updated successfully!', 'success'); + editBtn.textContent = "Edit"; + editBtn.dataset.isUpdating = "false"; + document.getElementById("Insert").textContent = "Insert"; + + // Clear form after update + document.querySelector("#First-Name").value = ""; + document.querySelector("#Last-Name").value = ""; + document.querySelector("#Age").value = ""; + document.querySelector("#Phone").value = ""; + + event.preventDefault(); + return; + } +}); + +// Delete +dataPlaceholder.addEventListener("click", function(event) { + if (event.target.id.startsWith("delete-")) { + event.preventDefault(); + id = event.target.id.split("-")[1]; + const card = document.getElementById(`firstName-${id}`).closest(".card"); + card.remove(); + appendAlert('Deleted successfully!', 'success'); + } +}); + + + diff --git a/Exercise 6/scripts/search.js b/Exercise 6/scripts/search.js new file mode 100644 index 00000000..da00d0d7 --- /dev/null +++ b/Exercise 6/scripts/search.js @@ -0,0 +1,67 @@ +const appendAlert = (message, type) => { + const alertPlaceholder = document.getElementById('alert'); + alertPlaceholder.innerHTML = '' // Clear previous alerts + const wrapper = document.createElement('div'); + wrapper.innerHTML = [ + `' + ].join(''); + alertPlaceholder.append(wrapper); +} + +const AppendResults = (picture, title, cost) => { + const resultsPlaceholder = document.getElementById('results'); + const wrapper = document.createElement('div'); + wrapper.innerHTML = [ + `
`, + `
`, + ` ${title}`, + `
`, + `
${title}
`, + `

$${cost}

`, + `
`, + `
`, + `
` + ].join(''); + resultsPlaceholder.append(wrapper); +} +const btn = document.getElementById("Search"); +btn.addEventListener("click", async function(event) { + event.preventDefault(); + const Name = document.getElementById("Name").value; + + + + if (Name === "") { + appendAlert('Game Name is required.', 'danger'); + event.preventDefault(); + } + else{ + try { + const encodedName = encodeURIComponent(Name); + const response = await fetch(`https://www.cheapshark.com/api/1.0/games?title=${encodedName}`); + const data = await response.json(); + + console.log("API Response:", data); + + document.getElementById("results").innerHTML = ""; + if (data.length === 0) { + appendAlert('Game not found.', 'danger'); + } + else { + for (const game of data.slice(0, 5)) { // Limit to first 5 results + console.log("Game Data:", game); + AppendResults(game.thumb, game.external, game.cheapest); + } + appendAlert('Game found successfully.', 'success') + // Clear input after successful search + document.getElementById("Name").value = ""; + } + } catch (error) { + console.error("Error:", error); + appendAlert('Error searching game.', 'danger'); + } + } +}); diff --git a/Exercise 6/scripts/validator.js b/Exercise 6/scripts/validator.js new file mode 100644 index 00000000..4617babc --- /dev/null +++ b/Exercise 6/scripts/validator.js @@ -0,0 +1,46 @@ +//validator app +btn = document.getElementById("Confirm-Identity"); +const alertPlaceholder = document.getElementById('alert'); +const appendAlert = (message, type) => { + alertPlaceholder.innerHTML = ''; // Clear previous alerts + const wrapper = document.createElement('div'); + wrapper.innerHTML = [ + `' + ].join(''); + + alertPlaceholder.append(wrapper); + } +btn.addEventListener("click", function(event) { + + + + First_Name = document.getElementById("First-Name").value; + Last_Name = document.getElementById("Last-Name").value; + Age = document.getElementById("Age").value; + Phone = document.getElementById("Phone").value; + + if (First_Name === "") { + appendAlert('Full Name is required.', 'danger'); + event.preventDefault(); + } + else if (Last_Name === "") { + appendAlert('Last Name is required.', 'danger'); + event.preventDefault(); + } + else if (Age === "") { + appendAlert('Age is required.', 'danger'); + event.preventDefault(); + } + else if (Phone === "") { + appendAlert('Phone is required.', 'danger'); + event.preventDefault(); + } + else { + appendAlert('Validated successfully!', 'success'); + event.preventDefault(); + } +}); + diff --git a/Exercise 6/search.html b/Exercise 6/search.html new file mode 100644 index 00000000..c1abc44c --- /dev/null +++ b/Exercise 6/search.html @@ -0,0 +1,60 @@ + + + + + + Document + + + + + +
+

Game Search App

+ +
+
+
+
+ + +
+
+
+ + + + + + diff --git a/Exercise 6/validator.html b/Exercise 6/validator.html new file mode 100644 index 00000000..037cdd29 --- /dev/null +++ b/Exercise 6/validator.html @@ -0,0 +1,59 @@ + + + + + + Document + + + + + +
+

Validator app

+ +
+
+
+
+ + + + + +
+
+ + + diff --git a/Exercise 7/.gitignore b/Exercise 7/.gitignore new file mode 100644 index 00000000..a547bf36 --- /dev/null +++ b/Exercise 7/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/Exercise 7/README.md b/Exercise 7/README.md new file mode 100644 index 00000000..7fd2b13c --- /dev/null +++ b/Exercise 7/README.md @@ -0,0 +1,73 @@ +# React_Lesson_Exercise +Welcome to the React 18 exercise. Upon completion of this exercise, you'll have permission to join the 'New Website' team, where you can contribute to a [real-world React application](https://github.com/buildingu/bu-front) for building-U. + +## Prerequisites +- Completed both JavaScript lessons. +- Node.js and NPM installed. +- Git installed + +## Objective +Demonstrate your understanding of various React hooks through a series of challenges. Each challenge will focus on a specific hook, and the final challenge will incorporate multiple hooks. Use this exercise to explore how React hooks can be used together to build dynamic forms and UI elements. + +ALSO DO NOT INSTALL OTHER PACKAGES, that challenge will automatically be wrong. + +## Instructions +### Step 1: Download the Project +1. Download the project as a zip file from the [repository](https://github.com/buildingu/React_Lesson_Exercise), **Do not clone** the repository since you're not contributing to it, and extract it to your bu-learning repository with the name `Exercise 7` or any other name you think makes sense. You should already have the bu-learning repository cloned, if not, clone it [here](https://github.com/buildingu/bu-learning.git). +2. Open the exercise directory in your preferred code editor or IDE. + +### Step 2: Set Up the React App +At the same level where the package.json is located install the dependencies in a terminal: +``` +$ npm install +``` + +### Step 3: The Challenges +Each challenge focuses on demonstrating the concept of each hook except the final challenge where you can use however many hooks you want. You will find the challenges in the src/components directory. +- Each file is named according to the hook it demonstrates. +- Read the comments inside each challenge file for what you have to complete. + +Here are the challenges you'll be working on: +1. **Hook Challenges:** + - `1.UseStateChallenge.jsx`: Demonstrate the use of `useState`. + - `2.UseRefChallenge.jsx`: Demonstrate the use of `useRef`. + - `3.UseEffectChallenge.jsx`: Demonstrate the use of `useEffect`. + - `4.useContextChallenge`: A directory to mimic the idea of the context being used somewhere else in the project; containing AuthContext.jsx and UseContext.jsx for demonstrating useContext. + - `5.UseReducerChallenge.jsx`: Demonstrate the use of `useReducer` + - `6.UseMemoChallenge.jsx` (Optional): Show how `useMemo` can optimize performance. +2. **Final Challenge:** + - The `7.FinalChallenge.jsx` will be a form that incorporates multiple hooks to manage form data, validation, and real-time feedback. + +### Step 5: Running the Challenges +The project is set up so you can run each challenge separately using npm scripts. Use the following commands in the terminal to start each challenge (e.g., npm run dev:useState): + +``` +$ npm run dev: +``` + +**Available Scripts:** +- `dev:useState` +- `dev:useRef` +- `dev:useEffect` +- `dev:useContext` +- `dev:useReducer` +- `dev:useMemo` (Optional) +- `dev:final` (Final Challenge) + +## Bonus! +Instead of using npm scripts like I mentioned to navigate between challenges, you can implement client-side routing using [`react-router-dom`](https://reactrouter.com) to create a page for each challenge. This will require modifying `App.jsx` to include route paths for each challenge and use the component as a page. + +If you decide to implement routing, you can delete the individual challenge scripts from the `package.json` and only use the `"dev"` script to run the app. + +## Your Submission +1. Open a terminal in your code editor (e.g., VSCode) or use Git Bash/any other terminal of your choice if not open already. +2. Ensure you are on your branch, it should be named as the first letter of your first name, followed by an underscore, and your last name (e.g., j_doe). If you somehow didn't create your branch yet use `git checkout -b your_branch_name` to create it. +3. Make the necessary changes to the files required in the exercise and stage your changes using `git add ` to add specific files, or use `git add .` to stage all modified files. +4. Commit your files with a message (see commit message convention: [Conventional Commit Message](https://gist.github.com/qoomon/5dfcdf8eec66a051ecd85625518cfd13)) using: +``` +$ git commit -m "feat: Insert message here" +``` +5. Push the changes on your branch to the remote repository using: +``` +$ git push origin your-branch-name +``` diff --git a/Exercise 7/index.html b/Exercise 7/index.html new file mode 100644 index 00000000..57f2b7ac --- /dev/null +++ b/Exercise 7/index.html @@ -0,0 +1,13 @@ + + + + + + + React 18 Exercise + + +
+ + + diff --git a/Exercise 7/package-lock.json b/Exercise 7/package-lock.json new file mode 100644 index 00000000..456e529b --- /dev/null +++ b/Exercise 7/package-lock.json @@ -0,0 +1,1772 @@ +{ + "name": "react-lesson", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "react-lesson", + "version": "1.0.0", + "dependencies": { + "react": "^18", + "react-dom": "^18", + "uuid": "^10" + }, + "devDependencies": { + "@types/react": "^18", + "@types/react-dom": "^18", + "@vitejs/plugin-react": "~4.3.0", + "cross-env": "^7.0.3", + "vite": "~6.2.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.26.8", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz", + "integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.9.tgz", + "integrity": "sha512-lWBYIrF7qK5+GjY5Uy+/hEgp8OJWOD/rpy74GplYRhEauvbHDeFB8t5hPOZxCZ0Oxf4Cc36tK51/l3ymJysrKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.9", + "@babel/helper-compilation-targets": "^7.26.5", + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helpers": "^7.26.9", + "@babel/parser": "^7.26.9", + "@babel/template": "^7.26.9", + "@babel/traverse": "^7.26.9", + "@babel/types": "^7.26.9", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.9.tgz", + "integrity": "sha512-kEWdzjOAUMW4hAyrzJ0ZaTOu9OmpyDIQicIh0zg0EEcEkYXZb2TjtBhnHi2ViX7PKwZqF4xwqfAm299/QMP3lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.26.9", + "@babel/types": "^7.26.9", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz", + "integrity": "sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.26.5", + "@babel/helper-validator-option": "^7.25.9", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", + "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", + "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.9.tgz", + "integrity": "sha512-Mz/4+y8udxBKdmzt/UjPACs4G3j5SshJJEFFKxlCGPydG4JAHXxjWjAwjd09tf6oINvl1VfMJo+nB7H2YKQ0dA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.26.9", + "@babel/types": "^7.26.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.9.tgz", + "integrity": "sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.26.9" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.25.9.tgz", + "integrity": "sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.25.9.tgz", + "integrity": "sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz", + "integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "@babel/parser": "^7.26.9", + "@babel/types": "^7.26.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.9.tgz", + "integrity": "sha512-ZYW7L+pL8ahU5fXmNbPF+iZFHCv5scFak7MZ9bwaRPLUhHh7QQEMjZUg0HevihoqCM5iSYHN61EyCoZvqC+bxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.9", + "@babel/parser": "^7.26.9", + "@babel/template": "^7.26.9", + "@babel/types": "^7.26.9", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.26.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.9.tgz", + "integrity": "sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz", + "integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.0.tgz", + "integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz", + "integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.0.tgz", + "integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz", + "integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz", + "integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz", + "integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz", + "integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz", + "integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz", + "integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz", + "integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz", + "integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz", + "integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz", + "integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz", + "integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz", + "integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz", + "integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz", + "integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz", + "integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz", + "integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz", + "integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz", + "integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz", + "integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz", + "integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz", + "integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.9.tgz", + "integrity": "sha512-qZdlImWXur0CFakn2BJ2znJOdqYZKiedEPEVNTBrpfPjc/YuTGcaYZcdmNFTkUj3DU0ZM/AElcM8Ybww3xVLzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.9.tgz", + "integrity": "sha512-4KW7P53h6HtJf5Y608T1ISKvNIYLWRKMvfnG0c44M6In4DQVU58HZFEVhWINDZKp7FZps98G3gxwC1sb0wXUUg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.9.tgz", + "integrity": "sha512-0CY3/K54slrzLDjOA7TOjN1NuLKERBgk9nY5V34mhmuu673YNb+7ghaDUs6N0ujXR7fz5XaS5Aa6d2TNxZd0OQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.9.tgz", + "integrity": "sha512-eOojSEAi/acnsJVYRxnMkPFqcxSMFfrw7r2iD9Q32SGkb/Q9FpUY1UlAu1DH9T7j++gZ0lHjnm4OyH2vCI7l7Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.9.tgz", + "integrity": "sha512-2lzjQPJbN5UnHm7bHIUKFMulGTQwdvOkouJDpPysJS+QFBGDJqcfh+CxxtG23Ik/9tEvnebQiylYoazFMAgrYw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.9.tgz", + "integrity": "sha512-SLl0hi2Ah2H7xQYd6Qaiu01kFPzQ+hqvdYSoOtHYg/zCIFs6t8sV95kaoqjzjFwuYQLtOI0RZre/Ke0nPaQV+g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.9.tgz", + "integrity": "sha512-88I+D3TeKItrw+Y/2ud4Tw0+3CxQ2kLgu3QvrogZ0OfkmX/DEppehus7L3TS2Q4lpB+hYyxhkQiYPJ6Mf5/dPg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.9.tgz", + "integrity": "sha512-3qyfWljSFHi9zH0KgtEPG4cBXHDFhwD8kwg6xLfHQ0IWuH9crp005GfoUUh/6w9/FWGBwEHg3lxK1iHRN1MFlA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.9.tgz", + "integrity": "sha512-6TZjPHjKZUQKmVKMUowF3ewHxctrRR09eYyvT5eFv8w/fXarEra83A2mHTVJLA5xU91aCNOUnM+DWFMSbQ0Nxw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.9.tgz", + "integrity": "sha512-LD2fytxZJZ6xzOKnMbIpgzFOuIKlxVOpiMAXawsAZ2mHBPEYOnLRK5TTEsID6z4eM23DuO88X0Tq1mErHMVq0A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.9.tgz", + "integrity": "sha512-dRAgTfDsn0TE0HI6cmo13hemKpVHOEyeciGtvlBTkpx/F65kTvShtY/EVyZEIfxFkV5JJTuQ9tP5HGBS0hfxIg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.9.tgz", + "integrity": "sha512-PHcNOAEhkoMSQtMf+rJofwisZqaU8iQ8EaSps58f5HYll9EAY5BSErCZ8qBDMVbq88h4UxaNPlbrKqfWP8RfJA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.9.tgz", + "integrity": "sha512-Z2i0Uy5G96KBYKjeQFKbbsB54xFOL5/y1P5wNBsbXB8yE+At3oh0DVMjQVzCJRJSfReiB2tX8T6HUFZ2k8iaKg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.9.tgz", + "integrity": "sha512-U+5SwTMoeYXoDzJX5dhDTxRltSrIax8KWwfaaYcynuJw8mT33W7oOgz0a+AaXtGuvhzTr2tVKh5UO8GVANTxyQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.9.tgz", + "integrity": "sha512-FwBHNSOjUTQLP4MG7y6rR6qbGw4MFeQnIBrMe161QGaQoBQLqSUEKlHIiVgF3g/mb3lxlxzJOpIBhaP+C+KP2A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.9.tgz", + "integrity": "sha512-cYRpV4650z2I3/s6+5/LONkjIz8MBeqrk+vPXV10ORBnshpn8S32bPqQ2Utv39jCiDcO2eJTuSlPXpnvmaIgRA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.9.tgz", + "integrity": "sha512-z4mQK9dAN6byRA/vsSgQiPeuO63wdiDxZ9yg9iyX2QTzKuQM7T4xlBoeUP/J8uiFkqxkcWndWi+W7bXdPbt27Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.9.tgz", + "integrity": "sha512-KB48mPtaoHy1AwDNkAJfHXvHp24H0ryZog28spEs0V48l3H1fr4i37tiyHsgKZJnCmvxsbATdZGBpbmxTE3a9w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.9.tgz", + "integrity": "sha512-AyleYRPU7+rgkMWbEh71fQlrzRfeP6SyMnRf9XX4fCdDPAJumdSBqYEcWPMzVQ4ScAl7E4oFfK0GUVn77xSwbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.14", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", + "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.18", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.18.tgz", + "integrity": "sha512-t4yC+vtgnkYjNSKlFx1jkAhH8LgTo2N/7Qvi83kdEaUtMDiwpbLAktKDaAMlRcJ5eSxZkH74eEGt1ky31d7kfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.5", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.5.tgz", + "integrity": "sha512-P4t6saawp+b/dFrUr2cvkVsfvPguwsxtH6dNIYRllMsefqFzkZk5UIjzyDOv5g1dXIPdG4Sp1yCR4Z6RCUsG/Q==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.4.tgz", + "integrity": "sha512-SCCPBJtYLdE8PX/7ZQAs1QAZ8Jqwih+0VBLum1EGqmCCQal+MIUqLCzj3ZUy8ufbC0cAM4LRlSTm7IQJwWT4ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.26.0", + "@babel/plugin-transform-react-jsx-self": "^7.25.9", + "@babel/plugin-transform-react-jsx-source": "^7.25.9", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.14.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0" + } + }, + "node_modules/browserslist": { + "version": "4.24.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", + "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001688", + "electron-to-chromium": "^1.5.73", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.1" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001702", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001702.tgz", + "integrity": "sha512-LoPe/D7zioC0REI5W73PeR1e1MLCipRGq/VkovJnd6Df+QVqT+vT33OXCp8QUd7kA7RZrHWxb1B36OQKI/0gOA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.112", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.112.tgz", + "integrity": "sha512-oen93kVyqSb3l+ziUgzIOlWt/oOuy4zRmpwestMn4rhFWAoFJeFuCVte9F2fASjeZZo7l/Cif9TiyrdW4CwEMA==", + "dev": true, + "license": "ISC" + }, + "node_modules/esbuild": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz", + "integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.0", + "@esbuild/android-arm": "0.25.0", + "@esbuild/android-arm64": "0.25.0", + "@esbuild/android-x64": "0.25.0", + "@esbuild/darwin-arm64": "0.25.0", + "@esbuild/darwin-x64": "0.25.0", + "@esbuild/freebsd-arm64": "0.25.0", + "@esbuild/freebsd-x64": "0.25.0", + "@esbuild/linux-arm": "0.25.0", + "@esbuild/linux-arm64": "0.25.0", + "@esbuild/linux-ia32": "0.25.0", + "@esbuild/linux-loong64": "0.25.0", + "@esbuild/linux-mips64el": "0.25.0", + "@esbuild/linux-ppc64": "0.25.0", + "@esbuild/linux-riscv64": "0.25.0", + "@esbuild/linux-s390x": "0.25.0", + "@esbuild/linux-x64": "0.25.0", + "@esbuild/netbsd-arm64": "0.25.0", + "@esbuild/netbsd-x64": "0.25.0", + "@esbuild/openbsd-arm64": "0.25.0", + "@esbuild/openbsd-x64": "0.25.0", + "@esbuild/sunos-x64": "0.25.0", + "@esbuild/win32-arm64": "0.25.0", + "@esbuild/win32-ia32": "0.25.0", + "@esbuild/win32-x64": "0.25.0" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/postcss": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", + "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.8", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-refresh": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", + "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.34.9", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.9.tgz", + "integrity": "sha512-nF5XYqWWp9hx/LrpC8sZvvvmq0TeTjQgaZHYmAgwysT9nh8sWnZhBnM8ZyVbbJFIQBLwHDNoMqsBZBbUo4U8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.6" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.34.9", + "@rollup/rollup-android-arm64": "4.34.9", + "@rollup/rollup-darwin-arm64": "4.34.9", + "@rollup/rollup-darwin-x64": "4.34.9", + "@rollup/rollup-freebsd-arm64": "4.34.9", + "@rollup/rollup-freebsd-x64": "4.34.9", + "@rollup/rollup-linux-arm-gnueabihf": "4.34.9", + "@rollup/rollup-linux-arm-musleabihf": "4.34.9", + "@rollup/rollup-linux-arm64-gnu": "4.34.9", + "@rollup/rollup-linux-arm64-musl": "4.34.9", + "@rollup/rollup-linux-loongarch64-gnu": "4.34.9", + "@rollup/rollup-linux-powerpc64le-gnu": "4.34.9", + "@rollup/rollup-linux-riscv64-gnu": "4.34.9", + "@rollup/rollup-linux-s390x-gnu": "4.34.9", + "@rollup/rollup-linux-x64-gnu": "4.34.9", + "@rollup/rollup-linux-x64-musl": "4.34.9", + "@rollup/rollup-win32-arm64-msvc": "4.34.9", + "@rollup/rollup-win32-ia32-msvc": "4.34.9", + "@rollup/rollup-win32-x64-msvc": "4.34.9", + "fsevents": "~2.3.2" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/vite": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.0.tgz", + "integrity": "sha512-7dPxoo+WsT/64rDcwoOjk76XHj+TqNTIvHKcuMQ1k4/SeHDaQt5GFAeLYzrimZrMpn/O6DtdI03WUjdxuPM0oQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "postcss": "^8.5.3", + "rollup": "^4.30.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + } + } +} diff --git a/Exercise 7/package.json b/Exercise 7/package.json new file mode 100644 index 00000000..cd4f1514 --- /dev/null +++ b/Exercise 7/package.json @@ -0,0 +1,28 @@ +{ + "name": "react-lesson", + "private": true, + "version": "1.0.0", + "type": "module", + "scripts": { + "dev:useState": "cross-env VITE_REACT_CHALLENGE=useState vite", + "dev:useRef": "cross-env VITE_REACT_CHALLENGE=useRef vite", + "dev:useEffect": "cross-env VITE_REACT_CHALLENGE=useEffect vite", + "dev:useContext": "cross-env VITE_REACT_CHALLENGE=useContext vite", + "dev:useReducer": "cross-env VITE_REACT_CHALLENGE=useReducer vite", + "dev:useMemo": "cross-env VITE_REACT_CHALLENGE=useMemo vite", + "dev:final": "cross-env VITE_REACT_CHALLENGE=final vite", + "dev": "vite" + }, + "dependencies": { + "react": "^18", + "react-dom": "^18", + "uuid": "^10" + }, + "devDependencies": { + "@types/react": "^18", + "@types/react-dom": "^18", + "@vitejs/plugin-react": "~4.3.0", + "cross-env": "^7.0.3", + "vite": "~6.2.0" + } +} diff --git a/Exercise 7/src/App.jsx b/Exercise 7/src/App.jsx new file mode 100644 index 00000000..93785de7 --- /dev/null +++ b/Exercise 7/src/App.jsx @@ -0,0 +1,37 @@ +import UseStateChallenge from "./components/1.UseStateChallenge"; +import UseRefChallenge from "./components/2.UseRefChallenge"; +import UseEffectChallenge from "./components/3.UseEffectChallenge"; +import UseContextChallenge from "./components/4.UseContextChallenge/UseContext"; +import { AuthContextProvider } from "./components/4.UseContextChallenge/AuthContext"; +import UseReducerChallenge from "./components/5.UseReducerChallenge"; +import UseMemoChallenge from "./components/6.UseMemoChallenge"; +import FinalChallenge from "./components/7.FinalChallenge"; + +function App() { + const hookName = import.meta.env.VITE_REACT_CHALLENGE; + + switch (hookName) { + case "useState": + return ; + case "useRef": + return ; + case "useEffect": + return ; + case "useContext": + return ( + + + + ); + case "useReducer": + return ; + case "useMemo": + return ; + case "final": + return ; + default: + return

ERROR: Please specify a valid hook challenge (e.g., npm run dev:useState).

; + } +} + +export default App; diff --git a/Exercise 7/src/components/1.UseStateChallenge.jsx b/Exercise 7/src/components/1.UseStateChallenge.jsx new file mode 100644 index 00000000..2e36f7f3 --- /dev/null +++ b/Exercise 7/src/components/1.UseStateChallenge.jsx @@ -0,0 +1,26 @@ +/** + * Challenge 1: useState + * + * Description: + * Create a toggle button to show and hide the div containing the text `BOO!`. + */ + +import { useState } from "react"; +const ShowBOO = () => { + const [show, setShow] = useState(false); + + return ( +
+ + {show &&
BOO!
} +
+ ); +} +export default function UseStateChallenge() { + return ( +
+

useState Challenge

+ +
+ ); +} diff --git a/Exercise 7/src/components/2.UseRefChallenge.jsx b/Exercise 7/src/components/2.UseRefChallenge.jsx new file mode 100644 index 00000000..120e1c7c --- /dev/null +++ b/Exercise 7/src/components/2.UseRefChallenge.jsx @@ -0,0 +1,28 @@ +/** + * Challenge 2: useRef + * + * Description: + * Create an input field with a button labeled "Focus". When the button is clicked, use useRef to focus on the input field. + */ + +import { useRef } from "react"; + + +export default function UseRefChallenge() { + + const inputRef = useRef(null); + const handleFocus = () => { + if (inputRef.current) { + inputRef.current.focus(); + } + }; + + + return ( +
+

useRef Challenge

+ + +
+ ); +} diff --git a/Exercise 7/src/components/3.UseEffectChallenge.jsx b/Exercise 7/src/components/3.UseEffectChallenge.jsx new file mode 100644 index 00000000..85b8e812 --- /dev/null +++ b/Exercise 7/src/components/3.UseEffectChallenge.jsx @@ -0,0 +1,52 @@ +/** + * Challenge 3: useEffect + * + * Description: + * Fetch and display user data from a public API (e.g. https://jsonplaceholder.typicode.com/users) when the component mounts. + * Display a loading indicator while the data is being fetched by using useState (optional). + * + * - Use the `useEffect` hook to fetch data when the component mounts. + * - Use `useState` to manage the fetched user data and the loading state. + * - Render the data in a list once it's successfully fetched. + */ + +import { useEffect, useState } from "react"; + +export default function UseEffectChallenge() { + + const [users, setUsers] = useState([]); + const [loading, setLoading] = useState(true); + + useEffect(() => { + fetch("https://jsonplaceholder.typicode.com/users") + .then((response) => response.json()) + .then((data) => { + setUsers(data); + setLoading(false); + }) + .catch((error) => { + console.error("Error fetching user data:", error); + setLoading(false); + }); + }, []); + + if (loading) { + return
Loading...
; + } + + + return ( + +
+

useEffect Challenge

+
    + {users.map((user) => ( +
  • + {user.name} - {user.email} +
  • + ))} +
+
+ ); +} + \ No newline at end of file diff --git a/Exercise 7/src/components/4.UseContextChallenge/AuthContext.jsx b/Exercise 7/src/components/4.UseContextChallenge/AuthContext.jsx new file mode 100644 index 00000000..8a4bf8f4 --- /dev/null +++ b/Exercise 7/src/components/4.UseContextChallenge/AuthContext.jsx @@ -0,0 +1,70 @@ +/** + * Challenge 4: createContext + * + * Description: + * You'll create a context to mimic an authentication context in this challenge. `createContext` and `useContext` will be used to manage and + * consume user authentication data just like you'll usually do in a real-world app. + * + * Overview: + * - Create and provide the `AuthContext` to the entire app. + * - Store the mock user in state, and create `login` and `logout` functions to update the state. + * + * Steps: + * 1. Create a mock user with credentials like `firstName`, `lastName`, and `email`, you can add however many you want, have fun!. + * 2. In this file, create the `AuthContext`, `AuthContextProvider` and the functions within the AuthContextProvider to deal with the user. + * - Hold the user object in state using `useState`. + * - Create a login function and initializes the user. + * - Create a logout function that clears the user and displays a message like "User session timed out." (you can use a alert). + * 2. Go to the `App.jsx` file and wrap the `AuthContextProvider` around `UseContextChallenge`. + * 3. Go to the `UseContext.jsx` file, and follow the steps there. + */ + +import React, { createContext, useState } from "react"; + +// Mock user obj. +const users = [ + { + firstName: "John", + lastName: "Doe", + email: "john.doe@example.com", + password: "password123" + }, + { + firstName: "Jane", + lastName: "Smith", + email: "jane.smith@example.com", + password: "password456" + } +]; + +// const AuthContext = +const AuthContext = createContext(); + +export function AuthContextProvider({ children }) { + const [user, setUser] = useState(null); + const login = (email, password) => { + const foundUser = users.find((u) => u.email === email && u.password === password); + if (foundUser) { + setUser(foundUser); + } + }; + const logout = () => { + setUser(null); + alert("User session timed out."); + }; + + return ( + + {children} + + ); +} + +export default AuthContext; + diff --git a/Exercise 7/src/components/4.UseContextChallenge/UseContext.jsx b/Exercise 7/src/components/4.UseContextChallenge/UseContext.jsx new file mode 100644 index 00000000..3202d8f8 --- /dev/null +++ b/Exercise 7/src/components/4.UseContextChallenge/UseContext.jsx @@ -0,0 +1,43 @@ +/** + * Challenge 4: useContext + * + * Description: + * In this component, you'll consume the `AuthContext` and display the user's information. + * + * 1. Use the `useContext` hook to get the context values (`user`, `login`, and `logout`). + * 2. Display a button that toggles between `login` and `logout` states. + * 3. If the user is logged in, display their first name, last name, and email. + */ + +import React, { useContext, useState } from "react"; +import AuthContext from "./AuthContext.jsx"; + +export default function UseContextChallenge() { + + const { user, login, logout } = useContext(AuthContext); + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + return ( +
+

useContext Challenge

+ {user ? ( +
+

Welcome, {user.firstName} {user.lastName}!

+

Email: {user.email}

+ +
+ ) : ( +
+

Please log in.

+ setEmail(e.target.value)}> + setPassword(e.target.value)}> + +
+ )} +
+ ); +} + + \ No newline at end of file diff --git a/Exercise 7/src/components/5.UseReducerChallenge.jsx b/Exercise 7/src/components/5.UseReducerChallenge.jsx new file mode 100644 index 00000000..e5dfc576 --- /dev/null +++ b/Exercise 7/src/components/5.UseReducerChallenge.jsx @@ -0,0 +1,55 @@ +/** + * Challenge 4: useReducer + * + * Description: + * Create a simple to-do list with useReducer for managing the to-do state. You should be able to add and remove to-dos. + */ + +import { useReducer, useRef } from "react"; +import { v4 as uuidV4 } from "uuid"; // Use the uuid for a unique identifier for each todo. + +function todoReducer(state, action) { + if (action.type === "ADD_TODO") { + return [...state, { id: uuidV4(), text: action.payload }]; + } else if (action.type === "REMOVE_TODO") { + return state.filter((todo) => todo.id !== action.payload); + } else { + return state; + } +} + +export default function UseReducerChallenge() { + const inputRef = useRef(); + const [todos, dispatch] = useReducer(todoReducer, []); + + + return ( +
+

useReducer Challenge

+
+

To-do

+ + + +
    + {todos.map((todo) => ( +
  • + {todo.text} + +
  • + ))} +
+
+
+ ); +} diff --git a/Exercise 7/src/components/6.UseMemoChallenge.jsx b/Exercise 7/src/components/6.UseMemoChallenge.jsx new file mode 100644 index 00000000..c3ebb753 --- /dev/null +++ b/Exercise 7/src/components/6.UseMemoChallenge.jsx @@ -0,0 +1,43 @@ +/** + * Challenge 6 (Optional): useMemo + * + * Description: + * Create a component that computes the factorial of a number. Use useMemo on number to memoize the factorial calculation to avoid unnecessary re-calculations. + */ + +import { useState, useMemo } from "react"; + +export default function UseMemoChallenge() { + const [number, setNumber] = useState(0); + const factorial = useMemo(() => { + const computeFactorial = (n) => { + if (n < 0) return "Undefined for negative numbers"; + if (n === 0 || n === 1) return 1; + let result = 1; + for (let i = 2; i <= n; i++) { + result *= i; + } + return result; + } + return computeFactorial(number); + }, [number]); + + + + return ( +
+

useMemo Challenge

+
+ setNumber(Number(e.target.value))} + placeholder="Enter a number" + /> +

+ Factorial of {number} is: {factorial} +

+
+
+ ); +} diff --git a/Exercise 7/src/components/7.FinalChallenge.jsx b/Exercise 7/src/components/7.FinalChallenge.jsx new file mode 100644 index 00000000..23564571 --- /dev/null +++ b/Exercise 7/src/components/7.FinalChallenge.jsx @@ -0,0 +1,151 @@ +/** + * Challenge 7: Final + * + * Description: + * Create a form with fields for first name, last name, age, and phone number. Use state, refs, and any other React hooks of your choice to + * manage form data, validation, and real-time feedback. Incorporate how ever many hooks you want! + * + * Validation: + * Display validation messages under each input if the input is invalid using useState and the error message should clear for the specific + * field if the user types in the field. + * + * - All fields are required. + * - `First name` and `last name` fields should have a max character count of 120. + * - The `age` field must: + * 1. Must be a number + * 2. Have max character count of 2. + * 3. Must be 18 or older. + * - The `phone` field must: + * 1. Must be a number + * 2. Character count equals 10 (e.g., 5048073240). + * + * Lastly, clear the form if validation passes and render a success message. + */ + +import {useState, useRef, useEffect} from "react"; + +export default function FinalChallenge() { + const [formData, setFormData] = useState({ + firstName: "", + lastName: "", + age: "", + phone: "" + }); + + const [errors, setErrors] = useState({}); + const [successMessage, setSuccessMessage] = useState(""); + + const firstNameRef = useRef(); + const lastNameRef = useRef(); + const ageRef = useRef(); + const phoneRef = useRef(); + + useEffect(() => { + + if (successMessage) { + const timer = setTimeout(() => setSuccessMessage(""), 3000); + return () => clearTimeout(timer); + } + }, [successMessage]); + + const handleChange = (e) => { + const { name, value } = e.target; + setFormData((prevData) => ({ ...prevData, [name]: value })); + setErrors((prevErrors) => ({ ...prevErrors, [name]: "" })); + }; + + const validateForm = () => { + const newErrors = {}; + if (!formData.firstName) newErrors.firstName = "First name is required."; + else if (formData.firstName.length > 120) newErrors.firstName = "First name must be less than 120 characters."; + + if (!formData.lastName) newErrors.lastName = "Last name is required."; + else if (formData.lastName.length > 120) newErrors.lastName = "Last name must be less than 120 characters."; + + if (!formData.age) newErrors.age = "Age is required."; + else if (isNaN(formData.age)) newErrors.age = "Age must be a number."; + else if (formData.age.length > 2) newErrors.age = "Age must be less than 3 characters."; + else if (Number(formData.age) < 18) newErrors.age = "You must be 18 or older."; + + if (!formData.phone) newErrors.phone = "Phone number is required."; + else if (isNaN(formData.phone)) newErrors.phone = "Phone number must be a number."; + else if (formData.phone.length !== 10) newErrors.phone = "Phone number must be exactly 10 digits."; + + setErrors(newErrors); + return Object.keys(newErrors).length === 0; + }; + + const handleSubmit = (e) => { + e.preventDefault(); + if (validateForm()) { + setSuccessMessage("Form submitted successfully!"); + setFormData({ + firstName: "", + lastName: "", + age: "", + phone: "" + }); + } + }; + + + + return ( +
+

Final Challenge

+ +
+

Subscribe to our Newsletter!

+
+
+ + {errors.firstName &&

{errors.firstName}

} +
+ +
+ + {errors.lastName &&

{errors.lastName}

} +
+ +
+ + {errors.age &&

{errors.age}

} +
+ +
+ + {errors.phone &&

{errors.phone}

} +
+ + {successMessage &&

{successMessage}

} + + +
+
+
+ ); +} diff --git a/Exercise 7/src/index.css b/Exercise 7/src/index.css new file mode 100644 index 00000000..151514fc --- /dev/null +++ b/Exercise 7/src/index.css @@ -0,0 +1,53 @@ +:root { + font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +#root { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} diff --git a/Exercise 7/src/index.jsx b/Exercise 7/src/index.jsx new file mode 100644 index 00000000..3f2d3d05 --- /dev/null +++ b/Exercise 7/src/index.jsx @@ -0,0 +1,5 @@ +import { createRoot } from "react-dom/client"; +import App from "./App.jsx"; +import "./index.css"; + +createRoot(document.getElementById("root")).render(); diff --git a/Exercise 7/vite.config.js b/Exercise 7/vite.config.js new file mode 100644 index 00000000..a0f4db5a --- /dev/null +++ b/Exercise 7/vite.config.js @@ -0,0 +1,10 @@ +import { defineConfig } from "vite" +import react from "@vitejs/plugin-react" + +// https://vitejs.dev/config/ +export default defineConfig({ + server: { + port: 3000 + }, + plugins: [react()] +})